Not looking for written code, just advise on how or what is needed to do what I explain. This is the hardest part, conveying my idea into what I need to be able to do it not knowing what functions would do it.
I want to execute PHP script A by a simple http web call. No big deal. Inside script A I want it to execute script B, which I know how to do, and I want it to also execute script C, but only execute script C once in a 60 second time-frame, no matter how many times script A is called on, because script A will be called on many times in that time frame and continually needs to execute script B. When 60 seconds (or whatever I want to designate) has passed then script A resets itself so that script C is executable once more in a new 60 second time-frame. Timers = sleep(x). So what do I need to do so script A so that it maybe excludes executing script C in the 60 second time after it executes it once? Like the code to execute script C would be "locked out" or passed over. What functions should I be looking into to learn this? Structure is killing me.
I would use sessions. Record the time you call C in a session variable and don't allow A to call C until 60 seconds has passed since that time. At the top of A (it needs to happen before any output from the script) add:
session_start();
when you want to call C, use something like this:
if (!isset($_SESSION['c_call_time']) || $_SESSION['c_call_time'] < time() - 60) {
$_SESSION['c_call_time'] = time();
// call C
}
#user655685 raises a valid point about the script possibly being called by different users, and the time limit applying separately to each of them. If this is a problem, you could work around it by declaring custom session handlers that used the same storage location for all users. See the manual for a description of how to do that (in their example, you would ignore the $id parameter passed to the read and write callbacks).
Sessions would solve this problem , but if the script is called by another user this would break , since php runs each environment saperate on php alone this would be impossible. You will have to either create an outside variable (ie file) or database entry which tracks when this was last run and then delete the file every minute ( file / database entry to have time stamp of last run)
Related
i have a big script written in php, which should import a lot of informations in a prestashop installation, using webservices, this script is written in "sections" I mean, there is a function that import the categories, another one that import products, then manufacturers, and so on, there are about 7 - 10 functions called in the main script. Basically I assume that this script must run for about an hour, passing from a function to the next one and so on since it arrives at the last function, then return some values and stops until the next night.
i would like to understand if it could be better :
1) impose a time limit of 30 minutes everytime i enter a new function (this will prevent the timeout)
2) make a chain of pages, each one with a single function call (and of course the time limit)
or any other idea... i would like to :
know if a function has been called (maybe using a global variable?)
be sure that the server will execute the function in order (so the pages chain)...
i hope to have beeen clear, otherwise i'll update the question.
edits:
the script is executed by another server that will call a page, the other server is "unkown" from me, so I simply know only that this page is called (they could also call the function by going on the page) but anyway i have no controll on it.
For any long running scripts, I would run it through the commandline, probably with a cronjob to kick it off. If it's triggered from the outside, I would create a job queue (for example in the database) where you insert a new row to signify that it should run, along with any variable input params. Then the background job would run - say - every 5 minutes, check if there's a new job in the queue. If there's not, just exit. If there is, mark that it has begun work and start processing. When done, mark that it's done.
1 hour of work is a looooooooong time though. Nothing you can do to optimise that?
You can increase the time limit for execution of a script as much as you want using :
set_time_limit(seconds);
And also for long running scripts you need a more memory. you can increase the memory limit using :
ini_set('memory_limit','20M');
And second other thing you have to make sure is that you are running your script on a dedicated server because if you are using a shared server you server will kill automatically long running scripts.
I run a procedure that takes about 20 minutes to complete, I just wonder if PHP can keep the connection active until the process finishes.
To be clear, this page will have a button which when you press it will call a php page to run a sql query, in the main page I just wait for the Http request to be complete to send a success message.
For queries that are set to take up some time, you should move some automation requests into the mix, preferably cronjobs if you have access to a linux server.
With cronjobs, you can create enteries in the database for specific values, linked to the user. The cronjob will kick in lets say, every 5 minutes to execute a query if a pending query has finished. This will minimize the fact the user will need to sit on the page until completion. Because you should know, the second the user navigates away from the active page; all active connections, queries etc will stop.
Once the script has complete, make a custom message at the end to send to the user letting them know that their process has been completed.
You should also know, PHP works down the script, from line 1 to the end; so if your hang is on line 40 for example; the script will sit on that line until the query has completed then carry on processing.
Edit: This is for example purposes only to point you in the direction that i'm getting at, and should not be used as you see it. This is merely a markup example
<?php
if (isset($_POST['ButtonToExecute']))
{
// Query to update a table in your database which an external PHP script will work with
// Example Table Structure:
/*
Username
State
*/
if ($state == 0)
{
// Then update state to 1 with username to the username for the query to take place on
}
else
{
// Warn user that their process will take longer to complete as their already is an active query in process
// but add them to a secondry pipeline which will be picked up on the next cronjob interval
}
}
?>
On your cronjob, might have:
<?php
if ($state=='1')
{
// Execute your script
// After query execution update state to 2
// if state == 2 then insert custom message/email to send
}
?>
Edit your crontab:
yourpreferrededitor /etc/crontab
^ Where yourpreferrededitor means your text editor, whether nano or other.
and your cronjob line:
* * * * * root /usr/bin/php /var/www/cron.php
^ This is taken from a current cronjob I have constantly running set for every minute of every day
A Cronjob will give the user the ability to navigate away from the page, because as I mentioned above, the second the user navigates away from the script.. All on going processes stop. The cronjob will carry on running throughout without no user interaction needed (apart from they make the initial request)
You could do it in an ordinary php script if you set the timeout limit and ignore user abort but this is a bad idea because your user will have no feedback if the script worked.
At the company I work at we had the same problem
What we did:
Run the query in a separate script.
Start the script WITHOUT waiting for results
Split the query into multiple parts (using limit and offset)
Have the query script write messages to a temp file
Implement a status screen fetching the current state from the log via ajax
BTW an example for all the wise guys asking why it takes so long:
using a transitive hull can speed up your application a lot if you have to deal with a tree with millions of nodes but building it can take hours.
You could try:
set_time_limit(0);
You may want to take a look at Set Time Limit
In your PHP ini you can set a max-execution time for scripts, however you NEVER want to have a user sit on a page loading screen for that long.
One thing that I could suggest would to e increase your max execution time to something around 30 minutes, and then call this in javascript after a page has already been rendered, so the user will not be left in the dark not knowing what the script is doing.
I'm making a PHP site, and I would like to have a script (when you click a button) which adds some info to my MySQL database (I can do this part by myself) and it executes a script 5 minutes later. Maybe it's not difficult, but it's hard to google stuff like this.
Sleep is a VERY bad idea. Client browser would have to wait 5 minutes to finish request!!!
In my opinion it's not possible to do it like you want to.
You should create another script which queries database and checks if there is new data (and on successful fetch does the job). This script should be run by cron every N minutes.
Pretty tough one.
I'd go for something like this:
your original script adds a record to the database, containing its time of execution,
another script contains the action that needs to be taken 5 minutes later - but launches it only if the db record mentioned above contains a timestamp of at least 5 minues ago (hope that's clear enough, I'm having trouble phrasing this)
set crontab to execute the second script every X minutes (perhaps 2).
It won't be 5 minutes EXACTLY, but rather something between 5 and 7 (in case you choose to launch the script every 2 minutes). Would that do?
You could implement a queue in your database, where you add "commands" to be executed, and also store when to execute this command. Then have a cron job that runs every minute and checks said queue to see if it's time to execute a certain command.
If you're on a unix box:
exec("echo 'php script.php' | at now +5 minutes");
Which will schedule the php script.php command to run after 5 minutes.
I'm making a browser-based game and I want it to if someone wants to build a building it takes * minutes and then finishes.
Considering this is your actual goal, I recommend just saving the original building with a timestamp.
I know you tagged your question with PHP, but I don't want to include all the overhead of handling mysql queries in PHP, especially since I don't know how you prefer to execute the queries or what framework you're suing, so here's some pseudocode to handle this "building buildings" task:
build.php
building_type_id = sanitize(POST['id'])
user_id = current_user['id']
query('INSERT INTO buildings (user_id, building_type_id, created_at)
VALUES (' + user_id + ', ' + building_type_id + ', CURRENT_TIME)');
my_buildings.php
user_id = current_user['id']
completed_buildings = query('SELECT * FROM buildings b
LEFT OUTER JOIN building_types t ON b.building_type_id = t.id
WHERE DATE_ADD(b.created_at, INTERVAL t.construction_time SECOND) < NOW();')
under_construction = query('SELECT * FROM buildings b
LEFT OUTER JOIN building_types t ON b.building_type_id = t.id
WHERE DATE_ADD(b.created_at, INTERVAL t.construction_time SECOND) > NOW();')
Hope this helps!
IMHO the best way is: On button click save the job to run in the db with the time it should run. Write a small daemon, fetches every 10/5/2 seconds new jobs which should be executed and executes them.
EDIT: Btw the idea using cron for checking for new jobs to execute, is better, but only if you have a small website and you don't need to do load balancing for the jobs.
The way I would do this is to run a cron job between the two scripts.
the first script sets a value in a database table.
the cron job executes the second script. every minute or what not.
the second script checks for the database value set by script 1 to decide whether to run entirely or not.
I would suggest doing the timer in Javascript rather than PHP.
Put a timestamp in the user's $_SESSION to indicate when they started the event, and then have Javascript call back to the browser after five minutes.
PHP would still need to know the start time (to prevent the user from hacking the game by tweaking the Javascript time-out), but it wouldn't need to actually do any count-down timing or sleeping or anything like that itself.
You could fork the process and in the child fork, do a sleep for 5 minutes before executing your second script. I've tested this and it appears the child process will still execute even after the parent has finished. Something like
//initial code
$pid = pcntl_fork(); //fork the process
if ($pid==0) // if in the child
{
exec("sleep 300; php second_process.php"); //sleep for 5 minutes and execute second script
return; // or exit
}
// rest of initial script...
The "return;" is important as the rest of the script will execute a 2nd time (i.e. in the child) unless it's there.
Someone asked about the purpose of this and your answer was:
"I'm making a browser-based game and I want it to if someone wants to build a building it takes * minutes and then finishes"
You don't actually need to time an execution for this. You can do it all in one run by storing buildStartedAt and buildFinishedAt as part of the building-schema.
Now maybe you want the building to have a nice animation when it finishes, then you just do all of that on the frontend but make sure nothing meaningful can be done with the building if the timestamp is before the buildFinishedAt time in order to a void cheating by potential hackers.
Are you looking for that?
sleep php.net
I'm pretty sure I've seen this done in a php script once, although I cant find the script. It was some script that would automatically check for updates to that script, and then replace itself if there was an update.
I don't actually need all that, I just want to be able to make my PHP script automatically run every 30 minutes to an hour, but I'd like to do it without cronjobs, if its possible.
Any suggestions? Or is it even possible?
EDIT: After reading through a possible duplicate that RC linked to, I'd like to clarify.
I'd like to do this completely without using resources outside of the PHP script. AKA no outside cronjobs that send a GET request. I'd also like to do it without keeping the script running constantly and sleeping for 30 minutes
If you get enough hits this will work...
Store a last update time somewhere(file, db, etc...). In a file that gets enough hits add a code that checks if the last update time was more xx minutes ago. If it was then run the script.
You may want to use the PHP's sleep function with specified time to run your code with that interval or you may want to try some online cron job services if you wish.
Without keeping the script running constantly, you'll either have to use something hackish that's not guaranteed to actually run (using regular user pages accesses to run a side routine to see if X amount of time has passed since last run of the script and if so, run it again), or use an external service like cron. There's no way for a regular PHP script to just magically invoke itself.
You can either use AJAX calls from your real visitors to run scheduled jobs in the background (google for "poor man's cron", there are a number of implementations out there) or use some external cron-like service (for example a cronjob on some other machine). In theory you could just run a PHP script with no timeout and make it loop forever and fire off requests at the appropriate time, but the only thing that would achieve is reinventing cron in a very ineffective and fragile way (if the script dies for some reason, it will never start again on its own, while cron would just call it again).
Either way, you will need to set proper execution time so the script does not exceed it.
I found this:
<?php
// name of your file
$myFile="time.db";
$time=file($myFile);
if(time()-3600 > $time[0]){
// an hour has elapsed
// do your thing.
// write the new timestamp to file
$fh = fopen($myFile, 'w') or die("can't open file");
fwrite($fh, time());
fclose($fh);
}
else{
// it hasn't been an hour yet, so do nothing
}
?>
in here
If the host includes a mysql 5.1+ db then perhaps timed triggers are availible to call the script? I like these mission impossible type questions, but need more information on what kind of playground and rules for the best answer.
Objects:
Object Sale
n Object User will participate on Object Sale
Each User can create one Object Agent
Each Agent will generate n Object Licitation (from time to time and with some conditions) for the object Sale
Goal:
Create a function that when a Sale has only 5 seconds left to end, will check all the Agents that there are for this Sale and post a licitation from the Agent that hasn't made a licitation on this sale the longest
This is something that needs to be continuously running since this agents would be in charge to replace users on posting licitations allowing them to be away during auctions.
My question
Updated (My question wasn't clear enough):
At index page of the sales I have a script with javascript that calculates the time left on a sale, so I can know when a sale should call the function to check for agents and place their bids, but my newbie question is: if I make a call for the function at this page, will this only work if the user has the page open? Or if he closes the function won't be called anymore? Because I need this to still work even the user closes webpage.
DaMacc already answered that this doesn't work
Updated (05/01/2010)
I've already created this function. The function will find all the sales that have 5 seconds left to end, then it will search all the agents and then place a bid from the agent that hasn't made a licitation on the selected sale the longest. Now i need this function to be called every second. I was going to use cron but cron has 1-minute boundaries. And I need this function to run on the server and not depend on the user that owns the agent.
Any suggestions?
PS: there are some auctions websites that have this kind of bidagents i'm trying to do, I could reffer one to use as example... But i'm not sure i'm allowed to do that here... :S
Thanks.
Create your normal function to do whatever it is you need to do and then use something like cron to set it up as a task to run every X amount of time.
Edit to expand on comments
In that case you are probably better off combining a few solutions. As mentioned in this question, I would recommend that you use cron to call a script every minute and in that script you run your process in a loop.
Some things to consider:
How long will each execution take?
Will you need to time_sleep_until at the end of each loop or will your script take longer than 1 second to run, in which case you will need to be calling the script multiple times from cron.
Be sure to keep track of how long your script has been running for as you don't want to have the situation where every minute you are taking up more and more resources as the script called the previous minute hasn't finished yet.
At the start of the script, take note of the current time, then at the start of each loop, check whether a minute has passed since the start of the script, if it has, exit the script (as another script will have taken over now thanks to cron).
Hope this helps. Let me know if this doesn't make a lot of sense and I'll try to clear it up a bit.
I wonder if this is what you are looking for:
function execInBackground($cmd) {
if (substr(php_uname(), 0, 7) == "Windows") {
pclose(popen("start /B ". $cmd, "r"));
} else {
exec($cmd . " > /dev/null &");
}
}
You can then start a php process in the background using the following method:
execInBackground("php path/to/file.php " . $param01 . " " . $param02);
// where $param01 and $param02 are optional values that you may want to
// send to the page. Equivalent to GET parameters of URL.
// You can include as many parameter values as you want.
//Example:
execInBackground("php automation/bidChecker.php daniel 53.25");
// automation/bidChecker.php is the file to be executed
// daniel can be the username
// 53.25 can be the bid value
And in the PHP file that runs in the background, you can access the parameter values using the following method:
$param01 = $argv[1]; // assigns daniel as value
$param02 = $argv[2]; // assigns 53.25 as value
This process can be started from within a script run when the user does something. It will also keep on running even if the user leaves the page and until you programatically break the operation.
I really don't know if this is what you are looking for. If so, you got it now.
Use a Queue, like Zend_Queue: http://framework.zend.com/manual/en/zend.queue.html . Just run an infinite loop (or two) and dispatch messages sent from your web application
Have you looked into using Javascript at all for this? If you have certain events that trigger the need to run this check, it may be the way to go.
You could write a js function included on every page that uses the the setInterval/clearInterval javascript functions to send an AJAX request to your server every few seconds and could send a different response back to the browser based on whether the conditions were met or not. (bandwidth may be an issue with this though)
I would recommend looking into jQuery and using it's AJAX functions for this.