On my website there is a php function func1(), which gets some info from other resources. It is very costly to run this function.
I want that when Visitor1 comes to my website then this func1() is executed and the value is stored in $variable1=func1(); in a text file (or something, but not a database).
Then a time interval of 5 min starts and when during this interval Visitor2 visits my website then he gets the value from the text file without calling the function func1().
When Visitor3 comes in 20 min, the function should be used again and store the new value for 5 minutes.
How to make it? A small working example would be nice.
Store it in a file, and check the file's timestamp with filemtime(). If it's too old, refresh it.
$maxage = 1200; // 20 minutes...
// If the file already exists and is older than the max age
// or doesn't exist yet...
if (!file_exists("file.txt") || (file_exists("file.txt") && filemtime("file.txt") < (time() - $maxage))) {
// Write a new value with file_put_contents()
$value = func1();
file_put_contents("file.txt", $value);
}
else {
// Otherwise read the value from the file...
$value = file_get_contents("file.txt");
}
Note: There are dedicated caching systems out there already, but if you only have this one value to worry about, this is a simple caching method.
What you are trying to accomplish is called caching. Some of the other answers you see here describe caching at it's simplest: to a file. There are many other options for caching depending on the size of the data, needs of the application, etc.
Here are some caching storage options:
File
Database/SQLite (yes, you can cache to a database)
MemCached
APC
XCache
There are also many things you can cache. Here are a few:
Plain Text/HTML
Serialized data such as PHP objects
Function Call output
Complete Pages
For a simple, yet very configurable way to cache, you can use the Zend_Cache component from the Zend Framework. This can be used on it's own without using the whole framework as described in this tutorial.
I saw somebody say use Sessions. This is not what you want as sessions are only available to the current user.
Here is an example using Zend_Cache:
include ‘library/Zend/Cache.php’;
// Unique cache tag
$cache_tag = "myFunction_Output";
// Lifetime set to 300 seconds = 5 minutes
$frontendOptions = array(
‘lifetime’ => 300,
‘automatic_serialization’ => true
);
$backendOptions = array(
‘cache_dir’ => ‘tmp/’
);
// Create cache object
$cache = Zend_Cache::factory(‘Core’, ‘File’, $frontendOptions, $backendOptions);
// Try to get data from cache
if(!($data = $cache->load($cache_tag)))
{
// Not found in cache, call function and save it
$data = myExpensiveFunction();
$cache->save($data, $cache_tag);
}
else
{
// Found data in cache, check it out
var_dump($data);
}
In a text file. Oldest way of saving stuff (almost). Or do a cronjob to run the script with the function each 5 minutes independently on the visits.
Use caching, such as APC!
If the resource is really big, this may not be the best option and a file may then indeed be better.
Look at:
apc_store
apc_fetch
Good luck!
Related
I have a function that generates a table with contents from the DB. Some cells have custom HTML which I'm reading in with file_get_contents through a templating system.
The small content is the same but this action is performed maybe 15 times (I have a limit of 15 table rows per page). So does file_get_contents cache if it sees that the content is the same?
file_get_contents() does not have caching mechanism. However, you can use write your own caching mechanism.
Here is a draft :
$cache_file = 'content.cache';
if(file_exists($cache_file)) {
if(time() - filemtime($cache_file) > 86400) {
// too old , re-fetch
$cache = file_get_contents('YOUR FILE SOURCE');
file_put_contents($cache_file, $cache);
} else {
// cache is still fresh
}
} else {
// no cache, create one
$cache = file_get_contents('YOUR FILE SOURCE');
file_put_contents($cache_file, $cache);
}
UPDATE the previous if case is incorrect, now rectified by comparing to current time. Thanks #Arrakeen.
Like #deceze says, generally the answer is no. However operating system level caches may cache recently used files to make for quicker access, but I wouldn't count on those being available. If you'd like to cache a file that is being read multiple times per request, consider using a static variable to act as a cache inside a wrapper function.
function my_file_read($filename) {
static $file_contents = array();
if (!isset($file_contents[$filename])) {
$file_contents[$filename] = file_get_contents($filename);
}
return $file_contents[$filename];
}
Calling my_file_read($filename) multiple times will only read the file from disk a single time, subsequent calls will read the value from the static variable within the function. Note that you shouldn't count on this approach for large files or ones used only once per page, since the memory used by the static variable will persist until the end of the request. Keeping the contents of files unnecessarily in static variables is a good way to make your script a memory hog.
The correct answer is yes. All the PHP file system functions do their own caching, and you can use the "realpath_cache_size = 0" directive in PHP.ini to disable the caching if you like. The default caching timeout is 120 seconds. This is separate from the caching typically done by browsers for all GET requests (the majority of Web accesses) unless the HTTP headers override it. Caching is not a good idea during development work, since your code may read in old data from a file whose contents you have changed.
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();
I have a simple problem. I use php as server part and have an html output. My site shows a status about an other server. So the flow is:
Browser user goes on www.example.com/status
Browser contacts www.example.com/status
PHP Server receives request and ask for stauts on www.statusserver.com/status
PHP Receives the data, transforms it in readable HTML output and send it back to the client
Browser user can see the status.
Now, I've created a singleton class in php which accesses the statusserver only 8 seconds. So it updates the status all 8 seconds. If a user requests for update inbetween, the server returns the locally (on www.example.com) stored status.
That's nice isn't it? But then I did an easy test and started 5 browser windows to see if it works. Here it comes, the php server created a singleton class for each request. So now 5 Clients requesting all 8 seconds the status on the statusserver. this means I have every 8 second 5 calls to the status server instead of one!
Isn't there a possibility to provide only one instance to all users within an apache server? That would be solve the problem in case 1000 users are connecting to www.example.com/status....
thx for any hints
=============================
EDIT:
I already use a caching on harddrive:
public function getFile($filename)
{
$diff = (time()-filemtime($filename));
//echo "diff:$diff<br/>";
if($diff>8){
//echo 'grösser 8<br/>';
self::updateFile($filename);
}
if (is_readable($filename)) {
try {
$returnValue = #ImageCreateFromPNG($filename);
if($returnValue == ''){
sleep(1);
return self::getFile($filename);
}else{
return $returnValue;
}
} catch (Exception $e){
sleep(1);
return self::getFile($filename);
}
} else {
sleep(1);
return self::getFile($filename);
}
}
this is the call in the singleton. I call for a file and save it on harddrive. but all the request call it at same time and start requesting the status server.
I think the only solution would be a standalone application which does an update every 8 seconds on the file... All request should just read the file and nomore able to update it.
This standalone could be a perl script or something similar...
Php requests are handled by different processes and each of them have a different state, there isn't any resident process like in other web development framework. You should handle that behavior directly in your class using for instance some caching.
The method which query the server status should have this logic
public function getStatus() {
if (!$status = $cache->load()) {
// cache miss
$status = // do your query here
$cache->save($status); // store the result in cache
}
return $status;
}
In this way only one request of X will fetch the real status. The X value depends on your cache configuration.
Some cache library you can use:
APC
Memcached
Zend_Cache which is just a wrapper for actual caching engines
Or you can store the result in plain text file and on every request check for the m_time of the file itself and rewrite it if more than xx seconds are passed.
Update
Your code is pretty strange, why all those sleep calls? Why a try/catch block when ImageCreateFromPNG does not throw?
You're asking a different question, since php is not an application server and cannot store state across processes your approach is correct. I suggest you to use APC (uses shared memory so it would be at least 10x faster than reading a file) to share status across different processes. With this approach your code could become
public function getFile($filename)
{
$latest_update = apc_fetch('latest_update');
if (false == $latest_update) {
// cache expired or first request
apc_store('latest_update', time(), 8); // 8 is the ttl in seconds
// fetch file here and save on local storage
self::updateFile($filename);
}
// here you can process the file
return $your_processed_file;
}
With this approach the code in the if part will be executed from two different processes only if a process is blocked just after the if line, which should not happen because is almost an atomic operation.
Furthermore if you want to ensure that you should use something like semaphores to handle that, but it would be an oversized solution for this kind of requirement.
Finally imho 8 seconds is a small interval, I'd use something bigger, at least 30 seconds, but this depends from your requirements.
As far as I know it is not possible in PHP. However, you surely can serialize and cache the object instance.
Check out http://php.net/manual/en/language.oop5.serialization.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.
server side is PHP + zend framework.
problem:
i have huge of data appox 5000 records and no of columns are 5 in input.txt file.
i like to read all data into memory only once and send some data to the every browser request.
but if i update that input.txt file then updated data must be auto synchronized to that
memory location.
so i need to solve that problem by using memory caching technique.but caching technique
has expire time.but if input.txt is updated before cache expire then i need to auto synchronize to that memory location.
now i am using zend framework 1.10.is it possible in zend framework.
can anybody give me some line of code of zendfrmawork
i have no option to use memchached server(distributed).
Only zend framwork.
It is possible to cache something like that using zend framework.
Check Zend documentation online - its not complete but can give you a head start:
http://framework.zend.com/manual/en/zend.cache.introduction.html
Use lazy loading like this (1h cache is usually OK).
function getData() {
$cache = ...; //get your memory cache here
$cacheId = 'MyCacheId'; //cache id for your data
$loadTimeCacheId = 'dataLoadCacheId'; //cache id for data load timestamp
$cacheLength = 3600; //seconds
$data = $cache->load($cacheId);
$loadTime = (int) $cache->load($loadTimeCacheId);
if (!$data || filemtime('/path/to/your/file') > $loadTime) {
$data = ...; //real loading here
$cache->save($data, $cacheId, array(/*no tags*/), $cacheLength); //save data to cache
$cache->save(time(), $loadTimeCacheId, array(/*no tags*/), $cacheLength); //save load timestamp
}
return $data;
}
Best option is to use Zend_Cache_Frontend_File pointed to your file and Zend_Cache_Backend_Memcached. There is virtually no other option how to store anything in memory than Memcache or APC. It cannot be done without external extension IMO.