I have a simple script that counts from 1 to 5000 with a for loop. It flushes output in real time to browser and shows a progress bar with %.
What I have: If I leave the page, the process interrupts. If I come back, it starts from 0.
What I want to achieve: If I leave the page, the process continues and, If I come back , it shows the right percentage.
Example: I run the process, it counts till 54, I leave the page for 10 seconds, when I come back it shows me 140 and continues to flush.
Is it possible?
I would suggest you to use server workers - scripts which are intended to run independently from webserver context.
The most common way of doing it - usage of message queues (RabbitMQ, Qless, etc). Event should be initiated by the script in web context, but the actual task should be executed by queue listener in a different context.
What you have asked seems quite simple to do with a session. (Purely assuming on the use case given). This is not running any process in the background, it just simply keep track of the time and show the progress. That's why I said "based on what you asked". If you want to keep track of any real background tasks, then I believe the case would be totally different, and you will have to change the wordings of your question as well ;)
Something like this would do.
<?php
session_start();
$s = &$_SESSION;
$sleep = 1; //seconds
//check if we have a value set in session before, if not set default = 0.
if(!isset($s['last'])){
$s['last'] = 0;
}
//check if we have a last time set in session before. if not set a default = curret time.
if(!isset($s['time'])){
$s['time'] = time();
}
//get the idle time of the user.
$idle = time() - $s['time'];
//start the loop..and set starting point.
$start = $s['last'] + ($idle / $sleep);
for( $i = $start; $i < 100; $i++){
echo $i . '<br />';
$s['last']++;
$s['time'] = time();
flush();
sleep($sleep);
}
Hope it helps!!
Related
I'm programming my own "smart home" as a learning project.
My code is running fine. I'm looking for help to improve the efficiency and of the code and/or the setup of crontab + php code.
I'm monitoring the energy consumption of my washing machine with a WIFI energy meter. Target is to notify me once the washing machine is completed so I don't forget to clear it.
on my Pi I have a crontab like so:
*/20 7-22 * * * /usr/bin/php '/home/holger/html/plugs/washer.php'
which runs following php code (I simplified for better readability):
[...]/I call the function, of course, but this function does the main task
function loop($maschine, $watt_init, $trashhold){
$max = 75;//max loops to avoid endless runs
$i = 1;//start counter
$tackt = 3;//tact time to check energy consumption
//$trashhold = 4;//ab x Watt kein standby
if ($watt_init < 1 ) {//Machine is switched off if energy consumption < 1 Watt
die;//quit
}
elseif ($watt_init < 2 ) {//Machine is switched off or in standby if energy consumption < 1 Watt
die;//quit
}
else {//Any thing else: Machine is running
while ($i < $max) {//loop as long as max loops are not reached
$watt_current = json_combine(IPplug5);//getting current energy consumption from WIFI energy meter via JSON
sleep(60*$tackt);//sleep and continue every 60s x tact time
$i++;//increase counter +1
//compare actual consumption with defined trashhold
if ($watt_current[0] >= $trashhold) {//continue while energy consumption bigger then trashhold
continue;//repeat loop
}
elseif ($watt_current[0] < $trashhold) {//stop if energy consumption lower then trashhold
break;//stop loop
}
}
echo "Program done. please clear. Runtime: " . $i*$tackt. "Min."
//[...] message me to my telegram bot
}
}
The code is running fine and I'm getting the output I need.
My question is: Is there a better way to do that?
Currently I'm afraid to overload my Pi with too many open php sessions, therefore I'm starting the code only every 20min and also let the while loop sleep for 3 Min. But for improved accuracy I like to run the cronjob more often and also let the while loop sleep only for 30s.
My requirements are to stick to my PI and php code and not to use any available software like Home Assisant.io as it contradicts with my learning approach.
Any ideas or insights welcome.
Ideally it's a not the best approach to handling and measuring power consumption. It would be best if you created an API that accepts events like on/off or threshold hold limit extends from your IP devices. Further you can create logs and store them in databases.
Although, for your current problem here is one alternate solution.
Set your cron that runs every second.
function get_powerConsumption($machine, $watt_init, $threshold)
{
if ($watt_init < 2) {
exit();
}
$time = date("Y-m-d H:i");
$filename = $machine . '_power_consumption.log'; // expecting some machine identification name here. otherwise ignore prefix
$watt_current = json_combine(IPplug5);
if ($watt_current[0] >= $threshold) {
$data = array(
$time,
$watt_current[0]
);
file_put_contents($filename, json_encode($data) . "\n", FILE_APPEND);
} elseif ($watt_current[0] < $threshold) {
$data = array(
$time,
'stopped'
);
file_put_contents($filename, json_encode($data) . "\n", FILE_APPEND);
}
}
Create another cron to look up for stopped events logged in the file. if found process the calculation based on logged data like time and consumption. You can set this cron to run based on your need like every second or minute or after some interval.
Also, handle code to delete old logs, once stopped events found.
I am creating a small Bitcoin payment gateway to pay 0.25 BTC and only need 1 confirmation. I have created a form (form.html) which shows a unique random address ($_POST['address']) so on the next page after you hit submit I need it to display a page and do some checks for me... but when I hit submit it just says "waiting for page to load" at the bottom of my browser and doesn't actually load the page up (which has HTML on it), I'm sure this is because of a for loop hogging the page but I'm not sure how to get around it.
My for loop
for ($i=0; $i <= 900; $i++) {
$conf = file_get_contents('https://blockchain.info/q/addressbalance/' . $_POST['address'] . '?confirmations=1');
$seen = file_get_contents('https://blockchain.info/q/addressfirstseen/' . $_POST['address']);
if ($seen != 0) {
if($conf >= 25000000) {
echo "Payment Complete <br><br>";
break;
} elseif ($conf != 0 && $conf < 25000000) {
echo "You Did Not Pay Enough Bitcoins<br><br>";
break;
}
}
sleep(30);
}
I'm pretty rusty with PHP and this is my first attempt in a while, if anyone could point me in the right direction to what I am doing incorrect that would be much appreciated.
Thank you for any time anyone spends on this.
you define i as a loop counter but you are not using it?!
most probably none of the break criteria is fulfilled and you are actually doing a big sleep 900 * 30 sec = 450 minutes
I'm absolutely sure that you don't need this.
not to mention that you have to change some vars in cnf, ini ... if you need a response after that long time
from what I can see, $seen is probably zero by default and/or $conf is < = 0
sleep
for delay in milliseconds, use
usleep
haven't used php for some years, but I believe sleep is in sec.
try not doing front-end checks with back-end language as the first comment under your post says but I can only guess what you are trying to achieve ...
I want to send ~50 requests to different pages on the same domain and then, I'm using DOM object to gain urls to articles.
The problem is that this number of requests takes over 30 sec.
for ($i = 1; $i < 51; $i++)
{
$url = 'http://example.com/page/'.$i.'/';
$client = new Zend_Http_Client($url);
$response = $client->request();
$dom = new Zend_Dom_Query($response); // without this two lines, execution is also too long
$results = $dom->query('li'); //
}
Is there any way to speed this up?
It's a generel problem by design - not the code itself. If you're doing a for-loop over 50 items each opening an request to an remote uri, things get pretty slow since every requests waits until responde from the remote uri. e.g.: a request takes ~0,6 sec to been completed, multiple this by 50 and you get an exection time of 30 seconds!
Other problem is that most webserver limits its (open) connections per client to an specific amount. So even if you're able to do 50 requests simultaneously (which you're currently not), things won't speed up measurably.
In my option there is only one solution (without any deep going changes):
Change the amout of requests per exection. Make chunks from e.g. only 5 - 10 per (script)-call and trigger them by an external call (e.g. run them by cron).
Todo:
Build a wrapper function which is able to save the state of its current run ("i did request 1 - 10 at my last run, so now I have to call 11 - 20) into a file or database and trigger this function by an cron.
Example Code (untested) for better declaration;
[...]
private static $_chunks = 10; //amout of calls per run
public function cronAction() {
$lastrun = //here get last run parameter saved from local file or database
$this->crawl($lastrun);
}
private function crawl($lastrun) {
$limit = $this->_chunks + $lastrun;
for ($i = $lastrun; $i < limit; $i++)
{
[...] //do stuff here
}
//here set $lastrun parameter to new value inside local file / database
}
[...]
I can't think of a way to speed it up but you can increase the timeout limit in PHP if that is your concern:
for($i=1; $i<51; $i++) {
set_time_limit(30); //This restarts the timer to 30 seconds starting now
//Do long things here
}
Suppose I have something like this:
$count = 0;
foreach($CourseDetails as $course_line) {
print "<tr><td>{$course_line['class_code']}</td>
<td>{$course_line['class_name']}</td>
<td>{$course_line['class_unit']}</td>
<td>{$course_line['class_description']}</td>
<td>{$course_line['class_instructors']}</td>";
$count = $count + 1
if ($count = 10);
$count = 0;
// code that stops script and makes a "Continue?" button pop up on the webpage under the already outputed details
// if the client presses the "Continue?" button, allow the script to continue (jump back into the foreach loop)
}
I'm trying to find a way to stop the script and then make a button saying "Continue?". If the client presses the button, I want the script to continue where it left off. Does PHP have any functions that allow this?
Short answer: no!
This is more of a workflow design issue. I would suggest creating a list of items to execute. Then try to execute them (as they are successfully processed, mark them as complete), if an error is hit, then stop execution and let the user know. If the user wishes to continue, reload the page, and continue executing the items that have not completed from your initial list.
You can't stop the script once the page has been loaded in the browser. You can only create an interrupt condition inside the script. The two ways for "memory" between pages are either passing an URL variable, e.g. start=20, or using $_SESSION variables to remember the last point of interrupt. Better pass the variable over URL so the pages are individually accessible.
Then, in your loop, simply evaluate whether the entries have a number above the last interrupt. The following presumes your courses are in an array with a numeric index, in which case the $count is redundant. If you're pulling them from a database, take a totally different approach...
$start = !empty($_GET['start']) ? $_GET['start'] : 0;
$offset = 10;
foreach($CourseDetails as $course_num => $course_line) {
if ($course_num < $start) continue; // These were already seen.
if ($course_num >= $start + $offset) {
// Interrupt and make a button that links to ?start=$start+$offset.
break;
}
// Here display stuff.
}
got this code:
<?php
function test ($url){
$starttime = microtime(true);
$valid = #fsockopen($url, 80, $errno, $errstr, 30);
$stoptime = microtime(true);
echo (round(($stoptime-$starttime)*1000)).' ms.';
if (!$valid) {
echo "Status - Failure";
} else {
echo "Status - Success";
}
}
test('google.com');
?>
I want to have an option to execute this function every 5mins / 1hour / 1 day etc.. I was suggested using cron, but i never heard of cron before and after doing some research i understood that its a sepperate file, that would exeute the function every x amout of time. What if i would have multiple users, for example userA would want to run the script every 5mins, and userB would want to run the script every hour. In this sittuation i would need to create multiple cron files for each user?
Edit:
I was thinking about doing something like this:
for ($i = 0; $i < 100; $i++) {
test('google.com');
sleep(10 * 60);
}
Only in the sleep line i would have a custom $n field that each user would define by themselves. My problem with this was - it returns results only when the full cycle has finished, i would want it to return result after every "round?" (idk what its called, but basically would give 1 value, then 10mins later 2nd value and so on) .
The only way I found is to use an ajax method which will be called from the user page within a setTimeout.
See : settimeout function
May be you need use cron (UNIX) or Windows Tasks (Microsoft) depending the OS on your server.
Cron
Windows Task
Greetings,