I am working on a test project involving the PHP's built-in web server and I am testing some ideas.
I want to implement my own caching mechanism for commonly used resources (png,jpg,json,txt, etc...) to reduce the load on the built-in server in php.
I start the built in server like this:
php -S 127.0.0.1:80 -t public router.php
So, the document root of the built-in server is set to public
and it runs the router.php
(as I am thinking of implementing a simple rewrite feature also).
Here's the contents of my router.php
file:
<?php
// Register request uri
$requestUri = isset($_SERVER['REQUEST_URI'])
? $_SERVER['REQUEST_URI']
: '/';
// Handle app resources with caching
if (preg_match('/\.(?:png|jpg|jpeg|gif|xml|json|css|eot|svg|otf|ttf|woff|woff2|scss|less|txt|ico)$/', $requestUri))
{
// Generate file name
$fileName = __DIR__ .'/public'. $requestUri;
// Parse file data
$lastModified = filemtime($fileName);
$etagFile = md5_file($fileName);
$ifModifiedSince = (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false);
$etagHeader = (isset($_SERVER['HTTP_IF_NONE_MATCH']) ? trim($_SERVER['HTTP_IF_NONE_MATCH']) : false);
// Set caching header
header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastModified) .' GMT');
header('Etag: '. $etagFile);
header('Cache-Control: public');
// Check if the requested resource has changed
if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $lastModified || $etagHeader == $etagFile)
{
// File has not changed
header('HTTP/1.1 304 Not Modified');
exit;
}
else
{
// Parse requested resource's mime type
$finfo = new finfo(FILEINFO_MIME);
$mime_type = $finfo->buffer(
file_get_contents($fileName, false, null, -1, 64),
FILEINFO_MIME_TYPE
);
// Serve requested resource
header('Content-Type: '. $mime_type);
header('Content-Length: '. filesize($fileName));
@readfile($fileName);
$finfo = null;
exit;
}
}
// Parse requested page & action
list ($page, $action) =
array_pad(array_values(array_filter(explode('/', $requestUri, 3), 'strlen')), 2, 'index');
if ($page == 'index') $page = 'server';
// Test - to do rest of routing
var_dump('page = '. $page);
var_dump('action = '. $action);
// include 'app/'. $page .'/'. $action .'.php';
?>
I tested the reource (png image) caching by visiting the following url: http://localhost/apple-icon-120x120.png
So, this is the first load of the resource, so serve returns the resource with HTTP 200
response as expected, takes approx 307ms
:
Now, if I press the F5
to reload the page, the server returns HTTP 304
(not modified) as expected and the request took approx 5ms
(great!!):
If I press F5
for the third time, the server still returns HTTP 304
(not modified) as expected, however this time the request took approx 306ms
again (as if the resource was not cached):
If I keep pressing F5
, the time to process the request is alternativing randomly between 5m
and approx 307ms
.
Any ideas why it's behaving like this? Once the resource is cached, shouldn't it constantly return 304
and process the request approx 5ms
? Why is the behaviour sporadic?
I do see that the returned content size is 225 bytes
(when it knows the data is cahced), I just can't figure out where the bottleneck is with the request processing time. My host machine is running windows with Intel i7 CPU, 6GB RAM & SSD drives.