PHP variable question - php

here is my code
echo ("<br/>");
if ($APIkbpersec < 30) {
global $SpeedTest;
echo ("Slow speed");
$SpeedTest--;
}
if ($APIkbpersec > 30) {
global $SpeedTest;
echo ("High speed");
$SpeedTest++;
}
echo $SpeedTest;
the page this code is in gets reloaded every second with AJAX and the $APIkbpersec changes between 40 and 0.
I basically want to have a variable ($SpeedTest) increase or decrese depending on what $APIkbpersec is.
if $APIkbpersec is less than 30, I want $SpeedTest to decrease by 1 every refresh to a minimum of 0.
if $APIkbpersec is greaterthan 30, I want $SpeedTest to increase from by 1 every refresh to a maximum of 10.
the problem is I dont know what the porblem is....Im currently trying to write $SpeedTest to a txt file so I can read it in every refresh to do the maths on it every refresh without it being reset in PHP
any help would be appreciated

It's being reset because the HTTP request is stateless. Each AJAX call is an isolated event to a PHP script. To make the variable persist, it has to be stored in $_SESSION.
You have not shown the code you're using to write it to a text file, but unless you need it to persist beyond a user session, that's the wrong approach. You're better served using $_SESSION. If you do need long-term persistence, you should use a database instead.
session_start();
// Initialize the variable if it doesn't exist yet
if (!isset($_SESSION['SpeedTest'])) {
$_SESSION['SpeedTest'] = 0;
}
echo ("<br/>");
if ($APIkbpersec < 30) {
echo ("Slow speed");
$_SESSION['SpeedTest']--;
}
if ($APIkbpersec > 30) {
echo ("High speed");
$_SESSION['SpeedTest']++;
}
echo $_SESSION['SpeedTest'];

You should use $_SESSION for that purpose.
See HERE for an explanation, but basically you would need to do the following:
session_start();
$SpeedTest = isset($_SESSION['speedTest']) ? $_SESSION['speedTest'] : 0;
if ($APIkbpersec < 30)
{
echo ("Slow speed");
$SpeedTest--;
}
if ($APIkbpersec > 30)
{
echo ("High speed");
$SpeedTest++;
}
$_SESSION['speedTest'] = $SpeedTest;
echo $SpeedTest;

Either:
Return $SpeedTest in the response and pass it back and forth.
Use some kind of persistent storage such as a cookie or PHP sessions.
Both are pretty easy to implement. If you want with persistent storage, I'd suggest a cookie as both JS and PHP could share it. Session, although the obvious candidate, are a bit overkill in this case - IMO.

If this is all of your code, the problem is simple. Each time the script is run, the values of all the variables are initialized. For your case, this means that the value of $SpeedTest does not persist - it's reset to zero each time the script is called. You can use a session as #Michael suggests (probably my recommendation), read the value out from a text file or database and then write a new value out, or you could return the value of $SpeedTest to your AJAX script and pass it back into the php script as a parameter. Each of these have various advantages and disadvantages, but using the $_SESSION superglobal is easy to do and takes little modification to your code.

If you want to do it with files you can use a single file to store a single global value for your variable:
Read data from file (docs here):
$data= file_get_contents('file.txt');
Put data into file (docs here)
$bytesWritten = file_put_contents( $data );
Else you can use sessions or database as other suggested.
Without cookies or sessions you cannot have a real "per user" solution so if you need that stick with other answers or use an hybrid solution with sessions/files
If you use the request solution (that kind of ping-pong with POST or GET variables) always pay attention because those variables can be altered by users.
Other things to remember:
Files and database records last until you delete them (so maybe you have to manage undeleted files or records).
Session duration is configured within your server (so they can last too short if you need long term persistency).
Usually database are better than files (the do more tasks and provide your application more scalability) but in some cases files solution is faster (tested) specially if your database resides in another host and is not on the same host as your webserver.

Related

PHP Session works fine under one directory, but the same code fails in a different directory

I have the below code that works fine under /t/cgi-bin/test1.php, but the same code fails under /p/cgi-bin/test1.php. Every time I run under /p/cgi-bin..., it takes me to test_log1.html right away. It is not waiting for 15 minutes before it times out to test_log1.html. Any help is appreciated.
<?php
session_start();
if(isset($_SESSION["test"]))
{
if((time() - $_SESSION['last_login_timestamp']) > 900)
{
header("location:../test_log1.html");
}
else
{
$_SESSION['last_login_timestamp'] = time();
}
}
else
{
header('location:../test_log2.html');
}
?>
Nothing wrong with the code. The file had to be recreated. It is working now. This post can be closed.
There are a few issues.
One
Perhaps because by default there is only one session per browser. It's not per tab, or per url.
So, once you have run, the session already has the last_login_timestamp. It then uses the same value for the second session.
If you want them to be different then you have to use different session ids for the two paths.
Another way is to clear/reset the session at the start of the file.
Yet another is to use a different test variable such as test1 and test2.
Two
test is never getting set, and the value of last_login_timestamp is null. I am assuming that you are setting test elsewhere. So, for testing, here is the updated code. The ?? operator ensures that the value goes to time when it is null
<?php
session_start();
if(isset($_SESSION["test"]))
{
$last = $_SESSION['last_login_timestamp'] ?? time();
if((time() - $last) > 900)
{
header("location:../test_log1.html");
}
else
{
echo 'Has not timed out';
}
}
else
{
$_SESSION["test"] = 'xx';
header('location:../test_log2.html');
}
?>
If you want three independent sessions then you have to use different session_ids or just different variables. So use test_p and last_login_timestamp_p for directory p, etc.
Three
PHP is a server side language. When run, nothing is sent to the browser, except the redirect, or echo from this code above.
Once the session variable is set, and 15 mins later you run the code, it will time out in both places. This will keep happening from then on, until the session variable is cleared.
However, it can not time out on the browser and go to a different page by itself, after 15 mins. For that you need to use javascript.
try:
header('Location: '../test_log2.html');

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.

php - simple cache feature - retrieve data every hour

I want to set up a simple cache feature with php. I want the script to get data from somewhere, but not to do it on every page view, but only every hour.
I know i can have a cron job that runs a php script every hour.
But I was wondering if this can be achieved without cron, just inside the php script that created the page based on the data fetched (or cached). I'm really looking the simplest solution possible. It doesn't have to be accurate
I would use APC as well, but in either case you still need some logic. Basic file cache in PHP:
if (file_exists($cache_file) and time() - filemtime($cache_file) < 3600)
{
$content = unserialize(file_get_contents($cache_file));
}
else
{
$content = your_get_content_function_here();
file_put_contents($cache_file, serialize($content));
}
You only need to serialize/unserialize if $content is not a string (e.g. an array or object).
Why just don't use APC ?
you can do
apc_store('yourkey','yourvalue',3600);
And then you can retrive the content with:
apc_fetch();

Prevent Code or Function from Executing More Than Once

Is there a way to prevent a code-block or a function within a code from running more than once even if I re-execute (or reload) the PHP file?
I mean, can I restrict someone from executing a php script more than once? I can't seem to find the way to do this.
Yes, you can use a $_SESSION variable to determine if the code has been executed. The session variable will be set until the user closes their browser. If you want to extend it further than that, you can set a cookie. Please see the following links for more details.
Session Variables
Cookies
If you are using sessions, then you can set a flag in the user's session array after the code has executed:
function doSomething(){
if (empty($_SESSION['completed'])){
//Do stuff here if it has not been executed.
}
$_SESSION['completed'] = TRUE;
}
You should also check the sesison variable to see if the task has been executed previously. This assumes that the user can accept a session cookie.
I have an app that does that.
What we did was create a table in the db called version, and stored a version number in there. When the script is ran, it compared the version number in the database with that in the php script. And perform whatever it needs to "upgrade" it to the new version, and then updates the version number in the database.
Of couse, if the version table does not exist, the code will create it and mark it as storing version zero.
Just put a counter in the function. If the counter is greater that 0, then don't do anything. The counter variable should be static so it "remembered" across multiple calls.
function sample() {
static $call_counter = 0;
if ( $call_counter>0 ) {
return;
}
...
$call_counter++;
}
As for making sure a file is only executed once, just use "include_once()" instead of "include()".

How to design an AJAX interface to show progress bar based ona running script backend

Ok here is my problem.
I have a file which outputs an XML based on an input X
I have another file which calls the above(1) file with 10000 (i mean many) times with different numbers for X
When an user clicks "Go" It should go through all those 10000 Xs and simultaneously show him a progress of how many are done. (hmm may be updated once every 10sec).
How do i do it? I need ideas. I know how to AJAX and stuff, but whats the structure my program should take?
EDIT
So according to the answer given below i did store my output in a session variable. It then outputs the answer. What is happening is:
When i execute a loong script. It gets executed say within 1min. But in the mean time if i open (in a new window) just the file which outputs my SESSION variable, then it doesnt output will the first script has run. Which is completely opposite to what i want. Whats the problem here? Is it my syste/server which doesnt handle multiple requests or what?
EDIT 2
I use the files approach:
To read what i want
> <?php include_once '../includeTop.php'; echo
> util::readFromLog("../../Files/progressData.tmp"); ?>
and in another script
$processed ++;
util::writeToLog($dir.'/progressData.tmp', "Files processed: $processed");
where the functions are:
public static function writeToLog($file,$data) {
$f = fopen($file,"w");
fwrite($f, $data);
fclose($f);
}
public static function readFromLog($file) {
return file_get_contents($file);
}
But still the same problem persist :(. I can manually see the file gettin updated like 1, 2, 3 etc. But when i run my script to do from php it just waits till my original script is output.
EDIT 3
Ok i finally found the solution. Instead of seeking the output from the php file i directly goto the log now and seek it.
Put the progress (i.e. how far are you into the 2nd file) into a memcached directly from the background job, then deliver that value if requested by the javascript application (triggered by a timer, as long as you did not reach a 100%). The only thing you need to figure out is how to pass some sort of "transaction ID" to both the background job and the javascript side, so they access the same key in memcached.
Edit: I was wrong about $_SESSION. It doesn't update asynchronously, i.e. the values you store in it are not accessible until the script has finished. Whoops.
So the progress needs to be stored in something that does update asynchronously: Memory (like pyroscope suggests, and which is still the best solution), a file, or the database.
In other words, instead of using $_SESSION to store the value, it should be stored by memcached, in a file or in the database.
I.e. using the database
$progress = 0;
mysql_query("INSERT INTO `progress` (`id`, `progress`) VALUES ($uid, $progress)");
# loop starts
# processing...
$progress += $some_increment;
mysql_query("UPDATE `progress` SET `progress`=$progress WHERE `id`=$uid");
# loop ends
Or using a file
$progress = 0;
file_put_contents("/path/to/progress_files/$uid", $progress);
# loop starts
# processing...
$progress += $some_increment;
file_put_contents("/path/to/progress_files/$uid", $progress);
# loop ends
And then read the file/select from the database, when requesting progress via ajax. But it's not a pretty solution compared to memcached.
Also, remember to remove the file/database row once it's all done.
You could put the progress in a $_SESSION variable (you'll need a unique name for it), and update it while the process runs. Meanwhile your ajax request simply gets that variable at a specific interval
function heavy_process($input, $uid) {
$_SESSION[$uid] = 0;
# loop begins
# processing...
$_SESSION[$uid] += $some_increment;
# loop ends
}
Then have a url that simply spits out the $_SESSION[$uid] value when it's requested via ajax. Then use the returned value to update the progress bar. Use something like sha1(microtime()) to create the $uid
Edit: pyroscope's solution is technically better, but if you don't have a server with memcached or the ability to run background processes, you can use $_SESSION instead

Categories