I find the SqlCacheDependency very useful when writing C# ASP.NET applications, and would love to use something similar in my PHP applications. Can anyone suggest something?
SqlCacheDependency caches the page page output forever, until the specified table(s) are modified in the database.
Here's the basic jist of what happens in ASP.NET:
SqlCacheDependency SqlDep = null;
// Check the Cache for the SqlSource key.
// If it isn't there, create it with a dependency
// on a SQL Server table using the SqlCacheDependency class.
if (Cache["MyCache"] == null) {
SqlDep = new SqlCacheDependency("DatabaseName", "TableName");
// Perform action to be cached ...
var result = DatabaseIntensiveFunction();
Cache.Insert("MyCache", result, SqlDep);
}
else {
// The data was retrieved from the Cache.
}
// Output page from cache.
Output(Cache["MyCache"]);
So does anyone know of any MySql table dependency technique? - much cleaner than time-based caching.
Why not use something like Memcache or APC for this?
Edit: I also just found the MySQLnd Query Cache plugin for 5.3.3.
Related
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 have a fairly basic website, written in pure php, no framework was used, running in a basic LAMP environment.
The site dynamically generates markup based on the HTTP User Agent header, and some query string parameters. For example "itemdetail.php" would inspect the querystring param "itemid" and the User Agent header and produce some markup.
I want to cache this markup, so that the next time a device with the same User Agent and itemid in the query string tries to request the page, it simply dumps out whatever markup is in its cache.
I realise I could do this manually in php using memcache, and just write some code at the top of the page to inspect the relevant params, and either try serve from memcached or render the page and store the markup in memcached, but I was thinking it might be possible to avoid the PHP layer altogether, using something like what is described here http://httpd.apache.org/docs/2.2/caching.html
So, my question, which I realise might be vague and this post will get killed is:
What is the recommended caching implementation here? Is it indeed to use memcache at the php level, or are the apache modules sufficient to meet my needs?
Generating different pages depending on User Agents is just bad practice. You shouldn't do that.
If you want to cache entire pages because your website is slow, the problem probably has to be searched in your code.
On-topic: Write a simple function that hashes the uri being served with a small footprint hash function (md5, sha1,...)
e.g.
<?php
$hash = md5('itemdetail.php-'.$itemid);
if ( file_exist('cache/'.$hash.'.html') {
echo file_get_contents('cache/'.$hash.'.html');
die();
}
and then at the end of your script save the result to 'cache/'.$hash.'.html';
You can offcourse use different kind of extension or folder or...
If you want to cache without using PHP, take a look at Varnish. Or the other example posted here.
If you are familiar with OpenCart at all here is something I wrote to do just this. hopefully you will get the idea given the possible unfamiliar
context.
ob_start();
$enableCaching = false; // Boolean flag
$route = !isset($_GET['route']) ? 'home' : str_replace("/",'-',$_GET['route']);
$cacheFile = DIR_CACHE . $route . '.' . md5($_SERVER['QUERY_STRING']) . ".cache.tpl";
if ($enableCaching !== false && in_array($_GET['route'], $cachePages) && file_exists($cacheFile) ||
$enableCaching !== false && file_exists($cacheFile) && !isset($_GET['route'])) {
/**
* This block of code will output the contents of the cache file.
*/
require ($cacheFile);
}
else {
/**
* Cache file doesn't exist, process the request
*/
$response->output();
if($enableCaching !== false && in_array($_GET['route'], $cachePages) ||
$enableCaching !== false && !isset($_GET['route'])){
file_put_contents($cacheFile, str_replace(array("\n","\r","\t"),'', str_replace(" "," ",ob_get_contents())));
}
}
Basically, create a variable generating a unique file name based on the file name and quest string.
Create that file, writing all HTML output to that file.
Then when it comes to processing request you can check if the unique cache file exists and just send that instead of processing the request.
use the memcached library...
you'll have to install it first and then memcached provides and in-memory caching system for php
I have to read a file and do some computation, than save the result of this computation inside a variable.
I just need to do this once. In Java + Servlet I can do this using a servlet container and, for instance, the singleton pattern.
I know that in PHP I can't act like this. Which is the better way to do this? Save the computation (or transfer the data) on DB?
No, it won't work like with Java Servlets. You'll have to find a workaround.
First, I assume that using $_SESSION, $_COOKIE or $_REQUEST in general isn't practicable to you as you want to save the state per server (or per application) and not per 'User Session'.
Using a database sounds practicable in your case. In a regular application design it will be the most common solution.
Also you can do something like this, using the serialization capabilities of PHP:
<?php
$resultfile = 'result.dat';
if(!file_exists($resultfile)) {
$result = compute_result('foo bar');
file_put_contents($resultfile, serialize($result));
} else {
$result = unserialize(file_get_contents($resultfile));
}
Using PHP's serialize() attempt is especially practicable when
You are in a PHP only environment
$result is a complex datatype but you don't want to create a database structure and map $result too it
If you are not in a PHP only environment you might prefer other serialization formats as JSON or XML.
Also the serialization result can be stored as a string in a database instead of a file. Saving it to a database instead of a file would make the application more scalable as the result would be available to all servers that access the same database (cluster).
In short: I would suggest using a database maybe combined with serialization.
I need to know if I can improve the way I cache my api calls from the inside of my CodeIgniter app.The way I do it right now is like this, in a hmvc pattern:
Controller HOME == calls to => module app/application/modules/apis/controllers/c_$api == loads library => app/application/libraries/$api ==> Library returns response to module's controller_X, the controller invokes the view with the data it has
//Note: My app does not use twitter api, but others
Inside the apis module is where the all the apc caching is happening, like so:
// Load up drivers
$this->load->library('driver');
$this->load->driver('cache', array('adapter' => 'apc'));
// Get Tweets from Cache
$tweets = $this->cache->get('my_tweets');
if ( ! $tweets)
{
// No tweets in the cache, so get new ones.
$url = 'http://api.twitter.com/1/statuses/user_timeline.json?screen_name=gaker&count=5';
$tweets = json_decode(file_get_contents($url));
$this->cache->save('my_tweets',$tweets, 300);
}
return $tweets;
as explained in this article: http://www.gregaker.net/2011/feb/12/codeigniter-reactors-caching-drivers/
So I was wondering:
Having 3 scenarios: home, query, result; in each module apis's controller, do you think it would be a good idea to implement cache for each controller with all the scenarios? example:
//for each api1, api2 ... apiX, apply this:
//home
$this->cache->save('api_home',$api_home, 300);
//query
$this->cache->save("api_$query", $api_{$query}, 300); // I don't know for sure if $api_{$query} works or not, so don't hang me because I haven't tried it.
//result
$this->cache->save("api_$queryId", $api_{$queryId}, 300);
Even though I cached the api call, do you think I should cache the result in the controller that is calling the api module controller, with the same 3 scenarios (home, query and result)? Like so:
//modules/{home,fetch,article}/controllers/{home,fetch,article}.php
//home
$homeData['latest'][$api] = modules::run("apis/c_$api/data", array('action'=>'topRated'));
$this->cache->save('home_data', $home_data, 300);
//query
$searchResults[$api] = modules::run("apis/c_$api/data", $parameters);
$this->cache->save("search_results_$query", $search_results_{$query}, 300);
//article page
$result = modules::run("apis/c_$api/data", $parameters);
$this->cache->save("$api_article_$id", ${$api}_article_{$id}, 300);
So, what do you think? Is it a good practice the mentioned above, or just an awful stupid one?
//Note, the suggested caching ideas were not tested... so, I don't know if ${$api}_article_{$id} will work or not (even though I suppose it will)
IMHO It is a good idea to cache api results if you don't need real time data. If you don't care that you won't see new data for an hour, then by all means cache it for an hour. So for your first question, you just need to ask yourself: "How fresh does the content need to be for my application?" and implement caching accordingly.
For the second question: I don't see a lot of value in caching content if it's only been manipulated in simple ways. At that point you're using up space in your cache and not getting a lot of value. But if there are database, or other api calls being made using that data, then yes they should be cached using a technique similar to the above.
If you're that worried about processor load (the only reason to cache content after manipulation) you're best bet is to look at something like Varnish or CloudFront.
My Google-fu hasn't revealed what I'm looking for, so I'm putting this one out to the crowd.
Coming from an ASP.NET development background, I'm used to having the Application and Cache collections available for me to stash rarely-modified but often-used resources (such as lookup rows from a database or the contents of static XML documents) in the memory of the web server, so I don't have to reload these often-used items during every request.
Does PHP have an equivalent? I've read up briefly on the memcache extension, but this won't work for me (as I don't have control over the server configuration.) I'm tempted to implement something that would allow me to pre-parse or pre-select the resources and generate a sort of PHP cache "file" that would construct the cached object from literals stored in the file, but this seems like a very hacky solution to me.
Is there something in PHP (or, alternatively, a helper library of some sort) that will allow me to accomplish this using best practices?
In short, no, such a thing is not available natively in PHP. To understand why, you have to understand that PHP has its entire environment built for each request, and it is subsequently torn down at the end of the request. PHP does give you $_SESSION to store per session variables, but after digging into the docs you will see that that variable is built during each request also. PHP (or mod php to be more specific) is fundamentally different from other "application servers". Basically, it is not an application server. It is a per request script runner.
Now, don't get me wrong, PHP lets you do application level data store, but you will have to go to a database, or to disk to get it. Remember this though, don't worry about optimizing for performance until it is shown that preformance is a problem. And I will guess that 99 times out of 100, by the time performance is an issue that isn't due to some poor code you wrote, you will have the resources to build your own pretty little memcached server.
Take a look at Zend_Cache library, for example. It can cache in multiple backends.
This is a bit of a hack but but works in php 7+
Basically you cache your data to a temp file and then use include to read the file, which is cached in memory by the php engine’s in-memory file caching (opcache)
function cache_set($key, $val) {
$val = var_export($val, true);
// HHVM fails at __set_state, so just use object cast for now
$val = str_replace('stdClass::__set_state', '(object)', $val);
// Write to temp file first to ensure atomicity
$tmp = "/tmp/$key." . uniqid('', true) . '.tmp';
file_put_contents($tmp, '<?php $val = ' . $val . ';', LOCK_EX);
rename($tmp, "/tmp/$key");
}
And here’s how we “get” a value from the cache:
function cache_get($key) {
#include "/tmp/$key";
return isset($val) ? $val : false;
}
from https://medium.com/#dylanwenzlau/500x-faster-caching-than-redis-memcache-apc-in-php-hhvm-dcd26e8447ad