|
1
|
|
|
<?php |
|
2
|
|
|
// This file is part of BOINC. |
|
3
|
|
|
// http://boinc.berkeley.edu |
|
4
|
|
|
// Copyright (C) 2008 University of California |
|
5
|
|
|
// |
|
6
|
|
|
// BOINC is free software; you can redistribute it and/or modify it |
|
7
|
|
|
// under the terms of the GNU Lesser General Public License |
|
8
|
|
|
// as published by the Free Software Foundation, |
|
9
|
|
|
// either version 3 of the License, or (at your option) any later version. |
|
10
|
|
|
// |
|
11
|
|
|
// BOINC is distributed in the hope that it will be useful, |
|
12
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
14
|
|
|
// See the GNU Lesser General Public License for more details. |
|
15
|
|
|
// |
|
16
|
|
|
// You should have received a copy of the GNU Lesser General Public License |
|
17
|
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>. |
|
18
|
|
|
|
|
19
|
|
|
// mechanism for caching commonly-accessed pages |
|
20
|
|
|
|
|
21
|
|
|
require_once("../project/cache_parameters.inc"); |
|
22
|
|
|
|
|
23
|
|
|
// If we can't see request headers, don't do caching |
|
24
|
|
|
// |
|
25
|
|
|
$no_cache = false; |
|
26
|
|
|
if (!function_exists("apache_request_headers")) { |
|
27
|
|
|
$no_cache = true; |
|
28
|
|
|
} |
|
29
|
|
|
|
|
30
|
|
|
function make_cache_dirs() { |
|
31
|
|
|
if (!@filemtime("../cache")) { |
|
32
|
|
|
mkdir("../cache", 0770); |
|
33
|
|
|
chmod("../cache", 0770); |
|
34
|
|
|
} |
|
35
|
|
|
for ($i=0;$i<256;$i++) { |
|
36
|
|
|
$j=sprintf("%02x",$i); |
|
37
|
|
|
if (!@filemtime("../cache/$j")) { |
|
38
|
|
|
mkdir("../cache/$j", 0770); |
|
39
|
|
|
chmod("../cache/$j", 0770); |
|
40
|
|
|
} |
|
41
|
|
|
} |
|
42
|
|
|
} |
|
43
|
|
|
|
|
44
|
|
|
function get_path($params, $phpfile=null) { |
|
45
|
|
|
if (!@filemtime("../cache/00")) make_cache_dirs(); |
|
46
|
|
|
if ($phpfile) { |
|
47
|
|
|
$z = $phpfile; |
|
48
|
|
|
} else { |
|
49
|
|
|
$y = pathinfo($_SERVER["PHP_SELF"]); |
|
50
|
|
|
$z = $y["basename"]; |
|
51
|
|
|
} |
|
52
|
|
|
|
|
53
|
|
|
// add a layer of subdirectories for reducing file lookup time |
|
54
|
|
|
$sz = substr(md5($z."_".urlencode($params)),1,2); |
|
55
|
|
|
$path = "../cache/".$sz."/".$z; |
|
56
|
|
|
if ($params) { |
|
57
|
|
|
$path = $path."_".urlencode($params); |
|
58
|
|
|
} |
|
59
|
|
|
return $path; |
|
60
|
|
|
} |
|
61
|
|
|
|
|
62
|
|
|
function disk_usage($dir) { |
|
63
|
|
|
$usage=0; |
|
64
|
|
|
if ($handle=@opendir($dir)) { |
|
65
|
|
|
while ($file=readdir($handle)) { |
|
66
|
|
|
if (($file != ".") && ($file != "..")) { |
|
67
|
|
|
if (@is_dir($dir."/".$file)) { |
|
68
|
|
|
$usage+=disk_usage($dir."/".$file); |
|
69
|
|
|
} else { |
|
70
|
|
|
$usage+=@filesize($dir."/".$file); |
|
71
|
|
|
} |
|
72
|
|
|
} |
|
73
|
|
|
} |
|
74
|
|
|
@closedir($handle); |
|
|
|
|
|
|
75
|
|
|
} |
|
76
|
|
|
return $usage; |
|
77
|
|
|
} |
|
78
|
|
|
|
|
79
|
|
|
function clean_cache($max_age, $dir) { |
|
80
|
|
|
$start_dir = getcwd(); |
|
81
|
|
|
if (!chdir($dir)) { |
|
82
|
|
|
return; |
|
83
|
|
|
} |
|
84
|
|
|
if ($handle=@opendir(".")) { |
|
85
|
|
|
while ($file=readdir($handle)) { |
|
86
|
|
|
if ($file == ".") continue; |
|
87
|
|
|
if ($file == "..") continue; |
|
88
|
|
|
|
|
89
|
|
|
// don't let hackers trick us into deleting other files! |
|
90
|
|
|
if (strstr($file, "..")) { |
|
91
|
|
|
continue; |
|
92
|
|
|
} |
|
93
|
|
|
if (@is_dir($file)) { |
|
94
|
|
|
clean_cache($max_age, $file); |
|
95
|
|
|
} else { |
|
96
|
|
|
if ((time()-@filemtime($file))>$max_age) { |
|
97
|
|
|
//echo "unlinking ".getcwd()."/$file\n"; |
|
98
|
|
|
@unlink($file); |
|
|
|
|
|
|
99
|
|
|
} |
|
100
|
|
|
} |
|
101
|
|
|
} |
|
102
|
|
|
@closedir($handle); |
|
|
|
|
|
|
103
|
|
|
} |
|
104
|
|
|
chdir($start_dir); |
|
105
|
|
|
} |
|
106
|
|
|
|
|
107
|
|
|
|
|
108
|
|
|
// check cache size every once in a while, purge if too big |
|
109
|
|
|
// |
|
110
|
|
|
function cache_check_diskspace(){ |
|
111
|
|
|
if ((rand() % CACHE_SIZE_CHECK_FREQ)) return; |
|
112
|
|
|
if (disk_usage("../cache") < MAX_CACHE_USAGE) return; |
|
113
|
|
|
$x = max(TEAM_PAGE_TTL, USER_PAGE_TTL, USER_HOST_TTL, |
|
114
|
|
|
USER_PROFILE_TTL, TOP_PAGES_TTL, INDEX_PAGE_TTL |
|
115
|
|
|
); |
|
116
|
|
|
clean_cache($x, "../cache"); |
|
117
|
|
|
} |
|
118
|
|
|
|
|
119
|
|
|
function cache_need_to_regenerate($path, $max_age){ |
|
120
|
|
|
$regenerate = false; |
|
121
|
|
|
$request = apache_request_headers(); |
|
122
|
|
|
|
|
123
|
|
|
clearstatcache(); |
|
124
|
|
|
$lastmodified = @filemtime($path); |
|
125
|
|
|
if ($lastmodified) { |
|
|
|
|
|
|
126
|
|
|
// See if cached copy is too old. |
|
127
|
|
|
// If so regenerate, |
|
128
|
|
|
// and touch the cached copy so other processes |
|
129
|
|
|
// don't regenerate at the same time |
|
130
|
|
|
// |
|
131
|
|
|
if ($lastmodified<time()-$max_age) { |
|
132
|
|
|
$regenerate = true; |
|
133
|
|
|
@touch($path); |
|
|
|
|
|
|
134
|
|
|
} |
|
135
|
|
|
} else { |
|
136
|
|
|
$regenerate = true; |
|
137
|
|
|
} |
|
138
|
|
|
return $regenerate; |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
// Returns cached data or false if nothing was found |
|
142
|
|
|
function get_cached_data($max_age, $params=""){ |
|
143
|
|
|
global $no_cache; |
|
144
|
|
|
|
|
145
|
|
|
if ($no_cache) return false; |
|
146
|
|
|
|
|
147
|
|
|
$path = get_path($params); |
|
148
|
|
|
if ($max_age) { |
|
149
|
|
|
if (defined('MEMCACHE_SERVERS')) { |
|
150
|
|
|
$cache = BoincMemcache::get()->get($path); |
|
151
|
|
|
if (isset($cache['content'])) { |
|
152
|
|
|
return $cache['content']; |
|
153
|
|
|
} else { |
|
154
|
|
|
return $cache; |
|
155
|
|
|
} |
|
156
|
|
|
} else { |
|
157
|
|
|
cache_check_diskspace(); |
|
158
|
|
|
$regenerate=cache_need_to_regenerate($path, $max_age); |
|
159
|
|
|
if (!$regenerate) { |
|
160
|
|
|
return file_get_contents($path); |
|
161
|
|
|
} |
|
162
|
|
|
} |
|
163
|
|
|
} |
|
164
|
|
|
return false; //No data was cached, just return |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
// DEPRECATED |
|
168
|
|
|
function start_cache($max_age, $params=""){ |
|
169
|
|
|
global $no_cache, $caching, $memcache; |
|
170
|
|
|
|
|
171
|
|
|
if ($no_cache) return; |
|
172
|
|
|
$caching = true; |
|
173
|
|
|
|
|
174
|
|
|
if ($max_age) { |
|
175
|
|
|
$path = get_path($params); |
|
176
|
|
|
$cache = null; |
|
177
|
|
|
if (defined('MEMCACHE_SERVERS')) { |
|
178
|
|
|
$cache = BoincMemcache::get()->get($path); |
|
179
|
|
|
if ($cache) { |
|
180
|
|
|
$regenerate = false; |
|
181
|
|
|
$lastmodified = abs($cache->timestamp); |
|
182
|
|
|
} else { |
|
183
|
|
|
$regenerate = true; |
|
184
|
|
|
} |
|
185
|
|
|
} else { |
|
186
|
|
|
$lastmodified = @filemtime($path); |
|
187
|
|
|
cache_check_diskspace(); //Check free disk space once in a while |
|
188
|
|
|
$regenerate = cache_need_to_regenerate($path, $max_age); |
|
189
|
|
|
} |
|
190
|
|
|
//Is the stored version too old, do we need to regenerate it? |
|
191
|
|
|
if ($regenerate){ |
|
192
|
|
|
// If cached version is too old (or non-existent) |
|
193
|
|
|
// generate the page and write to cache |
|
194
|
|
|
// |
|
195
|
|
|
ob_start(); |
|
196
|
|
|
ob_implicit_flush(0); |
|
197
|
|
|
Header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); |
|
198
|
|
|
Header("Expires: " . gmdate("D, d M Y H:i:s",time()+$max_age) . " GMT"); |
|
199
|
|
|
Header("Cache-Control: public, max-age=" . $max_age); |
|
200
|
|
|
|
|
201
|
|
|
// allow the calling page to see cache period |
|
202
|
|
|
// |
|
203
|
|
|
global $cached_max_age; |
|
204
|
|
|
$cached_max_age = $max_age; |
|
205
|
|
|
} else { |
|
206
|
|
|
// Otherwise serve the cached version and exit |
|
207
|
|
|
// |
|
208
|
|
|
if (strstr($params, "format=xml")) { |
|
209
|
|
|
header('Content-type: text/xml'); |
|
210
|
|
|
} |
|
211
|
|
|
Header("Last-Modified: " . gmdate("D, d M Y H:i:s",$lastmodified) . " GMT"); |
|
|
|
|
|
|
212
|
|
|
Header("Expires: " . gmdate("D, d M Y H:i:s",$lastmodified+$max_age) . " GMT"); |
|
213
|
|
|
Header("Cache-Control: public, max-age=" . $max_age ); |
|
214
|
|
|
if ($cache && $cache->content) { |
|
215
|
|
|
echo $cache->content; |
|
216
|
|
|
exit; |
|
|
|
|
|
|
217
|
|
|
} |
|
218
|
|
|
if (!@readfile($path)) { |
|
219
|
|
|
//echo "can't read $path; lastmod $lastmodified\n"; |
|
220
|
|
|
@unlink($path); |
|
|
|
|
|
|
221
|
|
|
//Proceed to regenerate content |
|
222
|
|
|
} else { |
|
223
|
|
|
exit; |
|
|
|
|
|
|
224
|
|
|
} |
|
225
|
|
|
} |
|
226
|
|
|
} |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
// write output buffer both to client and to cache |
|
230
|
|
|
// DEPRECATED |
|
231
|
|
|
function end_cache($max_age,$params=""){ |
|
232
|
|
|
global $no_cache; |
|
233
|
|
|
if ($no_cache) return; |
|
234
|
|
|
|
|
235
|
|
|
// for the benefit of hackers |
|
236
|
|
|
if (strstr($params, "..")) { |
|
237
|
|
|
return; |
|
238
|
|
|
} |
|
239
|
|
|
if ($max_age) { |
|
240
|
|
|
$path = get_path($params); |
|
241
|
|
|
|
|
242
|
|
|
if (defined('MEMCACHE_SERVERS')) { |
|
243
|
|
|
$cache = array('content' => ob_get_contents(), 'timestamp' => time()); |
|
244
|
|
|
ob_end_flush(); |
|
245
|
|
|
$cache = BoincMemcache::get()->set($path, $cache, $max_age); |
|
246
|
|
|
} else { |
|
247
|
|
|
$fhandle = fopen($path, "w"); |
|
248
|
|
|
$page = ob_get_contents(); |
|
249
|
|
|
ob_end_flush(); |
|
250
|
|
|
fwrite($fhandle, $page); |
|
251
|
|
|
fclose($fhandle); |
|
252
|
|
|
} |
|
253
|
|
|
} |
|
254
|
|
|
} |
|
255
|
|
|
|
|
256
|
|
|
function set_cached_data($max_age, $data, $params=""){ |
|
257
|
|
|
// for the benefit of hackers |
|
258
|
|
|
if (strstr($params, "..")) { |
|
259
|
|
|
return "bad params"; |
|
260
|
|
|
} |
|
261
|
|
|
$path = get_path($params); |
|
262
|
|
|
if (defined('MEMCACHE_SERVERS')) { |
|
263
|
|
|
$cache = array('content' => $data, 'timestamp' => time()); |
|
264
|
|
|
BoincMemcache::get()->set($path, $cache, $max_age); |
|
265
|
|
|
} else { |
|
266
|
|
|
$fhandle = @fopen($path, "w"); |
|
267
|
|
|
if (!$fhandle) { |
|
|
|
|
|
|
268
|
|
|
return "can't open $path"; |
|
269
|
|
|
} |
|
270
|
|
|
fwrite($fhandle, $data); |
|
271
|
|
|
fclose($fhandle); |
|
272
|
|
|
} |
|
273
|
|
|
return ""; |
|
274
|
|
|
} |
|
275
|
|
|
|
|
276
|
|
|
function clear_cache_entry($phpfile, $params) { |
|
277
|
|
|
if (strstr($phpfile, "..")) { |
|
278
|
|
|
return; |
|
279
|
|
|
} |
|
280
|
|
|
if (strstr($params, "..")) { |
|
281
|
|
|
return; |
|
282
|
|
|
} |
|
283
|
|
|
$path = get_path($params, $phpfile); |
|
284
|
|
|
@unlink($path); |
|
|
|
|
|
|
285
|
|
|
} |
|
286
|
|
|
|
|
287
|
|
|
// Memcached class |
|
288
|
|
|
class BoincMemcache { |
|
289
|
|
|
static $instance; |
|
290
|
|
|
|
|
291
|
|
|
static function get() { |
|
292
|
|
|
self::$instance = new Memcached; |
|
293
|
|
|
if (defined('MEMCACHE_PREFIX')) { |
|
294
|
|
|
self::$instance->setOption(Memcached::OPT_PREFIX_KEY, MEMCACHE_PREFIX); |
|
295
|
|
|
} |
|
296
|
|
|
$server_arr = array(); |
|
297
|
|
|
$servers = explode('|', MEMCACHE_SERVERS); |
|
298
|
|
|
foreach($servers as &$server) { |
|
299
|
|
|
list($ip, $port, $weight) = explode(':', $server); |
|
300
|
|
|
if (!$port) { $port = 11211; } |
|
301
|
|
|
$server_arr[] = array($ip, $port, $weight); |
|
302
|
|
|
} |
|
303
|
|
|
self::$instance->addServers($server_arr); |
|
304
|
|
|
return self::$instance; |
|
305
|
|
|
} |
|
306
|
|
|
} |
|
307
|
|
|
|
|
308
|
|
|
?> |
|
309
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.