-
Notifications
You must be signed in to change notification settings - Fork 12
/
fast_file_responder.php
184 lines (170 loc) · 4.68 KB
/
fast_file_responder.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<?php
/**
* PHP versions 5
*
* phTagr : Organize, Browse, and Share Your Photos.
* Copyright 2006-2013, Sebastian Felis ([email protected])
*
* Licensed under The GPL-2.0 License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2006-2013, Sebastian Felis ([email protected])
* @link http://www.phtagr.org phTagr
* @package Phtagr
* @since phTagr 2.2b3
* @license GPL-2.0 (http://www.opensource.org/licenses/GPL-2.0)
*/
/**
* This class enables a fast file response without the framework stack of
* CakePHP. It checks the session and the URL and returns a valid file
*/
class FastFileResponder {
/** Should be same as in app/config/core.php Session.cookie */
var $sessionCookie = 'phtagrSession';
var $sessionKey = 'fastFile';
var $items = array();
function __construct() {
$this->startSession();
}
/**
* Starts the session if the session sessionCookie is set
*/
function startSession() {
if (!isset($_COOKIE[$this->sessionCookie])) {
return;
}
session_id($_COOKIE[$this->sessionCookie]);
session_name($this->sessionCookie);
session_start();
if (isset($_SESSION[$this->sessionKey])) {
$this->items = (array) $_SESSION[$this->sessionKey]['items'];
$this->deleteExpiredItems();
}
}
/**
* Deletes expired itemes from the session list
*/
function deleteExpiredItems() {
if (!count($this->items)) {
return;
}
$now = time();
foreach ($this->items as $key => $item) {
if ($item['expires'] < $now) {
unset($_SESSION[$this->sessionKey][$key]);
}
}
}
/**
* Simple log function for debug purpos
*/
function log($msg) {
$h = @fopen(dirname(__FILE__) . DS . 'fast_file_responder.log', 'a');
@fwrite($h, sprintf("%s %s\n", date('Y-M-d h:i:s', time()), $msg));
@fclose($h);
}
/**
* Extracts the item key from the url and returns it. Returns false if no
* key could be found
*/
function getItemKey($url) {
if (!preg_match('/.*media\/(\w+)\/(\d+)/', $url, $matches)) {
return false;
}
return $matches[1] . '-' . $matches[2];
}
/**
* Returns the file of the media request
*/
function getFilename($url) {
$key = $this->getItemKey($url);
if (!$key || !isset($this->items[$key])) {
return false;
}
$item = $this->items[$key];
if ($item['expires'] < time() || !is_readable($item['file'])) {
return false;
}
return $item['file'];
}
/**
* Returns an array of request headers
*/
function getRequestHeaders() {
$headers = array();
if (function_exists('apache_request_headers')) {
$headers = apache_request_headers();
foreach($headers as $h => $v) {
$headers[strtolower($h)] = $v;
}
} else {
$headers = array();
foreach($_SERVER as $h => $v) {
if(preg_match('/^HTTP_(.+)/', $h, $hp)) {
$headers[strtolower($hp[1])] = $v;
}
}
}
return $headers;
}
/**
* Evaluates the client file cache and response if the client has still a
* valid file
*
* @param filename Current cache file
*/
function checkClientCache($filename) {
$cacheTime = filemtime($filename);
$headers = $this->getRequestHeaders();
if (isset($headers['if-modified-since']) &&
(strtotime($headers['if-modified-since']) == $cacheTime)) {
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $cacheTime).' GMT', true, 304);
// Allow further caching for 30 days
header('Cache-Control: max-age=2592000, must-revalidate');
exit;
}
}
function sendResponseHeaders($file) {
$fileSize = @filesize($file);
header('Content-Type: image/jpg');
header('Content-Length: ' . $fileSize);
header('Cache-Control: max-age=2592000, must-revalidate');
header('Pragma: cache');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime($file)));
}
/**
* Evaluates if a valid cache file exists
*/
function exists($url) {
return $this->getFilename($url) != false;
}
/**
* Sends the cache file if it exists and exit. If it returns an error
* occured
*/
function send($url) {
$filename = $this->getFilename($url);
if (!$filename) {
return false;
}
$this->checkClientCache($filename);
$this->sendResponseHeaders($filename);
$chunkSize = 1024;
$buffer = '';
$handle = fopen($filename, 'rb');
while (!feof($handle)) {
$buffer = fread($handle, $chunkSize);
echo $buffer;
}
fclose($handle);
//$this->log("File send: $filename");
exit(0);
}
/**
* Closes the session
*/
function close() {
session_write_close();
}
}
?>