Php caching pages with ads. PHP and Web


To optimize the work with the network, a mechanism is used to save documents once received via HTTP in the cache in order to reuse without contacting the origin server. The document stored in the cache will be available the next time it is accessed, without being unloaded from the source server, which is designed to increase the speed of client access to it and reduce network traffic consumption.

There are two types of caches - local and shared. Local is a cache stored directly on the client's disk, created and managed by its browser. General - An organization's or provider's proxy cache and may consist of one or more proxy servers. The local cache is present, probably in every browser, a significant part of the people using the Internet use the shared ones. And if a small part of sites are now evaluated by traffic consumption, then download speed is an important criterion that should be taken into account when developing your web project.

For dynamic pages created as a result of running a PHP program, it would seem that caching is harmful. The content of the page is formed at the request of the user based on some data source. However, caching can be useful. By managing it, you can make working with your server more comfortable for the user by allowing certain pages to be loaded from the cache, thereby preventing them from being re-uploaded from your server and saving the user time and traffic.

Cache or not?

The ability to cache a page is determined by the dynamic nature of the information in the data source. Thus, the need to use the cache is determined by you, based on the planned lifetime of the page.

If we are talking about the formation of a selection in the database (for example, searching for a word entered by the user), then such a page must be requested from the server at each call without using the cache, since the number of options for the requested words is huge, and if we are also dealing with a changing array of data, then caching is meaningless. Or we are talking about the formation of an acceptable schedule of incoming visitors (which changes with each visit, that is, with almost every call), then caching is simply harmful.

However, if we are talking about the same chart but for yesterday, then caching is recommended, since the data will not change anymore and we can save resources and time for ourselves and the user to load such pages by placing them in a local or shared cache. As a continuation of this situation, the formation of the graph is not in real time, but hourly. Here you can predict in advance the expiration date of the "shelf life" of the generated data.

General principles for saving pages to the cache

A PHP program can control the caching of the results of its work by providing additional fields in the HTTP response header by calling the Header() function.

A few general statements that are not specific to PHP programs:

  • Pages submitted via POST are never cached.
  • Pages requested by GET and containing parameters (there is a "?" in the URL) are not cached unless otherwise specified.

Thus, in most situations, additional instructions do not need to be added to the program. The main points to pay attention to can be summarized in two:

  • disable caching of documents that are cached by default
  • caching of documents not subject to caching by default.

Disable caching of documents that are cached by default

This problem arises for PHP scripts that are called without parameters or are indexes of directories, but generate data personally for the user (for example, based on cookies or user agent) or work on the basis of rapidly changing data. According to the HTTP/1.1 specification, we can manage the following fields:

  • Expires- Sets the expiration date for the document. Setting it in the past determines whether the cache is disabled for this page.
  • Cache-control: no-cache- Cache management. The no-cache value specifies that this page is not cached. For protocol version HTTP/1.0, "Pragma: no-cache" applies.
  • Last Modified- The date the content was last modified. The field is relevant only for static pages. Apache replaces this field with the value of the Date field for dynamically generated pages, including pages containing SSI.

The www.php.net website provides the following code to disable caching.

Header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 header("Pragma: no-cache"); // HTTP/1.0

However, I think this title is redundant. In most cases it is enough:

To mark a document as "out of date" set Expires to the Date field.

Header("Expires: " . gmdate("D, d M Y H:i:s") . " GMT");

Well, we should not forget that the forms requested by POST are also not subject to caching.

Caching documents that are not cacheable by default

The reverse problem may seem absurd at first glance. However, there is a need for this as well. In addition to the simple minimization of traffic, when developing a web program, one should take into account the comfort of the user's work with it. For example, some pages of your server are formed on the basis of static data of a large volume. The ability to include them in the cache will significantly improve the speed of the server for the user and partially free yours from numerous repeated generations of such a page. Header allowing saving on proxy servers:

header("cache-control: public");

If the page takes into account information stored in the user's browser (browser type and version, keys, authorization, etc.), such a page cannot be saved on the proxy, but it can be saved in the browser's local cache:

Header("Cache-control: private");

Caching until validity expires

The solutions described above are fairly straightforward, although they are suitable for most tasks. But HTTP protocol/1.1 has more fine-grained control over the page cache, and there are applications that require these mechanisms. As an example - web-applications working with data of large volume and predictable dynamism. The correctness of the data can be established both by the date of the predicted update, and by the change in content. For these cases, different cache control headers are used.

Predictive refresh caching

Consider an example - a price list updated on Mondays. You know in advance that the content of the page can be stored in the cache until the new week, which should be indicated in the response header ensuring the desired behavior of the page in the cache.

The main task is to get the date of the next Monday in RFC-1123 format

$dt_tmp=getdate(date("U")); header("Expires: " . gmdate("D, d M Y H:i:s", date("U")-(86400*($dt_tmp["wday"]-8))) . " GMT"); header("Cache control: public");

This method can effectively control the behavior of the page in the cache and is applicable for a large number pages - one way or another, you can select time intervals during which the content of the page remains constant. Real position things is that the pages of most dynamic sites have certain time life based on which the developer can seraer more enjoyable to work with.

Another approach, used when updating information more quickly and at the same time high server traffic (otherwise caching will not be effective) is to use the Cache-control: max-age=seconds header, which determines the time after which the document is considered outdated and has a higher priority in the calculation " freshness" of the document.

If you publish news with an interval of 30 minutes:

header("cache-control: public");
header("Cache-control: max-age=1800");

Content caching

Content-based HTTP/1.1 provides an even smarter view of control through the use of Vary directives. I highly recommend using it when forming large images or texts, which, as practice shows, change extremely rarely. At the same time, in case of a return, the user will not re-upload them if the content remains the same, and the page will be taken from your server if its content has changed.

Consider an example of issuing an image from a database identified by ID. The page call looks like this:

http://www.your.server/viewpic.php3?id=23123

which means that according to the rules, the page will not be saved to the cache (there are parameters), but you can control this through the header.

mysql_connect("host", "user", "passwd"); $image=mysql("db", "select pics,type from pictures where id=$id"); Header("Cache-Control: public, must-revalidate"); Header("Vary: ContentID"); Header("Content-ID: ".md5(mysql_result($image, 0, "pics"))); Header("Content-type: ".mysql_result($image, 0, "type")); echo mysql_result($image, 0, "pics"); mysql_freeResult($image); mysql_close();

The MD5 sum of the content of the image is used for control. As long as the content has not changed, the amount will be constant. If the content in the database on the server changes, the client will execute a request to regenerate the content. As long as the image is persistent, the content will be rendered from the cache.

Notes for Russian Apache

And a nice (or unpleasant) message for Russian Apache users. Since the server renders old-fashioned according to the user's encoding, it automatically supplies ALL pages (not just dynamic ones) with caching prohibition headers.

Intermediate data caching is the most primitive and at the same time the most useful way optimizations where you don't have to mess around with any complex algorithms or pre-optimization. If you're going to work with PHP, then you need to be aware of the tried and true methods and tools needed to get your site up and running.

Static local variables

Fast and effective way caching the results of a function/method is to use static local variables. Consider an example that performs complex calculations:

Now, each time the function is used in code, regardless of the number of calls, the function will only perform calculations once.

This caching technique is independent of external extensions and is supported at the language level. Since static local variables are only accessible within the function in which they are defined, updating the cache can be problematic. Typically, this requires passing some boolean $use_cache variable or using static class variables instead.

Static variables are not shared between PHP processes and can only be cached for a short time - spanning the execution time of the script. A good candidate is a method that is called many times from multiple places, such as storing user state or a result that requires a lot of math.

The same functionality can be implemented using global variables, but this will pollute the global namespace and is therefore not recommended.

APC shared memory functions

PHP is a semi-compiled language, which means that each script is compiled not directly into machine code, but into an intermediate code known as an opcode set (bytecode). This compilation step is CPU intensive and must be performed each time the script is executed. APC (Alternative PHP Cache) is an extension that skips this compilation step by caching opcodes in memory.

While APC's main purpose is generally considered to be opcode caching functionality, the extension also includes some additional functions memory access.

Now the advantage of this approach is obvious - it is the use of shared memory. This type of memory is shared across processes/threads and, unlike static variables, data cached in this manner will exist across multiple requests.

To invalidate a cache, you can use lifetime (TTL) values, as in the example above, or the following functions:

Other notes on shared memory support in APC:

There is a directive in the INI configuration file to limit the size of the cache. With appropriate TTL values, this makes it possible to prioritize cached data where, if the memory limit is reached, expired/old values ​​will be expelled from the cache.

From a performance point of view, static variables will always be faster than the apc_fetch/apc_store functions, since access to shared memory must be locked and synchronized to prevent collisions.

APC is a fairly popular extension, and is supported by the main PHP developers and will (very likely) ship with PHP 5.4.

Memcached for large distributed caches

Once a site starts getting a lot of hits, it eventually becomes a task of distributing the load across different machines. As a result, it is usually necessary to move PHP to multiple application servers. If you have used APC caching before - each application server now has a separate and redundant cache.

Memcached on the other hand is a distributed service for storing key-value data. The extension can be deployed on a separate dedicated server or in the same PHP application stack. It is important to understand that there is no synchronization/replication between multiple Memcached servers, and they don't know anything about each other at all. The actual server to be used for storage is selected on the client side with a hashing algorithm based on the "key" data provided. That is why, unlike APC, cached data is not duplicated between different machines, and memory is better used for large distributed applications.

The API is very similar to the shared memory functionality in APC. The same currency exchange example implemented with PHP extensions memcache:

connect("..."); function getCurrencyRates() ( global $memcache; $rates = $memcache->get("rates"); if ($rates === false) ( // Query database or external API functions $rates = ...; // The exchange rate will be cached for 1 hour $memcache->set("rates", $rates, 0, 3600); ) return $rates; ) ?>

Refreshing the cache is the same as in APC - using TTL functionality or a set of functions.

delete("rates"); // Flush cache $rates $memcache->flush(); // Delete all cached data?>

The local APC cache will always be over fast method compared to Memcached.

There are always delays in the network when the client needs to communicate with the back-end service via a dedicated text protocol.

Database tables in RAM

While not specific to PHP, many database management systems have in-memory implementations of tables. The data stored in such tables is not persisted across server restarts, is guaranteed to be kept in memory, and is never paged out to disk. This means faster access to records, making them suitable for data caching.

MySQL provides in-memory tables in the MEMORY storage subsystem. Although the data will be cleared after a server restart, the table schemas will be preserved:

CREATE TABLE test (...) ENGINE = MEMORY

AT PostgreSQL there are temporary tables that exist only during the session, in order to cache data in a temporary table, you must maintain a permanent connection to the database.

CREATE TEMPORARY TABLE test (...)

AT SQLite it is possible to create an entire database in memory, but with the same limitations as in PostgreSQL - the data will only exist for the duration of the session, and you will need to use persistent connections to maintain them between multiple requests.

true)); ?>

So what can be done with a table in RAM? Although such a table will never be faster access to key-value data in APC/Memcached, you get the power of SQL. Cached data can be filtered, ordered, grouped, and even combined with other data in tables.

Simple file cache

The flat file cache should be an alternative to the methods mentioned above and should only be used when the system does not have the necessary extensions or data that in question, cannot be stored in memory (e.g. due to size)

Because caching is done to improve performance, and performance optimization is a result of high concurrency - file locking should always be used to prevent read/write race conditions:


caching in PHP

In the good old days, when creating websites was as simple as typing a few HTML pages together, sending web pages to a browser was a simple matter of sending a file by a web server. Visitors to the site could see these small, all-text pages almost instantly (except for slow modem users). Once the page has been loaded, the browser caches it somewhere on local computer so that if the page is requested again, you can take it local version from the cache, sending only a short request to make sure that the page on the server has not been changed. Requests were processed quickly and most efficiently, and everyone was happy (except those using 9600 baud modems).

The advent of dynamic web pages has changed things for the worse, effectively breaking this web page serving model due to the presence of two problems:

1. When a request for a dynamic web page is received by the server, some intermediate processing is performed, for example, parsing (parsing) of the script by the PHP engine, which must be completed. This gives us a delay before the web server starts sending output to the browser. For simple PHP script it's not essential, but in the case of a more complex application, the PHP engine can do a lot of things before the page is ready to be submitted. These additional actions lead to a noticeable delay between user requests and the actual display of pages in their browsers.

2. A typical web server, such as Apache, uses the modification time of a file to correctly tell the browser the cache state of the requested page. In dynamic websites, the PHP script itself may change only occasionally, while the content it renders, possibly residing in a database, changes frequently. The web server has no way to know about database changes, so it doesn't send the last modification date. If the client (browser) does not get any indication of how long the data has been valid, it assumes that the next time it needs to request a new page. The web server will always respond updated version pages, regardless of whether the data has changed. To avoid this shortcoming, most web developers use meta tags or HTTP headers to tell the browser never to use the cached version of the page. However, this negates the web browser's natural ability to cache web pages and has some significant shortcomings. For example, the content of a dynamic page can change once a day, so the benefit of having even 24-hour browser caching of the page is obvious.

Usually, for small PHP applications, it's okay to ignore the existence of these issues, but as your site's complexity and traffic increases, you may run into problems. However, both of these problems can be solved: the first is by server-side caching, the second is by controlling client-side caching from your application. The approach you take will depend on your specific needs, but in this article we'll show you how you can solve both problems using PHP and some classes in the PEAR library.

how do i prevent browsers from caching the page?

Before we look at client and server caching techniques, we first need to understand how to prevent web browser (and proxy servers) from caching pages at all. The main way to achieve this is using HTML meta tags:

By inserting a past date in the Expires meta tag, you tell the browser that the cached copy of the page is always out of date. This means that the browser should never cache a page. The Pragma: no-cache meta tag is a fairly well-supported convention that most web browsers follow. Once they find this tag, they usually don't cache the page (though there are no guarantees, it's just a convention). This sounds good, but there are two problems with using meta tags:

1. If the tag did not exist when the page was first requested by the browser, but appears later (for example, you modified the pageheader.php include file, which is the header of every web page), the browser will remain blissfully unaware and use its cached copy of the original.

2. Proxy servers that cache web pages will not inspect the content of an HTML document directly at all. Instead, they rely only on the web server that the documents came from and the HTTP protocol. In other words, the browser may think it shouldn't cache the page, but the proxy between the browser and the web server probably doesn't know this - and will continue to send the same page to the client.

The best approach is to use the HTTP protocol directly with PHP functions header:


header("Pragma: no cache");
?>

We can go one step further by using the Cache-Control header, which is compatible with browsers that support HTTP 1.1:

header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", FALSE);
header("Pragma: no cache");
?>

This ensures that no web browser or intermediate proxy will cache the page, so visitors will always get the best latest version content. In fact, the first header should be self sufficient, it is The best way ensure that the page is not cached. The Cache-Control and Pragma headers are added as a safety net. Although they do not work in all browsers or proxies, they will catch some cases in which Expires does not work properly (for example, if the date on the client computer is not set correctly). Of course, completely eliminating caching introduces the problems we discussed at the beginning of this chapter. Now we will consider the solution to these problems.

Internet Explorer and file download caching

Problems can arise when you deal with caching and downloading files. If a PHP script uses headers such as Content-Disposition: attachment, filename=myFile.pdf or Content-Disposition: inline, filename=myFile.pdf when serving a file upload, you will have problems with Internet Explorer if you tell the browser not to cache the page.

Internet Explorer handles downloads in a rather unusual way, making two requests to a website. The first request downloads the file and stores it in the cache until the second request is made (without saving the response). This request invokes the process of transferring the file to the end user according to the file type (for example, starts Acrobat Reader if the file is a PDF document). This means that if you send headers that prevent the browser from caching the page, Internet Explorer will delete the file between the first and second request, resulting in nothing for the end user. If the file you're serving as a PHP script doesn't change, one of the simplest solutions is to remove the caching-disable headers from the script.

If the file being downloaded changes regularly (i.e. you want the browser to download the newest version), you should use Last-Modified header and ensure that the modification time between two consecutive requests does not change. You must do this in a way that does not affect users of browsers that handle downloads correctly. One solution in this case would be to store the file on your web server and provide a simple link to it, leaving the web server to report the caching headers for you. Of course, this solution may not be acceptable if authorized access to the file is supposed, since it allows direct download saved file.

how can i grab server side data for caching?

It's time to take a look at how we can reduce latency with server-side output caching. So, you can provide the page as you normally would by doing database queries and so on in PHP. But before sending the result to the browser, we capture it and save the finished page, for example, in a file. On the next request, the PHP script first checks for a cached version of the page. If it exists, the script sends the cached version to the browser, thus eliminating the delay for re-creation pages.

A few words about caching with templates. The presence of template engines like Smarty often speaks of template caching. Typically, these engines offer a built-in mechanism for saving a compiled version of the template (that is, generating a PHP source from the template), which prevents us from having to parse the template every time a page is requested. This is not to be confused with output caching, which is about caching the provided HTML (or other output) that PHP sends to the browser. You can successfully use both types of caching at the same time on the same site.

Now we'll take a look at PHP's built-in caching mechanism using output buffering, which you can use regardless of how you create your content (with or without templates). Consider a situation in which your script displays the result, using, for example, echo or print to output data directly to the browser. In such a case, you can use PHP's output control functions to store data in a buffer over which your PHP script has control.
Here is a simple example:


ob_start();
// Output some text (which is stored in the buffer);
echo "1. Output this to the buffer
";
// Get the contents of the buffer
$buffer = ob_get_contents();
// Stop buffering and clear the output buffer
ob_end_clean();
// Output some text normally
echo "2. Normal output
";
// Output the contents of the buffer
echo $buffer;
?>

The buffer itself stores the output as a string. So, in the above script, we start buffering at ob_start and use echo to output something. We then use ob_get_contents to fetch the data buffered by the echo statement and store it in a string. The ob_end_clean function stops output buffering and destroys its contents. Alternatively, ob_end_flush can be used to dump the contents of the buffer. The above script will output:

2. Normal output
1. Output it to the buffer

In other words, we captured the output of the first echo, then sent it to the browser after the second echo. As can be seen from this a simple example, output buffering is a very powerful tool for shaping your site, it provides a caching solution, as we will see shortly, and is great way hide errors from your website visitors. It also provides an alternative option for browser redirects in situations such as user authentication.

HTTP headers and output buffering

Output buffering can help solve the most common problem associated with the header function, not to mention session_start and set_cookie. Usually, if you call any of these functions after page rendering has started, you'll get a nasty error message. With output buffering enabled, the only type of output that avoids buffering is HTTP headers. By using ob_start at the very beginning of your application's execution, you can send headers at any point in the program you like without running into the usual errors. Then, once you're sure you don't need to print any more HTTP headers, you can immediately dump the page's content from the buffer.

/* It should be noted that such use of this function is unjustified. In most cases, there is simply no need to use output buffering to get rid of errors of this type and everything can be easily fixed by proper application design - approx. translator */

using output buffering for server side caching

You have already seen a basic example of output buffering, now the next step is to save the buffer to a file:

// If a cached version exists...
if (file_exists("./cache/2.cache")) (
// Read and output file
readfile("./cache/2.cache");
exit();
}
// Start buffering output
ob_start();
// Output the rest of the HTML
?>
>http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
>http://www.w3.org/1999/xhtml">

Cached Page

This page is cached by PHP
Functions>http://www.php.net/outcontrol">Output Control Functions

// Get the contents of the buffer
$buffer = ob_get_contents();
// Stop buffering and output buffer
ob_end_flush();
// Save cache file with content
$fp = fopen("./cache/2.cache", "w");
fwrite($fp, $buffer);
fclose($fp);
?>

This script first checks to see if the page version is in the cache, and if it is, the script reads and prints it out. Otherwise, it uses output buffering to create a cached version of the page. After using ob_end_flush to display a page to the user, it is saved as a file.

block buffering

In a simplistic approach, we cache the output buffer as a single page. However, this approach takes away the real power provided by PHP's output control functions.
Undoubtedly, some parts of the page sent to the visitor change very rarely, such as the header, menu, and footer. However, other parts, such as tables containing forum discussions, may change quite often. Output buffering can be used to cache sections of a page in separate files, then build a page out of them - a solution that eliminates the need for repeated database queries, while loops etc. You can give each page block an expiration date after which the cache file is recreated, or you can also include a mechanism in your application that will delete the cache file every time the content stored in it changes.
Here is an example demonstrating this principle:

/
* Write cache file
* @param string contents - buffer contents
* @param string filename is the filename used when creating the cache file
* @return void
*/
function writeCache($content, $filename) (
$fp = fopen("./cache/" . $filename, "w");
fwrite($fp, $content);
fclose($fp);
}
* Check cache files
* @param string filename – name of the cache file to be checked
* @param int expiry - the maximum "age" of the file in seconds
* @return mixed cache content or false
*/
function readCache($filename, $expiry) (
if (file_exists("./cache/". $filename)) (
if ((time() - $expiry) >filemtime("./cache/" . $filename))
return FALSE;
$cache = file("./cache/" . $filename);
return implode("", $cache);
}
return FALSE;
}
?>

The first two functions we defined, writeCache and readCache, are used respectively to create cache files and check for their existence. The writeCache function takes as arguments the data to be cached and the filename used to create the cache file. The readCache function gets the name of the cache file and the time in seconds after which the cache file should be considered stale. If it finds the cache file valid, the script will return its contents, otherwise it will return FALSE to indicate that the cache file either does not exist or is out of date.

In this example, I used a procedural approach. However, I don't recommend doing this in practice, as it will end up in very messy code (see later solutions with the best alternative) and will likely cause file locking issues (eg, what happens when someone accesses the cache while it is being updated?).
Let's continue this example. After output buffering is started, processing begins. First, the script calls readCache to see if the file 3_header.cache exists - it contains the page header, that is, the HTML header and the beginning of the body. We're using the date function to print out the time the page was actually generated, so you'll see the various cache files in action when the page is rendered.

// Start buffering output
ob_start();
// Handling the header
if (!$header = readCache("3_header.cache", 604800)) (
// Display header
?>
>http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
>http://www.w3.org/1999/xhtml">

Block cached page

Hat time:

$header = ob_get_contents();
ob_clean();
writeCache($header,"3_header.cache");
}
?>

What happens when the cache file is not found? Some content is output and assigned to a variable using ob_get_contents, after which the buffer is cleared with ob_clean. This allows us to capture the output in chunks and match them against individual cache files using writeCache. The page title is now stored as a file that can be used without our having to rebuild the page. Let's go back for a second to the beginning of the conditional statement. When we called readCache, we passed it a cache lifetime of 604800 seconds (one week), readCache uses the cache file's modification time to determine if the cache file is still valid.

For the content (body) of the page, we will still use the same process. However, this time when we call readCache we will use a cache lifetime of five seconds, the cache file will be updated every time it is "older" than 5 seconds:

// Processing the page body
if (!$body = readCache("3_body.cache", 5)) (
echo "Body creation time: " . date("H:i:s") . "
";
$body = ob_get_contents();
ob_clean();
writeCache($body, "3_body.cache");
}
?>

The footer effectively changes in the same way as the header.
The end result looks something like this:
- cap creation time - 17:10:42;
- body creation time - 18:07:40;
- footer creation time - 17:10:42.
The header and footer are updated weekly, while the body is updated when it's older than 5 seconds.

nested buffers

You can nest one buffer within another virtually indefinitely by simply calling ob_start repeatedly. This can be useful if you have a lot of operations that use the output buffer, for example some catch PHP error messages, others deal with caching. You must make sure that ob_end_flush or ob_end_clean is called each time ob_start is used.

How do I implement a simple server side caching system?
Now that we understand the ideas behind output buffering, it's time to look at how we can use this process in action in a way that is easy to maintain. To do this, we'll use a little help from PEAR::CacheLite.

As I said, in the interests of ease of code maintenance and a reliable caching mechanism, it's wise to leave the responsibility for the cache logic to classes that you trust. Cache_Lite is a powerful yet easy-to-use caching library that handles tasks such as temporarily locking cache files, creating and validating them, managing the output buffer, and directly caching the result of a function or class method. The main reason for choosing this library is the relatively simple integration of Cache_Lite into the already existing application which requires only minor changes to the code.

Cache_Lite consists of three main classes. The first is the Cache_Lite base class, which is only responsible for creating and reading cache files and does not buffer output. This class can be used alone in cases where there is no need to use output buffering, such as when saving the result of template parsing by a PHP script. The examples given here do not use the Cache_Lite class directly and demonstrate the use of the other two classes. Cache_Lite_Function is used to call a function or class method and then cache the results of the work. This can be useful, for example, for caching the result of a MySQL query. The Cache_Lite_Output class uses PHP's output control functions to capture the data generated by the script and store it in cache files. This allows you to perform the same tasks as the previous solution.

Cache_Lite settings

In the current version of the class (1.1), the following settings are available:
- cacheDir - directory where cache files will be placed. The default value is the directory where the script is executed;
- caching - this option enables or disables Cache_Lite features. For example, if you have a lot of requests to Cache_Lite, and during debugging you want to turn off caching, set to FALSE. The default value is TRUE.
lifetime - the parameter contains the default cache lifetime (in seconds);
- fileNameProtection - use MD5 encoding to generate the cache file name. This allows you to use any characters in the names of cache files and groups, even those prohibited by the file system;
- fileLocking - enables mechanisms for blocking a file with a cache while writing data to it;
- writeControl - checks that the cache file was written correctly immediately after the end of the write;
- readControl - before reading the file with the cache checks it for distortion;
- readControlType - this parameter defines the type of mechanism for reading cache files. Mechanisms available: loop redundancy check, MD5 hash, or simple check long. Note that this mechanism is not intended to protect cache files from being called directly. outside users. It's just a way to tell if a file is corrupted or not;
- pearErrorMode - enables PEAR error return method;
- memoryCaching - every time you call a cache write to a file, it is written to the Cache_Lite array. saveMemoryCachingState and
getMemoryCachingState are used to access the cache stored in memory between requests. Advantage similar method is that the contents of the cache can be stored in a single file, which reduces the number of read / write cycles to disk. The cache is restored directly to an array that your script has access to;
memoryCachingLimit - This parameter specifies the limit on the number of cache files that can be stored in the memory array.

clearing the cache

Cahce_Lite contains a clever mechanism for determining the lifetime of cache files, which creates a good basis for the safety of your files and their timely updates. However, there are times when you need to update the cache file immediately. For such cases, there are remove() and clean() methods. The remove() method is designed to remove a particular cache file. it needs the cache ID and the name of the group that the file belongs to. Next example will delete the body cache file from the previous example:

$cache->remove("body", "Dynamic");

The clean() method allows us to delete all files in our directory if we call it with no parameters. If you pass the name of a group as a parameter, then all files included in this group will be deleted. If we wanted to remove the header and bottom, then we need to issue commands similar to this:

$cache->clean("Static");

The remove() and clean() methods obviously need to be called in response to events within the application. For example, if you have a forum, you should definitely delete the cache file if any user posts a new message. Although this solution looks nice, it may involve code changes. If you have a main script that hooks into every page of the application that a visitor can view, you can simply watch for incoming events, such as the $_GET["newPost"] variable, and delete the required cache files. This will allow you to create a centralized cache management mechanism. You could even include this code in php.ini.

function call caching

Because web services are available over the network, it's often a good idea to cache the result so that it can be executed locally rather than repeating the same slow request over and over again. In the simplest case, we could use PHP sessions, but since this solution is based on visitor regularity, opening a request for each visitor would still be slow. In such cases, Cache_Lite can be very handy.

The PEAR Web installer uses Cache_Lite to cache the XML-RPC requests sent to the PEAR Web server.
Here is the code that receives data from the remote server:

$countries = $stationInfo->listCountries();

$country = $stationInfo->searchByCountry($_GET["country"]);

In both cases, these calls correspond to a request for data over the network. Using Cache_Lite, we could cache the data returned by the service and could reuse it. This would avoid additional unnecessary network connections and greatly increase the execution speed. Please note that we are only looking at code related to our theme here. At the beginning we include Cache_Lite_Function:

// Include PEAR::Cache_Lite_Function
require_once "Cache/Lite/Function.php";

// Set parameters for for Cache_Lite_Function
// WARNING: fileNameProtection = TRUE!
$options = array(
"cacheDir" =>"./cache/",
"fileNameProtection" =>TRUE,
"writeControl" => TRUE,
"readControl" => TRUE,
"readControlType" =>"strlen",
"defaultGroup" =>"SOAP"
);
// Create an object of class Cache_Lite_Function
$cache = new Cache_Lite_Function($options);

It is important that the fileNameProtection parameter is set to TRUE. This value is accepted by default, however, I deliberately set it manually to emphasize significance. Setting this parameter to FALSE will result in an invalid filename, so no caching will occur.
Next, we make a request to our SOAP client:

$countries = $cache->call("stationInfo->listCountries");
$country = $cache->call("stationInfo->searchByCountry",
$_GET["country"]);

When a request is made for the first time, Cache_Lite_Function stores the results as a serialized array in a cache file (you don't have to worry about this), and this file will be used for future requests until it expires. setLifeTime can be used to determine how long a cache file will live before the information in it is updated. The default value is 1 hour (3600 seconds).

PEAR::Cache

In general, Cach_Lite provides a single, easy-to-use system to solve any caching related issues. Since the next level is sites with especially high traffic, you should deal with PEAR::Cache - the "big brother" of Cache_Lite. It also provides caching enhancements, such as caching in shared memory, as an alternative to caching to a file, or the Msession PHP extension helping to store data in a balanced session, which is especially useful in balanced web servers. Cache_Lite, however, offers more than enough features to meet the needs of most sites.

how to manage client-side caching using PHP?

Now that we've looked at options for overriding client-side caching, it's time to look at a mechanism that allows us to control client-side caching with PHP. This approach will only work if you are using PHP in conjunction with Apache server, as we will be using the getallheaders function to get the headers passed by the browser. This feature only works in Apache. If you are using PHP 4.3.0 with Apache, working with HTTP headers is possible using the apache_request_headers and apache_response_headers functions. The getallheaders function has become an alias for new feature apache_request_headers.

The web browser cache mechanism is again HTTP. A number of headers are involved in instructing web browsers and proxy servers to cache the page independently. The situation is complicated by the fact that some of them are only available with HTTP 1.1.

checking HTTP headers in your browser

A simple but very handy tool for checking request and response headers is LiveHttpHeaders, an addon for Mozilla browser. You need to know exactly what headers your script is sending, especially when you're dealing with headers. HTTP caching.
For simplicity, we'll only cover the HTTP 1.0 caching headers, namely Expires, Last-Modified, and If-Modified-Since, and the HTTP 304 (Not Modified) status code.

Other headers available since HTTP 1.1, such as Cache-Control and ETag, are intended to provide an advanced mechanism that can be shared with web session state, in other words, the unauthorized visitor's version of the same page can be significantly different from displayed to the authorized user. HTTP 1.1 headers were originally added to allow such pages to be cached.

page expiration

The easiest header to use is the Expire header, which sets the date the page will expire. Until then, the web browser is allowed to use the cached version of the page.
Example:


function setExpires($expires)(
header("Expires: " . gmdate("D, d M Y H:i:s", time() + $expires) . "GMT");
}
echo "This page will self-destruct in 10 seconds
";
echo "Now " . gmdate("H:i:s") . " GMT
";
echo "
";
?>

The example above shows the current GMT time and displays a link that takes you to the page again. By using your browser's Refresh button, you can tell the browser you want to refresh the cache.

dates and times in HTTP

Dates in HTTP are always calculated relative to Greenwich Mean Time (GMT). The gmdate PHP function is exactly the same function as date, except that it automatically offsets GMT based on your server's system clock and region settings. When the browser encounters the Expires header, it caches the page. All subsequent page requests made before the specified expiration time use the cached version of the page, and no requests are made to the web server.
The Expires header is basically easy to implement, but in most cases, unless you're a highly organized person, you can't know exactly when this page your site will be updated. Since the browser will only contact the server after the page has expired, there is no way to tell the browser that the page in its cache is expired.

page change time

It's more practical to use the Last-Modified and If-Modified-Since headers available in HTTP 1.0. When using this method, you must send the Last-Modified header in response to every request to your PHP script. The next time the browser requests the page, it will send an If-Modified-Since header containing the time by which your script can determine if the page has been updated since the last request. If it doesn't, your script sends an HTTP 304 status code to indicate that the page hasn't changed, without displaying the page's content. If you combine the approach of time last change with a time value already available in your application (for example, the time of the most recent news article), you can take advantage of the web browser's cache and offload data traffic, saving traffic from your site where possible and improving its performance.

Be careful when testing any caching done in this style: if you do it wrong, you can cause your visitors to always have outdated copies of your site.

Harry Fuecks, translated by Sergey Mullin (SiMM) and Kuzma Feskov.

In the good old days, when creating websites was as simple as typing a few HTML pages together, sending web pages to a browser was a simple matter of sending a file by a web server. Visitors to the site could see these small, all-text pages almost instantly (except for slow modem users). Once the page has been loaded, the browser caches it somewhere on the local machine so that if the page is requested again, it can retrieve the local version from the cache, sending only a short request to make sure the page on the server hasn't been changed. Requests were processed quickly and as efficiently as possible, and everyone was happy (except those using 9600 baud modems).

The advent of dynamic web pages has changed things for the worse, effectively breaking this web page serving model due to two problems:

When a request for a dynamic web page is received by the server, some intermediate processing is performed, such as parsing (parsing) of the script by the PHP engine, which must be completed. This gives us a delay before the web server starts sending output to the browser. For a simple PHP script this is not essential, but for a more complex application the PHP engine can do a lot of things before the page is ready to be submitted. These additional steps result in a noticeable delay between user requests and the actual rendering of pages in their browsers.

A typical web server, such as Apache, uses the modification time of a file to correctly tell the web browser the cache state of the requested page. For dynamic web pages, the actual PHP script may only change occasionally, while the content it renders, possibly residing in a database, changes frequently. The web server has no way of knowing that the database has changed, yet it does not send the date of the last modification. If the client (browser) does not get any indication of how long the data has been valid, it assumes that the next time it needs to request a new page. The web server will always respond with an updated version of the page, whether or not the data has changed. To avoid this shortcoming, most web developers use meta tags or HTTP headers to tell the browser never to use the cached version of the page. However, this negates the web browser's natural ability to cache web pages and has some significant drawbacks. For example, the content of a dynamic page can change once a day, so the benefit of having even 24-hour browser caching of the page is obvious.

Normally for small PHP applications it's ok to ignore the existence of these issues, but as your site's complexity and traffic increases, you may run into problems. However, both of these problems can be solved, the first by server-side caching, the second by controlling client-side caching from your application. The approach you take to solve problems will depend on your application, but in this chapter we'll see how you can solve both problems using PHP and some PEAR library classes.

Note that the Caching chapter only discusses the decisions made when PHP help. They should not be confused with script caching solutions that work by optimizing and caching compiled PHP scripts. This group can include Zend Accelerator, ionCube PHP Accelerator, Turck MMCache/eaccelerator, APC.

How do I prevent browsers from caching the page?

Before we look at client and server caching methods, we first need to understand how to prevent web browsers (and proxies) from caching pages at all. The main way to achieve this is using HTML meta tags:

"Mon, 26 Jul 1997 05:00:00 GMT" />

By inserting a past date in the Expires meta tag, you tell the browser that the cached copy of the page is always out of date. This means that the browser should never cache a page. The Pragma: no-cache meta tag is a fairly well supported convention that most web browsers follow. Once they find this tag, they usually don't cache the page (though there are no guarantees, it's just a convention).

This sounds good, but there are two problems with using meta tags:

If the tag did not exist when the page was first requested by the browser, but appears later (for example, you modified the pageheader.php include file, which is the header of every web page), the browser will remain blissfully ignorant and use its cached copy of the original.

Proxy servers that cache web pages, such as a generic ISP, will generally not directly examine the content of an HTML document. Instead, they rely only on the web server that the documents came from and the HTTP protocol. In other words, the web browser may think it shouldn't cache the page, but the proxy server between the browser and your web server probably doesn't know this - and will continue to send the same stale page to the client.

The best approach is to use the HTTP protocol directly with the PHP header function, equivalent to the above two meta tags:

header(); header("Pragma: no-cache" ) ;

We can go one step further by using the Cache-Control header, which is compatible with browsers that support HTTP 1.1:

header( "Expires: Mon, 26 Jul 1997 05:00:00 GMT") ; header( "Cache-Control: no-store, no-cache, must-revalidate") ; header( "Cache-Control: post-check=0, pre-check=0", FALSE ) ; header("Pragma: no-cache" ) ;

This ensures that no web browser or intermediate proxy will cache the page, so visitors will always get the latest version of the content. In fact, the first header should be self contained, this is the best way to ensure that the page is not cached. Titles Cache-Control and pragma added for the purpose of "insurance". Although they do not work in all browsers or proxies, they will catch some cases in which Expires does not work properly (for example, if the date on the client computer is not set correctly).

Of course, completely eliminating caching introduces the problems we discussed at the beginning of this chapter. Now we will consider the solution to these problems. Internet Explorer and file download caching

Our discussion of PDF in Chapter 3 Alternative types content, explained that problems can arise when you're dealing with caching and downloading files. If the PHP script uses headers such as Content-Disposition: attachment, filename=myFile.pd f or Content-Disposition: inline, filename=myFile.pdf, you will have problems with Internet Explorer if you tell the browser not to cache the page.

Internet Explorer handles downloads in a rather unusual way, making two requests to a website. The first request downloads the file and stores it in the cache until the second request is made (without saving the response). This request initiates a file transfer process to the end user according to the file type (for example, launches Acrobat Reader if the file is a PDF document). This means that if you send headers that prevent the browser from caching the page, Internet Explorer will delete the file between the first and second request, resulting in nothing for the end user. If the file you serve as a PHP script doesn't change, one of the simplest solutions is to remove the "disable caching" headers from the script.

If the file being downloaded changes regularly (i.e. you want the browser to download the newest version), you should use the header Last Modified, which will be discussed later in this chapter, and ensure that the modification time does not change between two consecutive requests. You must do this in a way that does not affect users of browsers that handle downloads correctly. One solution in this case would be to store the file on your web server and provide a simple link to it, leaving the web server to report the caching headers for you. Of course, this solution may not be acceptable if authorized access to the file is supposed, this solution allows direct loading of the saved file.

How can I capture server side data for caching?

It's time to take a look at how we can reduce latency with server-side output caching. The general approach is to start rendering the page as usual, doing database queries and so on in PHP. However, before sending the result to the browser, we capture it and save the finished page, for example, in a file. On the next request, the PHP script first checks for a cached version of the page. If it exists, the script sends the cached version to the browser, thus eliminating the delay in re-creating the page.

A few words about caching with templates

Template engines like Smarty often talk about template caching. Typically, these engines offer a built-in mechanism for saving a compiled version of the template (i.e. generating a PHP source from the template), which prevents us from having to parse the template each time a page is requested. This is not to be confused with output caching, which is about caching the provided HTML (or other output) that PHP sends to the browser. You can successfully use both types of caching at the same time on the same site.

Now we'll take a look at PHP's built-in caching mechanism using output buffering, which you can use regardless of how you create your content (with or without templates). Consider a situation in which your script displays the result using, for example, echo or print to give data directly to the browser. In such a case, you can use PHP's output control functions to store data in a buffer memory that your PHP script has both access to and control over.

Here is a simple example:

Example 5.1. 1.php

Ob_start(); // Output some text (which is stored in the buffer); echo "1. Output it to the buffer
"
; // Stop buffering and clear the output buffer ob_end_clean(); // Output some text normally echo "2. Normal output
"
; // Output the contents of the buffer echo $buffer ;

The buffer itself stores the output as a string. So, in the script above, we start buffering at ob_start and use echo to output something. We then use ob_get_contents to fetch the data buffered by the echo statement and store it in a string. The ob_end_clean function stops output buffering and destroys its contents, alternatively ob_end_flush can be used to flush the contents of the buffer.

The above script will output:

2. Normal output 1. Output this to the buffer

In other words, we captured the output of the first echo, then sent it to the browser after the second echo. As you can see from this simple example, output buffering is a very powerful tool for shaping your site, it provides a caching solution, as we'll see shortly, and is a great way to hide errors from your site visitors (see Chapter 10, Handling Errors). It also provides an alternative option for browser redirects in situations such as user authentication.

HTTP headers and output buffering

Output buffering can help solve the most common header problem, not to mention session_start and set_cookie. Usually, if you call any of these functions after page rendering has started, you'll get a nasty error message. With output buffering enabled, the only type of output that avoids buffering is HTTP headers. By using ob_start at the very beginning of your application's execution, you can send headers at any point in the program you like without running into the usual errors. Then, once you're sure you don't need to print any more HTTP headers, you can immediately dump the page's content from the buffer. (translator's note: it should be noted that such use of this function is highly unjustified. In most cases, the need to use output buffering to get rid of errors of this type simply does not exist and everything can be easily fixed by proper application design)

Using Output Buffering for Server-Side Caching

You have already seen a basic example of output buffering, now the next step is to save the buffer to a file:

Example 5.2. 2.php

// If a cached version exists... if (file_exists("./cache/2.cache" ) ) ( // Read and output file readfile("./cache/2.cache" ); exit(); ) // Start buffering output ob_start(); // Output the rest of the HTML ?> Cached Page "http://www.php.net/outcontrol">Output Control Functions // Get the contents of the buffer$buffer = ob_get_contents(); // Stop buffering and output buffer ob_end_flush(); // Save cache file with content$fp = fopen("./cache/2.cache" , "w" ) ; fwrite ($fp , $buffer ) ; fclose($fp) ;

First, the above script checks to see if a version of the page exists in the cache, and if it does, the script reads and prints it out. Otherwise, it uses output buffering to create a cached version of the page. It is saved as a file after using ob_end_flush to display the page to the user.

The 2.cache file contains the exact HTML copy that the script provides:

"http://www.w3.org/1999/xhtml"> > > Cached Page > "text/html; charset=windows-1251" /> > > This page is cached by PHP "http://www.php.net/outcontrol"> Output control functions > > >

Block Buffering

The simplified approach caches the output buffer as a single page. However, this approach robs you of the real power provided by PHP's output-management functions to improve the performance of your site by varying the lifespan of your content accordingly.

Undoubtedly, some parts of the page you send to the visitor change very rarely, such as the header, menu, and footer. However, other parts, such as tables containing forum discussions, may change quite often. Output buffering can be used to cache sections of a page in separate files, then build a page out of them - a solution that eliminates the need for repeated database queries, while loops, and so on. You can give each page block an expiration date after which the cache file is recreated, or you can also include a mechanism in your application that will delete the cache file every time the content stored in it changes.

Here is an example demonstrating this principle:

Example 5.3. 3.php (start)

/** * Write cache file * @param string contents - contents of the buffer * @param string filename - filename used when creating the cache file * @return void */ function writeCache($content , $filename ) ( $fp = fopen ("./cache/" . $filename , "w" ) ; fwrite ($fp , $content ) ; fclose ($fp ) ; ) /** * Check cache files * @param string filename - name of the cache file to check * @param int expiry - maximum "age" of the file in seconds * @return mixed cache content or false */ function readCache($filename , $expiry ) ( if (file_exists ("./cache/" . $filename ) ) ( if ((time () - $expiry ) > filemtime ("./cache/" . $filename ) ) return FALSE ; $cache = file ("./cache/" . $filename ) ; return implode ("" , $cache ) ; ) return FALSE ; )

The first two functions we defined, writeCache and readCache, are used respectively to create cache files and check for their existence. The writeCache function receives the data to be cached in the first argument, and the file name to use when creating the cache file. The readCache function receives the name of the cache file in the first parameter, along with a time in seconds after which the cache file should be considered stale. If it finds the cache file valid, the script will return its contents, otherwise it will return FALSE to indicate that the cache file either does not exist or is out of date.

In this example, I used a procedural approach. However, I don't recommend doing this in practice, as it will end up in very messy code (see later solutions for a better alternative) and will likely cause file locking issues (e.g. what happens when someone accesses the cache while it is being updated? ).

Let's continue this example. After output buffering is started, processing begins. First, the script calls readCache to see if the file 3_header.cache exists, it contains the page header - the HTML header and the beginning of the body. We're using PHP's date function to print out the time the page was actually generated, so you'll see the various cache files in action when the page is rendered.

Example 5.4. 3.php (continued)

// Start buffering output ob_start(); // Handling the header if (!$header = readCache("3_header.cache" , 604800 ) ) ( // Display header ?>"-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/1999/xhtml"> Block cached page "text/html; charset=windows-1251" /> Hat time:

What happens when the cache file is not found? Some content is output and assigned to a variable using ob_get_contents, after which the buffer is cleared with ob_clean. This allows us to capture the output in chunks and match them against individual cache files using writeCache. The page title is now stored as a file that can be used without our having to rebuild the page. Let's go back for a second to the beginning of the conditional statement. When we called readCache, we passed it a cache lifetime of 604800 seconds (one week), readCache uses the cache file's modification time to determine if the cache file is still valid.

For the content (body) of the page, we will still use the same process. However, this time when we call readCache we will use a cache lifetime of five seconds, the cache file will be updated every time it is "older" than 5 seconds:

Example 5.5. 3.php (continued)

// Processing the page body if (!$body = readCache("3_body.cache" , 5 ) ) ( echo "Body Creation Time: ". date("H:i:s" ) . "
" ; $body = ob_get_contents () ; ob_clean () ; writeCache($body , "3_body.cache" ) ; )

The footer effectively changes in the same way as the header. After that, output buffering stops and the contents of three variables containing page data are displayed:

Example 5.6. 3.php (end)

// Handling the page footer if (!$footer = readCache("3_footer.cache" , 604800 ) ) ( ?> Footer creation time:
// stop buffering ob_end_clean(); // Display page content echo $header . $body. $footer ;

The end result looks something like this:

Header creation time: 17:10:42 Body creation time: 18:07:40 Footer creation time: 17:10:42

The header and footer are updated weekly while the body is updated when it is older than 5 seconds.

The flowchart in Figure 5.1 summarizes the block buffering methodology.

Figure 5.1. Block diagram of output buffering

Nested buffers

You can nest one buffer within another virtually indefinitely by simply calling ob_start repeatedly. This can be useful if you have a lot of operations that use the output buffer, for example some catch PHP error messages, others deal with caching. You must make sure that ob_end_flush or ob_end_clean is called each time ob_start is used.

How do I implement a simple server side caching system?

Now that we understand the ideas behind output buffering, it's time to look at how we can use this process in action in a way that is easy to maintain. To do this, we'll use a little help from PEAR::CacheLite (version 1.1 was used in the examples here).

Cache_Lite

As I said, in the interests of ease of code maintenance and a reliable caching mechanism, it is wise to leave the responsibility for the cache logic to classes that you trust. Cache_Lite is a powerful yet easy-to-use caching library that takes care of tasks such as temporarily locking cache files, creating and validating them, managing the output buffer, and directly caching the result of a function or class method. The main reason for choosing this library is the relatively easy integration of Cache_Lite into an existing application, which requires only minor changes in the code.

Cache_Lite consists of three main classes. The first is the Cache_Lite base class, which is only responsible for creating and reading cache files and does not buffer the output. This class can be used alone in cases where it is not necessary to use output buffering, such as when saving the result of a PHP script parsing a template. The examples given here do not use the Cache_Lite class directly and demonstrate the use of the other two classes. Cache_Lite_Function is used to call a function or class method and then cache the results of the work. This can be useful, for example, for caching the result of a My SQL? query. The Cache_Lite_Output class uses PHP's output control functions to capture the data generated by the script and store it in cache files. This allows you to perform the same tasks as the previous solution.

Here is an example that will show you how you could use Cache_Lite to accomplish the task we covered in the previous part. To consider any use of Cache_Lite, we must first set it up - create an array of parameters - which will define the behavior of the class. We'll look at them in more detail below, but for now, note that your script must have read and write permissions to the cacheDir directory.

Example 5.7. 4.php (start)

// Include the output class PEAR::Cache_Lite require_once "Cache/Lite/Output.php" ; // Define settings for Cache_Lite$options = array ( "cacheDir" => "./cache/" , "writeControl" => "true" , ​​"readControl" => "true" , ​​"readControlType" => "md5" ) ; // Create an object of class Cache_Lite_Output

For each part of your script's output that you want to cache, you need to set the cache lifetime in seconds. this time determines how long to take data from the cache. After this time, the data in the file will be updated. Next, we call the start() method, available only in the Cahce_Lite_Output class, which enables output buffering. We pass 2 parameters to the method: the first is the identifier of the file with the cache, the second is the group (cache type). The "group" parameter allows you to combine several templates, this allows you to perform group actions, for example, delete all cache files in the group. As soon as the output of the part we need is finished, we must call the stop() method. This method will stop buffering and save the contents of the buffer to a file.

Example 5.8. 4.php (continued)

// Set cache lifetime for this part$cache ->setLifeTime (604800 ) ; // Start buffering for the region named header // and put it in the Static group if (!$cache ->start ("header" , "Static" ) ) ( ?>"-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/1999/xhtml"> PEAR::Cache_Lite example "text/html; charset=windows-1251" />

PEAR::Cache_Lite example

Title Creation Time:
// Stop buffering and write buffer to file$cache ->end() ; )

The caching of the main body of the output (body) and the bottom part (footer) is similar to caching the header. Please note that we are again setting the cache lifetime for each next part.

Example 5.9. 4.php (continued)

$cache ->setLifeTime(5) ; if (!$cache ->start ("body" , "Dynamic" ) ) ( echo "Body Creation Time: ". date("H:i:s" ) . "
" ; $cache ->end () ; ) $cache ->setLifeTime (604800 ) ; if (!$cache ->start ("footer" , "Static" ) ) ( ?> Bottom part creation time:
end(); )

When you call this page to view, Cache_Lite will create the following files in the cache directory:

./cache/cache_Static_header ./cache/cache_Dynamic_body ./cache/cache_Static_footer

If you later request the same page, the code above will show you the contents of these files, as long as they haven't expired, of course.

  • Protect files with cache.
  • Make sure the directory where you store the cache files is not publicly accessible. otherwise, your site visitors will be able to do more than you would like them to.

Cache_Lite Settings

When calling Cache_Lite (or any of its subclasses, such as Cache_Lite_Output), there are many ways to control its behavior. All parameters must be placed in an array and passed to the constructor:

Example 5.10. 4.php (end)

// Set the settings for Cache_Lite$options = array ( "cacheDir" => "./cache/" , "writeControl" => TRUE , "readControl" => TRUE , "readControlType" => "md5" ) ; // Create a Cache_Lite_Output object$cache = new Cache_Lite_Output($options ) ;

In the current version of the class (1.1), the following settings are available:

  • cacheDir - This is the directory where the cache files will be placed. The default value is the directory where the script is executed.
  • caching - this option enables or disables Cache_Lite features. For example, if you have a lot of requests to Cache_Lite, and during debugging you want to turn off caching, set to FALSE. The default value is TRUE.
  • lifetime - This parameter contains the default cache lifetime (in seconds). You can change the value by calling the setLifeTime() method. The default value is 3600 (one hour).
  • fileNameProtection - If this option is enabled, Chache_Lite will use MD5 encoding to generate the cache filename. This allows you to use any characters in the names of cache files and groups, even those prohibited by the file system. This setting must be enabled when you use the Cache_Lite_Function. The default value is TRUE (enabled).
  • fileLocking - This option enables mechanisms for blocking the cache file while data is being written to it. The default value is TRUE (enabled).
  • writeControl - Verifies that the cache file was written correctly immediately after the write ended. Throws PEAR:Error on error. This feature allows your script to overwrite the cache file one more time, but slows it down. The default value is TRUE (enabled).
  • readControl - Before reading the file with the cache checks it for corruption. Cache_Lite places a file length value in the file that can be used to control its integrity. There is also an alternative mechanism for checking file integrity. It is enabled by the readControlType parameter. These mechanisms slow things down somewhat, but help ensure that your users see an uncorrupted page. the default value is TRUE (enabled).
  • readControlType - This parameter specifies the type of mechanism for reading cache files. Mechanisms available: loop redundancy check ("crc32" is the default) - using PHP's crc32 function, "MD5" hash - using PHP's md5 function, or a simple length check - "strlen". Note that this mechanism is not intended to protect cache files from being called directly by unauthorized users. This is just a way to determine if the file is corrupted or not.

pearErrorMode - Enables PEAR's way of returning errors. The default value is CACHE_LITE_PEAR_RETURN - returns the /#c#?PEAR::Error object.

  • memoryCaching - If this option is enabled, each time you call a cache write to a file, it is written to the Cache_Lite array. saveMemoryCachingState and getMemoryCachingState are used to access the cache stored in memory between requests. The advantage of this method is that the contents of the cache can be stored in a single file, reducing the number of read/write cycles to disk. The cache is restored directly to an array that your script has access to. In our examples, we will use the regular Cache_Lite mechanism, but you may want to experiment with this setting later if you have a very large site. Default is TRUE (off).
  • onlyMemoryCaching - If you enable this option - only the memory caching mechanism will be used. Default is TRUE (off).

memoryCachingLimit - This parameter specifies the limit on the number of cache files that can be stored in the in-memory array. the larger the number of files, the more memory will be consumed. So defining a constraint is a very good idea. Of course, this does not affect the size of the cache file, since one or two massive files will not create any problems. the default value is 1000.

Clearing the cache

Cahce_Lite contains a clever mechanism for determining the lifetime of cache files, which creates a good basis for the safety of your files and their timely updates. However, there are times when you need to update the cache file immediately. For such cases, there are remove() and clean() methods. The remove() method is designed to remove a particular cache file. it needs the cache ID and the name of the group that the file belongs to. The following example will delete the body cache file from the previous example:

$cache ->remove ("body" , "Dynamic" ) ;

The clean() method allows us to delete all files in our directory if we call it with no parameters. If you pass the name of a group as a parameter, then all files included in this group will be deleted. If we wanted to remove the header and bottom, then we need to issue commands similar to these:

$cache ->clean("Static" ) ;

The remove() and clean() methods obviously need to be called in response to events within the application. For example, if you have a forum, you should definitely delete the cache file if any user submits a new message. Although this solution looks nice, it may involve code changes. If you have a main script that hooks into every page of the application that a visitor can view, you can simply watch for incoming events, such as the $_GET["newPost"] variable, and delete the required cache files. This will allow you to create a centralized cache management mechanism. you could even include this code in php.ini (see the description of the auto_prepend_file setting).

Function call caching

In Chapter 2, XML, we looked at remoting web services using SOAP and XML-RPC. Because web services are available over the network, it's often a good idea to cache the result so that it can be executed locally rather than repeating the same slow request over and over again. In the simplest case, we could use PHP sessions, which we covered in that chapter, but because this solution is based on visitor regularity, opening a request for each visitor would still be slow. In such cases, Cache_Lite can be very handy.

  • PEAR uses Cache_Lite
  • The PEAR Web installer (read Appendix D, working with PEAR) uses Cache_Lite to cache XML-RPC requests sent to the PEAR Web server.

In the section called “How do I consume SOAP Web services with PHP?” we wrote a client to serve a SOAP Web service based on its WSDL file; this service provides weather information to all airports in the world. Here is the code that receives data from the remote server:

$countries = $stationInfo ->listCountries () ;

$country = $stationInfo ->searchByCountry ($_GET [ "country" ] ) ;

In both cases, these calls correspond to a request for data over the network. Using Cache_Lite, we could cache the data returned by the service and could reuse it. This would avoid additional unnecessary network connections, and would greatly increase the speed of execution. Please note that we are only looking at code related to our theme here. At the beginning we include Cache_Lite_Function:

Example 5.11. 5.php (start)

// Include PEAR::Cache_Lite_Function require_once "Cache/Lite/Function.php" ;

Example 5.12. 5.php (continued)

// Set parameters for for Cache_Lite_Function // WARNING: fileNameProtection = TRUE!$options = array ( "cacheDir" => "./cache/" , "fileNameProtection" => TRUE , "writeControl" => TRUE , "readControl" => TRUE , "readControlType" => "strlen" , "defaultGroup" => "SOAP" ) ; // Create an object of class Cache_Lite_Function$cache = new Cache_Lite_Function($options ) ;

It is important that the fileNameProtection parameter is set to TRUE. This value is accepted by default, but I deliberately set it manually to emphasize significance. Setting this parameter to FALSE will result in an invalid filename, so no caching will occur.

Example 5.13. 5.php (continued)

$countries = $cache ->call ("stationInfo->listCountries" ) ;

Example 5.14. 5.php (end)

$country = $cache ->call ( "stationInfo->searchByCountry",$_GET [ "country" ] ) ;

When a request is made for the first time, Cache_Lite_Function stores the results as a serialized array in a cache file (you don't have to worry about this), and this file will be used for future requests until it expires. setLifeTime can be used to determine how long a cache file will live before updating the information in it. The default value is 1 hour (3600 seconds).

In general, Cache_Lite provides a single, easy-to-use system to solve any caching related issues. Since the next level is sites with particularly high traffic, you should look into PEAR::Cache, it's the big brother of Cache_Lite. It also provides caching extensions, such as shared memory caching as an alternative to file caching, or the Msession PHP extension help by storing data in a balanced session, which is especially useful in balanced WEB servers. I'll provide more PEAR::Cache material at the end of this article. Cache_Lite, however, offers more than enough features to meet the needs of most sites.

How do I manage client-side caching with PHP?

Now that we've looked at options for overriding client-side caching and how client-side caching can be set up, it's time to look at a mechanism that will allow us to control the client-side cache with PHP. This approach will only work if you are using PHP in conjunction with an Apache server, as we will be using the getallheaders function to get the headers passed by the browser. this feature only works in Apache.

New function names

If you are using PHP 4.3.0 with Apache, the HTTP headers are available with the apache_request_headers and apache_response_headers functions. The getallheaders function has become an alias for the new apache_request_headers function.

The mechanism for dealing with the web browser cache is again HTTP. A number of headers are involved in instructing web browsers and proxies to independently cache a page, a situation made more difficult by the fact that some of them are only available with HTTP 1.1.

Checking HTTP Headers in Your Browser

A simple but very handy tool for checking request and response headers is Live Http Headers? is an addon for the Mozilla browser. You need to know exactly what headers your script is sending, especially when dealing with HTTP caching headers.

For simplicity, we'll only cover the HTTP 1.0 caching headers, namely Expires, Last-Modified, and If-Modified-Since, and the HTTP 304 (Not Modified) status code.

Other headers available since HTTP 1.1, such as Cache-Control and ETag, are intended to provide an advanced mechanism that can be used in conjunction with web session state, in other words, the version of a given page displayed to an unauthorized visitor may be significantly different from that displayed to an authorized user. HTTP 1.1 headers were originally added to allow such pages to be cached.

Page expiration

The easiest header to use is the Expire header, which sets a date (possibly in the future) when the page will expire. Until then, the web browser is allowed to use the cached version of the page.

Example 5.15. 6.php

/** * Sends an Expires HTTP 1.0 header. * @param int number of seconds until timeout */ function setExpires($expires ) ( header ("Expires: " . gmdate ("D, d M Y H:i:s" , time () + $expires ) . "GMT" ) ; ) // Set the expiration time header Expires setExpires(10) ; // Display echo "This page will self-destruct in 10 seconds
"
; echo "Now " . gmdate("H:i:s" ) . " GMT
" ; echo """>View again
" ;

The setExpires function sends an HTTP Expires header with a future time in seconds. The example above shows the current GMT time and displays a link that allows you to go to the page again. By using your browser's Refresh button, you can tell the browser you want to refresh the cache. Using the link, you will see that the time only changes once every 10 seconds.

Dates and times in HTTP

Dates in HTTP are always calculated relative to Greenwich Mean Time (GMT). The gmdate PHP function is exactly the same function as date, except that it automatically compensates for GMT based on your server's system clock and region settings.

When the browser encounters the Expires header, it caches the page. All subsequent page requests made before the specified expiration time use the cached version of the page, and no requests are made to the web server.

The Expires header is mostly easy to implement, but in most cases, unless you're a highly organized person, you can't know exactly when a given page on your site has been updated. Since the browser will only contact the server after the page has expired, there is no way to tell the browser that the page in its cache is expired. You also lose some traffic to your website because the browser does not contact the server when requesting a page from the cache.

Page change time

It's more practical to use the Last-Modified and If-Modified-Since headers available in HTTP 1.0. Technically known as making a conditional GET request, you return any content based on the condition of the If-Modified-Since request header that came in.

When using this method, you must send the Last-Modified header each time your PHP script is accessed. The next time the browser requests the page, it will send an If-Modified-Since header containing the time by which your script can determine if the page has been updated since the last request. If it doesn't, your script sends an HTTP 304 status code to indicate that the page hasn't changed, without displaying the page's content.

The simplest example of a conditional GET is pretty tricky, a pretty handy tool to show how it works - PEAR::Cache_Lite. However, this should not be taken as an example of server-side caching, it simply provides for a file that is updated periodically.

Example 5.16. 7.php (start)

// Include PEAR::Cache_Lite require_once "Cache/Lite.php" ; // Define Cache_Lite settings$options = array ( "cacheDir" => "./cache/" ) ; // Initialize Cache_Lite$cache = new Cache_Lite($options ) ; // Some dummy data to store$id = "MyCache" ; // Initialize the cache if the page is requested for the first time if (!$cache ->get ($id ) ) ( $cache ->save ("Dummy" , $id ) ; ) // Randomizer...$random = array (0 , 1 , 1 ) ; shuffle($random) ; // Random cache update if ($random [ 0 ] == 0 ) ( $cache ->save ("Dummy" , $id ) ; ) // Get the last modification time of the cache file$lastModified = filemtime ($cache ->_file) ; header ("Last-Modified: " . gmdate ("D, d M Y H:i:s" , $lastModified ) . " GMT" ) ; < v6 отдаёт их неправильно) $modifiedSince = 0 ; ) if ($lastModified<= $modifiedSince ) { header ("HTTP/1.1 304 Not Modified" ) ; exit () ; } echo "Сейчас " . gmdate ("H:i:s" ) . "according to GMT
"
; echo """>Update
" ;

Remember to use the Refresh link when running this example (clicking Refresh will usually clear your browser's cache). If you click on the link repeatedly, eventually the cache will be modified, your browser will remove the version from the cache and store the new page provided by PHP in it.

In the example above, we used PEAR::Cache_Lite to create an arbitrarily modified cache file. We set the modification time of the cache file with this line:

$lastModified = filemtime ($cache ->_file) ;

Technically speaking, this is a hack, since the $_file variable of the PEAR::Cache_Lite class is supposed to be private. However, we are forced to use it to get the name of the cache file and find out its modification time.

Then, using the modification time of the cache file, we send the Last-Modified header. We need to send it for every rendered page to force the browser to send us an If-Modified-Since header with every request.

// Give HTTP header Last-Modified header ("Last-Modified: " . gmdate ("D, d M Y H:i:s" , $lastModified ) . " GMT" ) ;

Using the getallheaders function ensures that we get all incoming headers from PHP as an array. Then we have to check that the If-Modified-Since header actually exists, if it does, we have to handle the special case of older versions of Mozilla (below version 6) that added an extra field to the If-Modified- header at the end (deviating from the spec) Since. Using PHP's strtotime function, we get the timestamp of the date passed to us by the browser. If there is no such header, we set the timestamp to zero, thus forcing PHP to give the visitor the latest version of the page.

// Get client request headers - Apache only$request = getallheaders(); if (isset ($request [ "If-Modified-Since" ] ) ) ( // Split If-Modified-Since (Netscape< v6 отдаёт их неправильно) $modifiedSince = explode (";" , $request [ "If-Modified-Since" ] ) ; // Convert the If-Modified-Since client request to a timestamp$modifiedSince = strtotime ($modifiedSince [ 0 ] ) ; ) else ( // Set modification time to zero$modifiedSince = 0 ; )

Finally, we check to see if the cache has been modified since the visitor last accessed this page. If it's not, we simply send a Not Modified response in the header and stop running the script without loading the data link and saving CPU time by instructing the browser to display the cached version of the page.

// Compare content last modification time with client cache if ($lastModified<= $modifiedSince ) { // Unload the data link! header("HTTP/1.1 304 Not Modified" ) ; exit(); )

If you combine the last modified time approach with a time value that is already available in your application (for example, the time of the most recent news article, or the expiration time from the server-side caching system we saw in the last solution), you can take advantage of the web browser's cache. and offload the data link, saving information traffic from your site where possible and improving its perceived performance.

Be careful when testing any caching done in this style, if you do it wrong you can cause your visitors to always have stale copies of your site.

Additional links

  • Conditional GET request
  • Tracking content on dynamic sites

In the good old days, when creating websites was as simple as typing a few HTML-pages, sending web pages to the browser was simply a file being sent by the web server. Visitors to the site could see these small, all-text pages almost instantly (except for slow modem users). Once the page has been loaded, the browser caches it somewhere on the local machine so that if the page is requested again, it can retrieve the local version from the cache, sending only a short request to make sure the page on the server hasn't been changed. Requests were processed quickly and as efficiently as possible, and everyone was happy (except those using 9600 baud modems).

The advent of dynamic web pages has changed things for the worse, effectively breaking this web page serving model due to two problems:

  1. When a request for a dynamic web page is received by the server, some intermediate processing is performed, such as parsing (parsing) the script by the engine PHP to be completed. This gives us a delay before the web server starts sending output to the browser. For simple PHP-script is not essential, but for a more complex application, the engine PHP may perform many actions before the page is ready to be submitted. These additional steps result in a noticeable delay between user requests and the actual rendering of pages in their browsers.
  2. A typical web server, such as Apache, uses the modification time of a file to correctly tell the web browser the cache state of the requested page. For dynamic web pages, in fact PHP-script may change only occasionally, while the content it displays, possibly residing in a database, changes frequently. The web server has no way of knowing that the database has changed, yet it does not send the date of the last modification. If the client (browser) does not get any indication of how long the data has been valid, it assumes that the next time it needs to request a new page. The web server will always respond with an updated version of the page, whether or not the data has changed. To avoid this shortcoming, most web developers use meta tags or HTTP-headers to tell the browser never to use the cached version of the page. However, this negates the web browser's natural ability to cache web pages and has some significant drawbacks. For example, the content of a dynamic page can change once a day, so the benefit of having even 24-hour browser caching of the page is obvious.

Normally for small PHP applications it's ok to ignore the existence of these issues, but as your site's complexity and traffic increases, you may run into problems. However, both of these problems can be solved, the first by server-side caching, the second by controlling client-side caching from your application. The approach you take to solve problems will depend on your application, but in this chapter we will see how you can solve both problems using PHP and some library classes. PEAR.

How do I prevent browsers from caching the page?

Before we look at client and server caching methods, we first need to understand how to prevent web browsers (and proxies) from caching pages at all. The main way to achieve this is using HTML meta tags:

By inserting a past date in the Expires meta tag, you tell the browser that the cached copy of the page is always out of date. This means that the browser should never cache a page. Meta tag Pragma: no-cache a fairly well supported convention followed by most web browsers. Once they find this tag, they usually don't cache the page (though there are no guarantees, it's just a convention).

This sounds good, but there are two problems with using meta tags:

  1. If the tag did not exist when the page was first requested by the browser, but appears later (for example, you modified the include file pageheader.php which is the header of every web page), the browser will remain blissfully unaware and will use its cached copy of the original.
  2. Proxy servers that cache web pages, such as the common ISP, will not examine the contents directly at all HTML-document. Instead, they rely only on the web server that the documents came from and the protocol HTTP. In other words, the web browser may think it shouldn't cache the page, but the proxy server between the browser and your web server probably doesn't know this - and will continue to send the same stale page to the client.

The best approach is to use the protocol directly HTTP using PHP function header(), equivalent to the two meta tags above:

We can go one step further by using the title Cache-Control compatible with browsers that support HTTP 1.1:

Header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", FALSE); header("Pragma: no cache");

This ensures that no web browser or intermediate proxy will cache the page, so visitors will always get the latest version of the content. In fact, the first header should be self contained, this is the best way to ensure that the page is not cached. Titles Cache-Control and pragma added for the purpose of "insurance". Although they do not work in all browsers or proxies, they will catch some cases in which Expires does not work properly (for example, if the date on the client computer is not set correctly).

Of course, completely eliminating caching introduces the problems we discussed at the beginning of this chapter. Now we will consider the solution to these problems.

Internet Explorer and file download caching

If while serving a file download PHP The script uses headers such as Content-Disposition: attachment, filename=myFile.pdf or Content-Disposition: inline, filename=myFile.pdf you will have problems with Internet Explorer'ohm if you tell the browser not to cache the page.

Internet Explorer handles the download in a rather unusual way, making two requests to the website. The first request downloads the file and stores it in the cache until the second request is made (without saving the response). This request invokes the process of transferring the file to the end user according to the file type (for example, starts Acrobat Reader if the file is PDF-document). This means that if you send headers that prevent the browser from caching the page, Internet Explorer will delete the file between the first and second request, leaving the end user with nothing. If the file you are uploading PHP-script does not change, one of the simplest solutions would be to remove the "prohibit caching" headers from the script.

If the file being downloaded changes regularly (i.e. you want the browser to download the newest version), you should use the header Last Modified, which will be discussed later in this chapter, and ensure that the modification time does not change between two consecutive requests. You must do this in a way that does not affect users of browsers that handle downloads correctly. One solution in this case would be to store the file on your web server and provide a simple link to it, leaving the web server to report the caching headers for you. Of course, this solution may not be acceptable if authorized access to the file is supposed, this solution allows direct loading of the saved file.

How can I capture server side data for caching?

It's time to take a look at how we can reduce latency with server-side output caching. The general approach starts to render the page as usual, making queries against the database and so on to PHP. However, before sending the result to the browser, we capture it and save the finished page, for example, in a file. On the next request, PHP-script first checks for a cached version of the page. If it exists, the script sends the cached version to the browser, thus eliminating the delay in re-creating the page.

A few words about caching with templates

How do I manage client-side caching with PHP?

It's time to look at the mechanism that will allow us to control the cache on the client side by means of PHP. This approach will only work if you use PHP in connection with the server Apache, as we will be using the getallheaders() function to get the headers passed by the browser. This function only works in Apache.

New function names

If you are using PHP 4.3.0 s Apache, HTTP headers are available from the apache_request_headers() and apache_response_headers() functions. The getallheaders() function has become an alias for the new apache_request_headers() function.

The mechanism for working with the web browser cache is again HTTP. A number of headers are involved in instructing web browsers and proxies to cache the page independently, a situation complicated by the fact that some of them are only accessible from HTTP 1.1.

Checking HTTP Headers in Your Browser

A simple but very handy tool for checking request and response headers is LiveHttpHeaders- browser addon Mozilla. You need to know exactly what headers your script is sending, especially when dealing with caching headers. HTTP.

For simplicity, we will only consider HTTP 1.0 caching headers, namely Expires, Last Modified and If-Modified-Since, as well as the status code HTTP 304 (Not Modified).

Other titles available from HTTP 1.1 for example Cache-Control and ETag, are intended to provide an advanced mechanism that can be used in conjunction with web session state, in other words, the version of a given page displayed to an unauthorized visitor may be significantly different from that displayed to an authorized user. Titles HTTP 1.1 was originally added to allow such pages to be cached.

Page expiration

The easiest header to use is the header Expire, which sets a date (possibly in the future) when the page will expire. Until then, the web browser is allowed to use the cached version of the page.

Example 7.6.php
"; echo "Now " . gmdate("H:i:s") . " GMT
"; echo "View again
"; ?>

Function setExpires sends header HTTP Expires with future time given in seconds. The example above shows the current GMT time and displays a link that allows you to go to the page again. By using your browser's Refresh button, you can tell the browser you want to refresh the cache. Using the link, you will see that the time only changes once every 10 seconds.

Dates and times in HTTP

Dates in HTTP are always calculated relative to Greenwich Mean Time (GMT). PHP's gmdate() function is exactly the same function as date() , except that it automatically offsets GMT based on your server's system clock and region settings.

When the browser encounters the header Expires, it caches the page. All subsequent page requests made before the specified expiration time use the cached version of the page, and no requests are made to the web server.

header Expires mostly simple to implement, but in most cases, unless you're a highly organized person, you can't know exactly when a given page on your site has been updated. Since the browser will only contact the server after the page has expired, there is no way to tell the browser that the page in its cache is expired. You also lose some traffic to your website because the browser does not contact the server when requesting a page from the cache.

Page change time

More practical use of headers Last Modified and If-Modified-Since available in HTTP 1.0. Technically known as making a conditional GET request, you return any content based on the condition of the request header that came in. If-Modified-Since.

When using this method, you must send the header Last Modified every time your PHP script is accessed. The next time the browser requests the page, it will send the header If-Modified-Since A containing the time by which your script can determine if the page has been updated since the last request. If it's not, your script sends a status code HTTP 304 to indicate that the page hasn't changed without displaying the page's content.

Set the cache file modification time with this line: $lastModified = filemtime($cache_file);

Then, using the modification time of the cache file, we send the header Last Modified. We need to send it for every rendered page to force the browser to send us the header If-Modified-Since with every request.

// Return the HTTP header Last-Modified header("Last-Modified: " . gmdate("D, d M Y H:i:s", $lastModified) . " GMT");\n \n"; echo " \n"; echo " \n"; echo " \n"; ?>

If you combine the last modified time approach with a time value that is already available in your application (for example, the time of the most recent news article, or the expiration time from the server-side caching system we saw in the last solution), you can take advantage of the web browser's cache. and unload the data transmission channel, saving information traffic from your site if possible and improving its performance.

Be careful when testing any caching done in this style, if you do it wrong you can cause your visitors to always have stale copies of your site.

Caching Your Pages in 5 Steps

Original: Posted in PHP / JavaScript by ibzi on the February 17th, 2007
Translation: Kuzma Feskov ( [email protected],http://kuzma.russofile.ru)

Caching your pages can be a nice and useful mechanism, especially if they are generated by PHP and do a lot of SQL queries. As soon as you apply caching, your server will immediately reduce the load and stop eating up a lot of memory to generate pages - it will simply load them from the cache. I'll show you how PHP can cache pages, and then you can spend 5 minutes doing it.


Consider the caching technology step by step:

  1. Create files in home directory .htaccess, start_cache.php, end_cache.php, as well as a folder named cache_files.
  2. Folder cache_files attributes must be set 777 .
  3. Inside .htaccess file, write the following lines: php_value auto_prepend_file /home/username/public_html/start_cache.php php_value auto_append_file /home/username/public_html/end_cache.php Line /home/username/public_html/ should be replaced with the path to your home directory.
  4. To the script start_cache.php put the following code:Don't forget to fix the path /home/username/public_html/ to the path to your home directory.
  5. And put the following code in the script end_cache.php:

All your pages will be cached for 3600 seconds = 1 hour. You can easily change this parameter in the script start_cache.php. The page cache will be saved in the folder cache_files.

It is clear that in this case the attributes 777 are a definite security breach. In this connection, I recommend to take out the folder cahce_files beyond the limits public_html, for example, put it one level up. This will close access to the files of your site users located in it, but will not affect the system's performance in any way.

Also, this method has another serious drawback: the author of the article puts the entire cache in one folder, which, with a sufficient number of pages on your site, will cause a problem, for example, on Unix systems, there is a sufficient slowdown in performance when there are more than 1000 files in the folder . In this connection, it is necessary to make a number of changes to the algorithm and decompose the files into separate subfolders inside the folder cache_files. For example, using the first 3-4 characters of the md5 cache for this.

For dynamic resources, it is quite possible to choose a caching time of a few (5-10) seconds or 1-2 minutes, which will already significantly reduce the load on the server, but will not harm the interactivity of the site.

For pages where interactivity is especially important, you can enter exceptions in .htaccess, which will allow them to constantly change, and caching can be used for other pages.

Content regeneration on the fly

Dynamically created but statically served pages, i.e. pages that should be transferred as purely static (read from the file system and then transferred on request), but they should be dynamically generated by the web server if they are not in the file system. So you can have PHP generated pages that are statically served unless someone (or the scheduler) removes the static content. In this case, the content is updated.

This is done with the following set of directives:

RewriteCond %(REQUEST_FILENAME) !-s RewriteRule ^page\.html$ page.php

Here, a request to page.html causes the corresponding page.php to be run internally if page.html is still missing or has zero size. The trick here is that page.php is just a regular PHP script that writes its output to the page.html file in addition to its own output. By running this once, the server sends the data to page.html. When the webmaster wants to update the content, he simply deletes page.html (usually via a cronjob).

Problem with page caching in Internet Explorer.

In IE, when working with the "Vary" header, there is one unpleasant error related to page caching. The problem is solved by adding the following lines to .htaccess:







2022 gtavrl.ru.