This may be a silly question, but how do I save variables that are not specific to a particular session. An simple example of why you might want to do this would be a visitor counter - a number that increases by one each time someone visits a web page (note - I'm not actually doing that, my application is different, but that is the functionality I need). The only ways I can think of doing this are either writing the variables to a file, or putting the variables into a database. Both seem a bit inelegant. Is there a better way to to this kind of thing?
If you need to save global state, you need to save global state. This is typically done in either a file or a database as you already noted.
It's not "inelegant" at all. If you need to save something (semi-)permanently, you put it in a database. That's what databases are for.
Have a look at the serialize() function in PHP http://uk3.php.net/serialize where you'll be able to write an array or such to a file and re-retrieve:
<?php
// Save contents
$var = array('pageCounter' => 1);
file_put_contents('counter.txt', serialize($var));
// Retrieve it
$var = unserialize(file_get_contents('counter.txt'));
?>
Otherwise save the value to a database.
Given that PHP is stateless and that each pageload is essentially re-running your page anew, if you're going to be saving variables that will increment over multiple pageloads (e.g., number of distinct users), you'll have to use some form of server-end storage - file-based, database, whatever - to save the variable.
You could try installing APC (Alternative PHP Cache) which has cool features for sharing data between all PHP scripts, you could try using shared memory too or like you said, use a file or database
I think I've found the answer - session_name('whatever') can be used to have a fixed name for a session, I can refer to that data as well as the session specific session.
If you want it to be permanent, database and files are really your only two choices.
If you only want to temporarily store these values in memory, if APC is installed, you can do this:
// Fetch counter value back from memory
$success = false;
$counter = apc_fetch('counter', &$success);
if ($success) {
// fetch succeeded
} else {
// fetch failed
$counter = 0;
}
// Increment the counter and store again
// Note that nothing stops another request/page from changing this value
// between the fetch and store calls.
$counter++;
apc_store('counter', $counter);
That was just an example.
For a counter, you're better off using apc_inc('counter') / apc_dec('counter').
Presumably other opcode caches have similar methods. If you're not running an opcode cache... really? You want PHP to recompile a page every time its requested?
Elegant, no database and no file ?
Store it in your server memory with shmop and hope your server does not reboot !
Related
I have a PHP script that can take a few minutes to be done. It's some search engine which executes a bunch of regex commands and retrieve the results to the user.
I start by displaying a "loading page" which does an AJAX call to the big processing method in my controller (let's call it 'P'). This method then returns a partial view and I just replace my "loading page" content with that partial view. It works fine.
Now what I would like to do is give the user some information about the process (and later on, some control over it), like how many results the script has already found. To achieve that, I do another AJAX call every 5 seconds which is supposed to retrieve the current number of results and display it in a simple html element. This call uses a method 'R' in the same controller as method 'P'.
Now the problem I have is that I'm not able to retrieve the correct current number of results. I tried 2 things :
Session variable ('file' driver) : in 'P' I first set a session variable 'v' to 0 and then update 'v' every time a new result is found. 'R' simply returns response()->json(session('v'))
Controller variable : same principle as above but I use a variable declared at the top of my controller.
The AJAX call to 'P' works in both cases, but everytime and in both cases it returns 0. If I send back 'v' at the end of the 'P' script, it has the correct value.
So to me it looks like 'R' can't access the actual current value of 'v', it only access some 'cached' version of it.
Does anyone have an idea about how I'm going to be able to achieve what I'd like to do? Is there another "cleaner" approach and/or what is wrong with mine?
Thank you, have a nice day!
__
Some pseudo-code to hopefully make it a bit more precise.
SearchController.php
function P() {
$i = 0;
session(['count' => $i]); // set session variable
$results = sqlQuery(); // get rows from DB
foreach ($results as $result) {
if (regexFunction($result))
$i++
session(['count' => $i]); // update session variable
}
return response()->json('a bunch of stuff');
}
function R() {
return response()->json(session('count')); // always returns 0
}
I would recommend a different approach here.
Read a bit more about flushing content here http://php.net/manual/en/ref.outcontrol.php and then use it.
Long story short in order to display the numbers of row processed with flushing you could just make a loop result and flush from time to time or at an exact number or rows, the need for the 5 seconds AJAX is gone. Small untested example :
$cnt = 0;
foreach($result as $key => $val) {
//do your processing here
if ($cnt % 100 == 0) {
//here echo smth for flushing, you can echo some javascript, tough not nice
echo "<script>showProcess({$cnt});</script>";
ob_flush();
}
}
// now render the proccessed full result
And in the showProcess javascript function make what you want... some jquery replace in a text or some graphical stuff...
Hopefully u are not using fast_cgi, beacause in order to activate output buffering you need to disable some important features.
I believe you have hit a wall with PHP limitations. PHP doesn't multithread, well. To achieve the level of interaction you are probably required to edit the session files directly, the path of which can be found in your session.save_path global through php_info(), and you can edit this path with session_save_path(String). Though this isn't recommended usage, do so at your own risk.
Alternatively use a JSON TXT file stored somewhere on your computer/server, identifying them in a similar manner to the session files.
You should store the current progress of the query to a file and also if the transaction has been interrupted by the user. a check should be performed on the status of the interrupt bit/boolean before continuing to iterate over the result set.
The issue arises when you consider concurrency, what if the boolean is edited just slightly before, or at the same time, as the count array? Perhaps you just keep updating the file with interrupts until the other script gets the message. This however is not an elegant solution.
Nor does this solution allow for concurrent queries being run by the same user. to counter this an additional check should be performed on the session file to determine if something is already running. An error should be flagged to notify the user.
Given the option, I would personally, rewrite the code in either JSP or ASP.NET
All in all this is a lot of work for an unreliable feature.
I'm currently coding one of my first php applications.
The application has to connect to a LDAP server and change some user attributes in the directory.
That application has some parameters to read in a mySQL Database in order to run.
Some examples of these parameters could be:
-LDAP Address
-LDAP Service Account
-LDAP Password
there are much more parameters, which rule, for example, the way users authenticate to my application,...
Currently, the database is read at each user session initialization, but, it doesn't have any sense because parameters do not vary from a session to another.
So, i'm looking for a way to load these parameters from the database, only one time (for example, at the php service initialization), and access to these parameters in the "normal" php code through variables.
What would be the best way to do this?
Thank you in advance.
You are looking for a persistent cross-request storage. There are many options for this.
The simplest is APCu (which can be used in conjunction with Zend OpCache, or for PHP < 5.5, APC).
Simply:
if (apc_exists('mykey')) {
$data = apc_fetch('mykey');
} else {
// create it from scratch
apc_store('mike', $data);
}
$data can be most any PHP type, arrays, objects, or scalars.
You can even put this code in the auto_prepend_file INI setting so it is run automatically on every request.
However: this is per server (and per SAPI, so mod_php/php-fpm/cli don't share the cache) so you will have to create it once per server.
Alternatively, for a multi-server setup you can use something like memcached or redis. These are stand-alone daemons that will let you store arbitrary key/value pairs of string data (so you may need to serialize()/unserialize() on the values).
I personally prefer memcache, which has two extensions for PHP, pecl/memcached and pecl/memcache (I prefer pecl/memcached, it has more features).
Both of them are pretty simple.
pecl/memcached:
$memcache = new Memcached();
$memcache->addServer('localhost', '11211');
$data = $memcache->get('mykey');
if (empty($data)) {
// Create data
$memcache->set('mykey', $data);
}
pecl/memcache:
$memcache = new Memcache();
$memcache->connect(); // uses localhost:11211, the default memcache host/port
$data = $memcache->get('mykey');
if (empty($data)) {
// Create data
$memcache->set('mykey', $data);
}
Both extensions support storage of arrays and objects without serialization.
You can of course store multiple keys with any of these solutions and just pull them all, instead of using one, or one with an array/object.
You can use Memcache do cache database requests. See here how to use.
Another way is using Php Sessions.
<?php
session_start(); // need to be before any html code
$_SESSION['something'] = 'Something here...';
echo $_SESSION['something']; // will show "Something here..."
And you can remove using...
unset($_SESSION['something']);
You also can use cookies, using the function setcookie. See here.
And you can get cookies using...
echo $_COOKIE['something'];
Production mode
In a production mode, this will work as set_transient of Wordpress. You will do the first db request to get the value and will cache this value using cookies, sessions or memcache.
If you want to show this values inside of your page, you can use a standard caching library.
My understanding of the question is that you have some SQL data that is more or less constant and you don't want to have to read that in from the SQL connection on every request.
If that is the case you can use memcache to store the data:
http://php.net/manual/en/book.memcache.php
The data will still be persistent and you will only need to go to the database if the cached data isn't there or needs to be refreshed.
If the data is specific to a particular user you can just use a session.
http://php.net/manual/en/book.session.php
http://php.net/manual/en/session.examples.basic.php
If this is only to be used when starting up your server (so once and done) and you don't want to bother to with memcached/xcache (as they would be over kill) you can still use environment variables. See get_env
I want to store a single integer like so:
<?php
$_SERVER['amount'] = 54;
echo($_SERVER['amount']);
?>
And be able to modify it, as well as be accessed from every new php session. However whenever the session ends the server variable disappears. How can i store a single variable on the server without a database? A .txt file seems kinda unnecessary for 2 characters stored.
Your storage options are a file, a hardcoded variable in the PHP code, a database table, a cookie or a session variable, as I understand it. Probably the most elegant solution if you already are using a database is to add a new table with your permanent data variables.
Another solution, if you are looking for a quick and dirty solution, is to add a global php variable with a magic number, which is really what you are trying to do with your server variable, eg global $_AMOUNT = 54; // The amount is always 54 for all users. That doesn't really meet your requirement of being able to modify it each time the page is accessed, though.
$_SERVER is a superglobal, which is read from a file each time PHP is initiated on every pageload. You are not writing to the file that the variable is read from, and so it resets each time the script executes.
Just make a database table, in my opinion. Make one row for the table, amount. I am willing to bet the table will grow over time as you add more global variables.
You could use file_put_contents and create a kind of cache file then use file_get_contents to retrieve the data..
file_get_contents AND
file_put_contents
something like
$data = array(
'something' => 'this',
'somethingelse' => 'again',
);
$settings = json_encode($data);
file_put_content( 'settings.txt', $settings);
//then
$texstSettings = file_get_contents('settings.txt' );
$settings = json_decode(texstSettings);
i have a query that, how can i transfer an object from php file A to php file B?.
but i know a solution using session.But what i need to know is, is their any other method to transfer object between php files other than session?
APC is probabaly the easiest method:
example:
// new object
$object = new ClassName('Kieran', 123);
// Store it
apc_store('object', $object);
The other script
$obj = apc_fetch('object');
print_r($obj->method());
Save in a file, save in a database, save in shared memory, save in a cache server.
One way is to store the serialized object - or its data - into a database, using the session ID as the key to "find" it again.
The same could be done using a cache file.
A faster way is using a shared memory cache like memcache. These solutions always require server-side administration and root access to set up.
you can use this method:
serialize() and unserialize()
fileA.php :
<?php
require_once 'employee.class.php';
$employee=new employee($id,$firstname,$lastname);
$serializeemployee=serialize($employee);
session_start();
$_SESSION['employee']=$serializeemployee;
header('location: ./fileB.php');
?>
fileB.php :
<?php
session_start();
if(isset($_SESSION['employee']) && $_SESSION['employee'])
{
require_once 'employee.class.php';
$employee=unserialize($_SESSION['employee']);
echo $employee->getFirstname();
?>
Serialize the object and store in one of the following (Database,Temp,Memcache).
Depending on what the object consists of i would take a look at implementing the __sleep and __wake magic methods to make sure the object is able to be transferred correctly.
by using cURL you can transfer any thing... try this..
http://php.net/manual/en/book.curl.php
The easiest way (besides using sessions) is probably to save it as an APC (Alternative PHP Cache) user variable, as you probably will install APC for opcode caching purposes already. This way you have one extension for two things.
APC stores values inmemory as Memcached does, but is way easier to install, because it's not an extra daemon running, but a PHP extension.
Ok, I am storing a session variable like so to load up users layouts faster if it's set instead of calling the database. But since the layout can be changed via the Administrator, I'd like to be able to globally remove all sessions where $_SESSION['layout']['action'] is set for all users.
$_SESSION['layout']['action'] = array(a ton of indexes and mulit-dimensional arrays);
Now, I know it's being stored into my database sessions table, there's a column for session_id, last_update, and data. So, question I have is how to remove that session array key ['action'] from all users.
Using
$_SESSION = array();
session_destroy();
Does not work.
Basically, session_start() is being loaded on every page load, so I just want to remove all ['action'] keys from ['layout'].
Is this possible to do?
Thanks
Ok, I am storing a session variable
like so to load up users layouts
wrong
I'd like to be able to globally remove
all sessions where
wrong
it's being stored into my database
OMG "t instead of calling the database"!
Is this possible to do? Thanks
Leave sessions alone and don't use it for the global settings.
If you don't want to hit the database each time to load configuration data, you can cache it in a generated .inc file. Remember, PHP is just text - you can use a PHP script to generate another PHP script:
$fh = fopen('sitevars.inc'); // skipping error handling, since this is an example.
fwrite($fh, '<' . '?php' . "\n"); // split the <? tags in case an unbalanced ' somewhere hoses things
fwrite($fh, '$lifetheuniverse = 42;' . "\n"); // single quotes to the $ doesn't have to be escaped.
fwrite($fh, "\$layoutaction = 'slap forehead with palm';\n");
fclose($fh);
and then you just include_once('sitevars.inc'); and boom, it's a "global" variable. No messing with sessions.
That being said, if your sessions are being stored in the database, most likely they're in serialized format. To do a proper job of stripping a particular "global" session var from each, you'd have to load each record, de-serialize, delete the variable, re-serialize, and re-save into the DB. And hope you don't trash someone's session who happens to be active at the time you're doing these updates.