Skip to content

Commit f394a34

Browse files
committed
Allow cache files inside web root
Cache files now use PHP to avoid being readable. We also prevent access with .htaccess (for the common Apache setup).
1 parent 618a503 commit f394a34

4 files changed

Lines changed: 11 additions & 11 deletions

File tree

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Ignore config file in development
22
qa-config.php
3+
qa-cache/*/
34

45
# Other files
56
.DS_Store
@@ -9,5 +10,4 @@ qa-config.php
910
.Trashes
1011
ehthumbs.db
1112
Thumbs.db
12-
1313
.idea/

qa-cache/.htaccess

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Deny from all

qa-config-example.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,10 @@
8686
*/
8787

8888
/*
89-
If you wish to use caching, you must define QA_CACHE_DIRECTORY to store the cache files. The
90-
directory must be writable by the web server. It also must be OUTSIDE the public root. For
91-
example if your site resides in '/var/www/yoursite/public_html', then the cache directory could
92-
be '/var/www/yoursite/qa-cache', but it cannot be '/var/www/yoursite/public_html/qa-cache'.
89+
If you wish to use file-based caching, you must define QA_CACHE_DIRECTORY to store the cache
90+
files. The directory must be writable by the web server. For maximum security it's STRONGLY
91+
recommended to place the folder outside of the web root (so they can never be accessed via a
92+
web browser).
9393
9494
define('QA_CACHE_DIRECTORY', '/path/to/writable_cache_directory/');
9595
*/

qa-include/Q2A/Storage/FileCacheDriver.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class Q2A_Storage_FileCacheDriver implements Q2A_Storage_CacheDriver
3030
private $error;
3131
private $cacheDir;
3232

33+
private $phpProtect = '<?php header($_SERVER[\'SERVER_PROTOCOL\'].\' 404 Not Found\'); die; ?>';
34+
3335
/**
3436
* Creates a new FileCache instance and checks we can write to the cache directory.
3537
* @param array $config Configuration data, including cache storage directory.
@@ -46,12 +48,8 @@ public function __construct($config)
4648

4749
if (isset($config['dir'])) {
4850
$this->cacheDir = realpath($config['dir']);
49-
5051
if (!is_writable($this->cacheDir)) {
5152
$this->error = qa_lang_html_sub('admin/caching_dir_error', $config['dir']);
52-
} elseif (strpos($this->cacheDir, realpath($_SERVER['DOCUMENT_ROOT'])) === 0 || strpos($this->cacheDir, realpath(QA_BASE_DIR)) === 0) {
53-
// check the folder is outside the public root - checks against server root and Q2A root, in order to handle symbolic links
54-
$this->error = qa_lang_html_sub('admin/caching_dir_public', $config['dir']);
5553
}
5654
} else {
5755
$this->error = qa_lang_html('admin/caching_dir_missing');
@@ -77,6 +75,7 @@ public function get($key)
7775

7876
if (is_readable($file)) {
7977
$lines = file($file, FILE_IGNORE_NEW_LINES);
78+
$skipLine = array_shift($lines);
8079
$actualKey = array_shift($lines);
8180

8281
// double check this is the correct data
@@ -114,7 +113,7 @@ public function set($key, $data, $ttl)
114113
if ($this->enabled && $ttl > 0) {
115114
$encData = serialize($data);
116115
$expiry = time() + ($ttl * 60);
117-
$cache = $fullKey . "\n" . $expiry . "\n" . $encData;
116+
$cache = $this->phpProtect . "\n" . $fullKey . "\n" . $expiry . "\n" . $encData;
118117

119118
$file = $this->getFilename($fullKey);
120119
$dir = dirname($file);
@@ -279,6 +278,6 @@ private function deleteFile($file)
279278
private function getFilename($fullKey)
280279
{
281280
$filename = sha1($fullKey);
282-
return $this->cacheDir . '/' . substr($filename, 0, 1) . '/' . substr($filename, 1, 2) . '/' . $filename;
281+
return $this->cacheDir . '/' . substr($filename, 0, 1) . '/' . substr($filename, 1, 2) . '/' . $filename . '.php';
283282
}
284283
}

0 commit comments

Comments
 (0)