Skip to content

Commit 87aea33

Browse files
add cache system and Tests for cache
1 parent 61e3298 commit 87aea33

File tree

6 files changed

+393
-34
lines changed

6 files changed

+393
-34
lines changed

composer.json

+16-4
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,34 @@
11
{
22
"name": "arishem/php-http-server",
3+
"version": "1.0.0",
4+
"minimum-stability": "dev",
5+
"prefer-stable": true,
36
"autoload": {
47
"psr-4": {
58
"PhpHttpServer\\": "src/",
6-
"PhpHttpServer\\Tests\\": "tests/"
9+
"PhpHttpServer\\Tests\\": "tests/"
710
}
811
},
912
"authors": [
1013
{
1114
"name": "Keshav Kumar",
12-
"email": "94639526+DeveloperKeshavKumar@users.noreply.github.com"
15+
"email": "[email protected]"
1316
}
1417
],
1518
"scripts": {
1619
"dev": "php public/index.php",
17-
"test":"./vendor/bin/phpunit"
20+
"test": "./vendor/bin/phpunit"
1821
},
1922
"require-dev": {
2023
"phpunit/phpunit": "^11.5"
24+
},
25+
"config": {
26+
"platform": {
27+
"php": "8.3"
28+
}
29+
},
30+
"repository": {
31+
"type": "git",
32+
"url": "git://github.com/yourusername/php-http-server.git"
2133
}
22-
}
34+
}

src/Cache/Cache.php

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<?php
2+
3+
namespace PhpHttpServer\Cache;
4+
5+
class Cache implements CacheInterface
6+
{
7+
private $cacheDir;
8+
private $maxSize; // Maximum number of items in the cache
9+
private $cache = []; // In-memory cache storage
10+
11+
public function __construct($cacheDir = __DIR__ . '/cache', $maxSize = 100)
12+
{
13+
$this->cacheDir = $cacheDir;
14+
$this->maxSize = $maxSize;
15+
16+
// Create the cache directory if it doesn't exist
17+
if (!file_exists($this->cacheDir)) {
18+
mkdir($this->cacheDir, 0755, true);
19+
}
20+
21+
// Load existing cache items from disk
22+
$this->loadCache();
23+
}
24+
25+
public function set($key, $value, $ttl = 3600)
26+
{
27+
if ($this->is_full()) {
28+
$this->evict(); // Evict expired or least recently used items
29+
}
30+
31+
$this->cache[$key] = [
32+
'data' => $value,
33+
'expires' => time() + $ttl
34+
];
35+
36+
$this->saveCache();
37+
}
38+
39+
public function get($key)
40+
{
41+
if ($this->exists($key)) {
42+
$item = $this->cache[$key];
43+
44+
// Check if the item has expired
45+
if (time() < $item['expires']) {
46+
return $item['data'];
47+
} else {
48+
// Item has expired, delete it
49+
$this->delete($key);
50+
}
51+
}
52+
53+
return null;
54+
}
55+
56+
public function delete($key)
57+
{
58+
if ($this->exists($key)) {
59+
// Remove the item from memory
60+
unset($this->cache[$key]);
61+
62+
// Remove the corresponding cache file
63+
$file = $this->getCacheFilePath($key);
64+
if (file_exists($file)) {
65+
unlink($file);
66+
}
67+
68+
$this->saveCache();
69+
}
70+
}
71+
72+
public function clear()
73+
{
74+
// Remove all items from memory
75+
$this->cache = [];
76+
77+
// Remove all cache files
78+
$files = glob($this->cacheDir . '/*.cache');
79+
foreach ($files as $file) {
80+
if (is_file($file)) {
81+
unlink($file);
82+
}
83+
}
84+
}
85+
86+
public function exists($key)
87+
{
88+
return array_key_exists($key, $this->cache);
89+
}
90+
91+
public function size()
92+
{
93+
return count($this->cache);
94+
}
95+
96+
public function evict()
97+
{
98+
foreach ($this->cache as $key => $item) {
99+
if (time() >= $item['expires']) {
100+
$this->delete($key);
101+
}
102+
}
103+
104+
// If the cache is still full, remove the oldest item
105+
if ($this->is_full()) {
106+
$oldestKey = array_key_first($this->cache);
107+
$this->delete($oldestKey);
108+
}
109+
}
110+
111+
public function update($key, $value)
112+
{
113+
if ($this->exists($key)) {
114+
$this->cache[$key]['data'] = $value;
115+
$this->cache[$key]['expires'] = time() + 3600; // Reset TTL
116+
$this->saveCache();
117+
}
118+
}
119+
120+
public function is_full()
121+
{
122+
return $this->size() >= $this->maxSize;
123+
}
124+
125+
private function loadCache()
126+
{
127+
$files = glob($this->cacheDir . '/*.cache');
128+
129+
foreach ($files as $file) {
130+
$data = file_get_contents($file);
131+
$cache = unserialize($data);
132+
133+
if (time() < $cache['expires']) {
134+
$key = basename($file, '.cache');
135+
$this->cache[$key] = $cache;
136+
} else {
137+
// Delete expired cache files
138+
unlink($file);
139+
}
140+
}
141+
}
142+
143+
public function getCacheFilePath($key)
144+
{
145+
return $this->cacheDir . '/' . md5($key) . '.cache';
146+
}
147+
148+
private function saveCache()
149+
{
150+
foreach ($this->cache as $key => $item) {
151+
$file = $this->getCacheFilePath($key);
152+
file_put_contents($file, serialize($item));
153+
}
154+
}
155+
}

src/Cache/CacheInterface.php

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace PhpHttpServer\Cache;
4+
5+
interface CacheInterface
6+
{
7+
/**
8+
* Store an item in the cache.
9+
*
10+
* @param string $key
11+
* @param mixed $value
12+
* @return void
13+
*/
14+
public function set($key, $value, $ttl);
15+
16+
/**
17+
* Retrieve an item from the cache by key.
18+
*
19+
* @param string $key
20+
* @return mixed|null
21+
*/
22+
public function get($key);
23+
24+
/**
25+
* Delete an item from the cache by key.
26+
*
27+
* @param string $key
28+
* @return void
29+
*/
30+
public function delete($key);
31+
32+
/**
33+
* Clear the entire cache.
34+
*
35+
* @return void
36+
*/
37+
public function clear();
38+
39+
/**
40+
* Check if an item exists in the cache by key.
41+
*
42+
* @param string $key
43+
* @return bool
44+
*/
45+
public function exists($key);
46+
47+
/**
48+
* Get the number of items in the cache.
49+
*
50+
* @return int
51+
*/
52+
public function size();
53+
54+
/**
55+
* Evict expired items from the cache.
56+
*
57+
* @return void
58+
*/
59+
public function evict();
60+
61+
/**
62+
* Update an item in the cache by key.
63+
*
64+
* @param string $key
65+
* @param mixed $value
66+
* @return void
67+
*/
68+
public function update($key, $value);
69+
70+
/**
71+
* Check if the cache is full.
72+
*
73+
* @return bool
74+
*/
75+
public function is_full();
76+
}

src/Core/Server.php

+20-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PhpHttpServer\WebSocket\WebSocketHandlerInterface;
66
use PhpHttpServer\Middleware\MiddlewareStack;
7+
use PhpHttpServer\Cache\CacheInterface;
78

89
class Server
910
{
@@ -14,19 +15,22 @@ class Server
1415
private $middlewareStack;
1516
private $webSocketHandler;
1617
private $clients = [];
18+
private $cache;
1719

1820
public function __construct(
1921
$host = '0.0.0.0',
2022
$port = 8080,
2123
RouterInterface $router,
2224
array $middlewareStack = [],
23-
WebSocketHandlerInterface $webSocketHandler = null
25+
WebSocketHandlerInterface $webSocketHandler = null,
26+
CacheInterface $cache = null
2427
) {
2528
$this->host = $host;
2629
$this->port = $port;
2730
$this->router = $router;
2831
$this->middlewareStack = $middlewareStack;
2932
$this->webSocketHandler = $webSocketHandler;
33+
$this->cache = $cache;
3034
}
3135

3236
public function getRouter()
@@ -124,6 +128,18 @@ private function handleHttpRequest($conn, Request $request)
124128
$route = $this->router->match($request->getMethod(), $request->getUri());
125129

126130
if ($route) {
131+
// Generate a unique cache key for the request
132+
$cacheKey = $request->getMethod() . ':' . $request->getUri();
133+
134+
// Try to get the response from the cache
135+
$cachedResponse = $this->cache->get($cacheKey);
136+
137+
if ($cachedResponse !== null) {
138+
// Serve the cached response
139+
$cachedResponse->send($conn);
140+
return;
141+
}
142+
127143
$response = new Response();
128144

129145
// Combine global and route-specific middleware
@@ -140,6 +156,9 @@ private function handleHttpRequest($conn, Request $request)
140156
call_user_func_array($route['handler'], [$request, $response, $route['params']]);
141157
});
142158

159+
// Cache the response for future requests
160+
$this->cache->set($cacheKey, $response, 60); // Cache for 60 seconds
161+
143162
// Send the response
144163
$response->send($conn);
145164
} else {

src/Middleware/ModifyRequestResponseMiddleware.php

-29
This file was deleted.

0 commit comments

Comments
 (0)