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
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
We are using get_browser() in PHP using php_browscap.ini but performance is horrible. We pass 100 or so user-agents into get_browser() per page and it takes over 30 seconds to render the page. We need a performant solution, without storing the actual get_browser() results persistently (we only want to store user agents).
We already use memcached, is there a way we can alter get_browser() to cache results, or load the entire php_browscap.ini into memcached.
Ended up rolling our own solution:
////
// This function caches in memcached.
////
public static function get_browser_memcached($user_agent) {
if(empty(MemcacheConnection::$memcache_connection)) {
MemcacheConnection::connect();
}
$memcache_key = preg_replace('/\s+/', '', sha1($user_agent)) . "_user_agent";
$memcache_result = MemcacheConnection::get($memcache_key);
if($memcache_result !== false) {
return $memcache_result;
}
$browser = get_browser($user_agent);
//Store in Memcached (cached for 7 days)
MemcacheConnection::set($memcache_key, $browser, 604800);
return $browser;
}
I know I'm chiming in a little late, but for what it's worth, I'm using the browscap-php library (as mentioned by #AbcAeffchen) in one of my projects and I'm happy so far.
A typical lookup (from my own simple measurements) takes about 20~30ms on a 1 core 512MB cloud instance (which is pretty much the minimum you can find anywhere). I've opted to cache with Redis and this brings the lookup time down to just a couple of ms... so it's possible to optimize if you really need to.
The convenience alone makes it worth a try.
I havn't used the browscap-php library, but the the usage is highly recommend by the Browser Capabilities Project. http://browscap.org/
The libary on GitHub should improve the performance.
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.
From a tutorial I read on Sitepoint, I learned that I could load JS files through PHP (it was a comment, anyway). The code for this was in this form:
<script src="js.php?script1=jquery.js&scipt2=main.js" />
The purpose of using PHP was to reduce the number of HTTP requests for JS files. But from the markup above, it seems to me that there are still going to be the same number of requests as if I had written two tags for the JS files (I could be wrong, that's why I'm asking).
The question is how is the PHP code supposed to be written and what is/are the advantage(s) of this approach over the 'normal' method?
The original poster was presumably meaning that
<script src="js.php?script1=jquery.js&scipt2=main.js" />
Will cause less http requests than
<script src="jquery.js" />
<script src="main.js" />
That is because js.php will read all script names from GET parameters and then print it out to a single file. This means that there's only one roundtrip to the server to get all scripts.
js.php would probably be implemented like this:
<?php
$script1 = $_GET['script1'];
$script2 = $_GET['script2'];
echo file_get_contents($script1); // Load the content of jquery.js and print it to browser
echo file_get_contents($script2); // Load the content of main.js and print it to browser
Note that this may not be an optimal solution if there is a low number of scripts that is required. The main issue is that web browser does not load an infinitely number of scripts in parallel from the same domain.
You will need to implement caching to avoid loading and concatenating all your scripts on every request. Loading and combining all scripts on every request will eat very much CPU.
IMO, the best way to do this is to combine and minify all script files into a big one before deploying your website, and then reference that file. This way, the client just makes one roundtrip to the server, and the server does not have any extra load upon each request.
Please note that the PHP solution provided is by no means a good approach, it's just a simple demonstration of the procedure.
The main advantage of this approach is that there is only a single request between the browser and server.
Once the server receives the request, the PHP script combines the javascript files and spits the results out.
Building a PHP script that simply combines JS files is not at all difficult. You simply include the JS files and send the appropriate content-type header.
When it gets more difficult is based on whether or not you want to worry about caching.
I recommend you check out minify.
<script src="js.php?script1=jquery.js&scipt2=main.js" />
That's:
invalid (ampersands have to be encoded)
hard to expand (using script[]= would make PHP treat it as an array you can loop over)
not HTML compatible (always use <script></script>, never <script />)
The purpose of using PHP was to reduce the number of HTTP requests for JS files. But from the markup above, it seems to me that there are still going to be the same number of requests as if I had written two tags for the JS files (I could be wrong, that's why I'm asking).
You're wrong. The browser makes a single request. The server makes a single response. It just digs around in multiple files to construct it.
The question is how is the PHP code supposed to be written
The steps are listed in this answer
and what is/are the advantage(s) of this approach over the 'normal' method?
You get a single request and response, so you avoid the overhead of making multiple HTTP requests.
You lose the benefits of the generally sane cache control headers that servers send for static files, so you have to set up suitable headers in your script.
You can do this like this:
The concept is quite easy, but you may make it a bit more advanced
Step 1: merging the file
<?php
$scripts = $_GET['script'];
$contents = "";
foreach ($scripts as $script)
{
// validate the $script here to prevent inclusion of arbitrary files
$contents .= file_get_contents($pathto . "/" . $script);
}
// post processing here
// eg. jsmin, google closure, etc.
echo $contents();
?>
usage:
<script src="js.php?script[]=jquery.js&script[]=otherfile.js" type="text/javascript"></script>
Step 2: caching
<?php
function cacheScripts($scriptsArray,$outputdir)
{
$filename = sha1(join("-",$scripts) . ".js";
$path = $outputdir . "/" . $filename;
if (file_exists($path))
{
return $filename;
}
$contents = "";
foreach ($scripts as $script)
{
// validate the $script here to prevent inclusion of arbitrary files
$contents .= file_get_contents($pathto . "/" . $script);
}
// post processing here
// eg. jsmin, google closure, etc.
$filename = sha1(join("-",$scripts) . ".js";
file_write_contents( , $contents);
return $filename;
}
?>
<script src="/js/<?php echo cacheScripts(array('jquery.js', 'myscript.js'),"/path/to/js/dir"); ?>" type="text/javascript"></script>
This makes it a bit more advanced. Please note, this is semi-pseudo code to explain the concepts. In practice you will need to do more error checking and you need to do some cache invalidation.
To do this is a more managed and automated way, there's assetic (if you may use php 5.3):
https://github.com/kriswallsmith/assetic
(Which more or less does this, but much better)
Assetic
Documentation
https://github.com/kriswallsmith/assetic/blob/master/README.md
The workflow will be something along the lines of this:
use Assetic\Asset\AssetCollection;
use Assetic\Asset\FileAsset;
use Assetic\Asset\GlobAsset;
$js = new AssetCollection(array(
new GlobAsset('/path/to/js/*'),
new FileAsset('/path/to/another.js'),
));
// the code is merged when the asset is dumped
echo $js->dump();
There is a lot of support for many formats:
js
css
lot's of minifiers and optimizers (css,js, png, etc.)
Support for sass, http://sass-lang.com/
Explaining everything is a bit outside the scope of this question. But feel free to open a new question!
PHP will simply concatenate the two script files and sends only 1 script with the contents of both files, so you will only have 1 request to the server.
Using this method, there will still be the same number of disk IO requests as if you had not used the PHP method. However, in the case of a web application, disk IO on the server is never the bottle neck, the network is. What this allows you to do is reduce the overhead associated with requesting the file from the server over the network via HTTP. (Reduce the number of messages sent over the network.) The PHP script outputs the concatenation of all of the requested files so you get all of your scripts in one HTTP request operation rather than multiple.
Looking at the parameters it's passing to js.php it can load two javascript files (or any number for that matter) in one request. It would just look at its parameters (script1, script2, scriptN) and load them all in one go as opposed to loading them one by one with your normal script directive.
The PHP file could also do other things like minimizing before outputting. Although it's probably not a good idea to minimize every request on the fly.
The way the PHP code would be written is, it would look at the script parameters and just load the files from a given directory. However, it's important to note that you should check the file type and or location before loading. You don't want allow a people a backdoor where they can read all the files on your server.