[ Index ] |
PHP Cross Reference of phpBB-3.1.12-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * This file is part of the phpBB Forum Software package. 5 * 6 * @copyright (c) phpBB Limited <https://www.phpbb.com> 7 * @license GNU General Public License, version 2 (GPL-2.0) 8 * 9 * For full copyright and license information, please see 10 * the docs/CREDITS.txt file. 11 * 12 */ 13 14 namespace phpbb\cache\driver; 15 16 /** 17 * ACM File Based Caching 18 */ 19 class file extends \phpbb\cache\driver\base 20 { 21 var $var_expires = array(); 22 23 /** 24 * Set cache path 25 * 26 * @param string $cache_dir Define the path to the cache directory (default: $phpbb_root_path . 'cache/') 27 */ 28 function __construct($cache_dir = null) 29 { 30 global $phpbb_root_path; 31 $this->cache_dir = !is_null($cache_dir) ? $cache_dir : $phpbb_root_path . 'cache/'; 32 } 33 34 /** 35 * {@inheritDoc} 36 */ 37 function load() 38 { 39 return $this->_read('data_global'); 40 } 41 42 /** 43 * {@inheritDoc} 44 */ 45 function unload() 46 { 47 parent::unload(); 48 unset($this->var_expires); 49 $this->var_expires = array(); 50 } 51 52 /** 53 * {@inheritDoc} 54 */ 55 function save() 56 { 57 if (!$this->is_modified) 58 { 59 return; 60 } 61 62 global $phpEx; 63 64 if (!$this->_write('data_global')) 65 { 66 if (!function_exists('phpbb_is_writable')) 67 { 68 global $phpbb_root_path; 69 include($phpbb_root_path . 'includes/functions.' . $phpEx); 70 } 71 72 // Now, this occurred how often? ... phew, just tell the user then... 73 if (!phpbb_is_writable($this->cache_dir)) 74 { 75 // We need to use die() here, because else we may encounter an infinite loop (the message handler calls $cache->unload()) 76 die('Fatal: ' . $this->cache_dir . ' is NOT writable.'); 77 exit; 78 } 79 80 die('Fatal: Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx); 81 exit; 82 } 83 84 $this->is_modified = false; 85 } 86 87 /** 88 * {@inheritDoc} 89 */ 90 function tidy() 91 { 92 global $phpEx; 93 94 $dir = @opendir($this->cache_dir); 95 96 if (!$dir) 97 { 98 return; 99 } 100 101 $time = time(); 102 103 while (($entry = readdir($dir)) !== false) 104 { 105 if (!preg_match('/^(sql_|data_(?!global))/', $entry)) 106 { 107 continue; 108 } 109 110 if (!($handle = @fopen($this->cache_dir . $entry, 'rb'))) 111 { 112 continue; 113 } 114 115 // Skip the PHP header 116 fgets($handle); 117 118 // Skip expiration 119 $expires = (int) fgets($handle); 120 121 fclose($handle); 122 123 if ($time >= $expires) 124 { 125 $this->remove_file($this->cache_dir . $entry); 126 } 127 } 128 closedir($dir); 129 130 if (file_exists($this->cache_dir . 'data_global.' . $phpEx)) 131 { 132 if (!sizeof($this->vars)) 133 { 134 $this->load(); 135 } 136 137 foreach ($this->var_expires as $var_name => $expires) 138 { 139 if ($time >= $expires) 140 { 141 $this->destroy($var_name); 142 } 143 } 144 } 145 146 set_config('cache_last_gc', time(), true); 147 } 148 149 /** 150 * {@inheritDoc} 151 */ 152 function get($var_name) 153 { 154 if ($var_name[0] == '_') 155 { 156 if (!$this->_exists($var_name)) 157 { 158 return false; 159 } 160 161 return $this->_read('data' . $var_name); 162 } 163 else 164 { 165 return ($this->_exists($var_name)) ? $this->vars[$var_name] : false; 166 } 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 function put($var_name, $var, $ttl = 31536000) 173 { 174 if ($var_name[0] == '_') 175 { 176 $this->_write('data' . $var_name, $var, time() + $ttl); 177 } 178 else 179 { 180 $this->vars[$var_name] = $var; 181 $this->var_expires[$var_name] = time() + $ttl; 182 $this->is_modified = true; 183 } 184 } 185 186 /** 187 * {@inheritDoc} 188 */ 189 function purge() 190 { 191 parent::purge(); 192 $this->var_expires = array(); 193 } 194 195 /** 196 * {@inheritDoc} 197 */ 198 function destroy($var_name, $table = '') 199 { 200 global $phpEx; 201 202 if ($var_name == 'sql' && !empty($table)) 203 { 204 if (!is_array($table)) 205 { 206 $table = array($table); 207 } 208 209 $dir = @opendir($this->cache_dir); 210 211 if (!$dir) 212 { 213 return; 214 } 215 216 while (($entry = readdir($dir)) !== false) 217 { 218 if (strpos($entry, 'sql_') !== 0) 219 { 220 continue; 221 } 222 223 if (!($handle = @fopen($this->cache_dir . $entry, 'rb'))) 224 { 225 continue; 226 } 227 228 // Skip the PHP header 229 fgets($handle); 230 231 // Skip expiration 232 fgets($handle); 233 234 // Grab the query, remove the LF 235 $query = substr(fgets($handle), 0, -1); 236 237 fclose($handle); 238 239 foreach ($table as $check_table) 240 { 241 // Better catch partial table names than no table names. ;) 242 if (strpos($query, $check_table) !== false) 243 { 244 $this->remove_file($this->cache_dir . $entry); 245 break; 246 } 247 } 248 } 249 closedir($dir); 250 251 return; 252 } 253 254 if (!$this->_exists($var_name)) 255 { 256 return; 257 } 258 259 if ($var_name[0] == '_') 260 { 261 $this->remove_file($this->cache_dir . 'data' . $var_name . ".$phpEx", true); 262 } 263 else if (isset($this->vars[$var_name])) 264 { 265 $this->is_modified = true; 266 unset($this->vars[$var_name]); 267 unset($this->var_expires[$var_name]); 268 269 // We save here to let the following cache hits succeed 270 $this->save(); 271 } 272 } 273 274 /** 275 * {@inheritDoc} 276 */ 277 function _exists($var_name) 278 { 279 if ($var_name[0] == '_') 280 { 281 global $phpEx; 282 $var_name = $this->clean_varname($var_name); 283 return file_exists($this->cache_dir . 'data' . $var_name . ".$phpEx"); 284 } 285 else 286 { 287 if (!sizeof($this->vars)) 288 { 289 $this->load(); 290 } 291 292 if (!isset($this->var_expires[$var_name])) 293 { 294 return false; 295 } 296 297 return (time() > $this->var_expires[$var_name]) ? false : isset($this->vars[$var_name]); 298 } 299 } 300 301 /** 302 * {@inheritDoc} 303 */ 304 function sql_save(\phpbb\db\driver\driver_interface $db, $query, $query_result, $ttl) 305 { 306 // Remove extra spaces and tabs 307 $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); 308 309 $query_id = sizeof($this->sql_rowset); 310 $this->sql_rowset[$query_id] = array(); 311 $this->sql_row_pointer[$query_id] = 0; 312 313 while ($row = $db->sql_fetchrow($query_result)) 314 { 315 $this->sql_rowset[$query_id][] = $row; 316 } 317 $db->sql_freeresult($query_result); 318 319 if ($this->_write('sql_' . md5($query), $this->sql_rowset[$query_id], $ttl + time(), $query)) 320 { 321 return $query_id; 322 } 323 324 return $query_result; 325 } 326 327 /** 328 * Read cached data from a specified file 329 * 330 * @access private 331 * @param string $filename Filename to write 332 * @return mixed False if an error was encountered, otherwise the data type of the cached data 333 */ 334 function _read($filename) 335 { 336 global $phpEx; 337 338 $filename = $this->clean_varname($filename); 339 $file = "{$this->cache_dir}$filename.$phpEx"; 340 341 $type = substr($filename, 0, strpos($filename, '_')); 342 343 if (!file_exists($file)) 344 { 345 return false; 346 } 347 348 if (!($handle = @fopen($file, 'rb'))) 349 { 350 return false; 351 } 352 353 // Skip the PHP header 354 fgets($handle); 355 356 if ($filename == 'data_global') 357 { 358 $this->vars = $this->var_expires = array(); 359 360 $time = time(); 361 362 while (($expires = (int) fgets($handle)) && !feof($handle)) 363 { 364 // Number of bytes of data 365 $bytes = substr(fgets($handle), 0, -1); 366 367 if (!is_numeric($bytes) || ($bytes = (int) $bytes) === 0) 368 { 369 // We cannot process the file without a valid number of bytes 370 // so we discard it 371 fclose($handle); 372 373 $this->vars = $this->var_expires = array(); 374 $this->is_modified = false; 375 376 $this->remove_file($file); 377 378 return false; 379 } 380 381 if ($time >= $expires) 382 { 383 fseek($handle, $bytes, SEEK_CUR); 384 385 continue; 386 } 387 388 $var_name = substr(fgets($handle), 0, -1); 389 390 // Read the length of bytes that consists of data. 391 $data = fread($handle, $bytes - strlen($var_name)); 392 $data = @unserialize($data); 393 394 // Don't use the data if it was invalid 395 if ($data !== false) 396 { 397 $this->vars[$var_name] = $data; 398 $this->var_expires[$var_name] = $expires; 399 } 400 401 // Absorb the LF 402 fgets($handle); 403 } 404 405 fclose($handle); 406 407 $this->is_modified = false; 408 409 return true; 410 } 411 else 412 { 413 $data = false; 414 $line = 0; 415 416 while (($buffer = fgets($handle)) && !feof($handle)) 417 { 418 $buffer = substr($buffer, 0, -1); // Remove the LF 419 420 // $buffer is only used to read integers 421 // if it is non numeric we have an invalid 422 // cache file, which we will now remove. 423 if (!is_numeric($buffer)) 424 { 425 break; 426 } 427 428 if ($line == 0) 429 { 430 $expires = (int) $buffer; 431 432 if (time() >= $expires) 433 { 434 break; 435 } 436 437 if ($type == 'sql') 438 { 439 // Skip the query 440 fgets($handle); 441 } 442 } 443 else if ($line == 1) 444 { 445 $bytes = (int) $buffer; 446 447 // Never should have 0 bytes 448 if (!$bytes) 449 { 450 break; 451 } 452 453 // Grab the serialized data 454 $data = fread($handle, $bytes); 455 456 // Read 1 byte, to trigger EOF 457 fread($handle, 1); 458 459 if (!feof($handle)) 460 { 461 // Somebody tampered with our data 462 $data = false; 463 } 464 break; 465 } 466 else 467 { 468 // Something went wrong 469 break; 470 } 471 $line++; 472 } 473 fclose($handle); 474 475 // unserialize if we got some data 476 $data = ($data !== false) ? @unserialize($data) : $data; 477 478 if ($data === false) 479 { 480 $this->remove_file($file); 481 return false; 482 } 483 484 return $data; 485 } 486 } 487 488 /** 489 * Write cache data to a specified file 490 * 491 * 'data_global' is a special case and the generated format is different for this file: 492 * <code> 493 * <?php exit; ?> 494 * (expiration) 495 * (length of var and serialised data) 496 * (var) 497 * (serialised data) 498 * ... (repeat) 499 * </code> 500 * 501 * The other files have a similar format: 502 * <code> 503 * <?php exit; ?> 504 * (expiration) 505 * (query) [SQL files only] 506 * (length of serialised data) 507 * (serialised data) 508 * </code> 509 * 510 * @access private 511 * @param string $filename Filename to write 512 * @param mixed $data Data to store 513 * @param int $expires Timestamp when the data expires 514 * @param string $query Query when caching SQL queries 515 * @return bool True if the file was successfully created, otherwise false 516 */ 517 function _write($filename, $data = null, $expires = 0, $query = '') 518 { 519 global $phpEx; 520 521 $filename = $this->clean_varname($filename); 522 $file = "{$this->cache_dir}$filename.$phpEx"; 523 524 $lock = new \phpbb\lock\flock($file); 525 $lock->acquire(); 526 527 if ($handle = @fopen($file, 'wb')) 528 { 529 // File header 530 fwrite($handle, '<' . '?php exit; ?' . '>'); 531 532 if ($filename == 'data_global') 533 { 534 // Global data is a different format 535 foreach ($this->vars as $var => $data) 536 { 537 if (strpos($var, "\r") !== false || strpos($var, "\n") !== false) 538 { 539 // CR/LF would cause fgets() to read the cache file incorrectly 540 // do not cache test entries, they probably won't be read back 541 // the cache keys should really be alphanumeric with a few symbols. 542 continue; 543 } 544 $data = serialize($data); 545 546 // Write out the expiration time 547 fwrite($handle, "\n" . $this->var_expires[$var] . "\n"); 548 549 // Length of the remaining data for this var (ignoring two LF's) 550 fwrite($handle, strlen($data . $var) . "\n"); 551 fwrite($handle, $var . "\n"); 552 fwrite($handle, $data); 553 } 554 } 555 else 556 { 557 fwrite($handle, "\n" . $expires . "\n"); 558 559 if (strpos($filename, 'sql_') === 0) 560 { 561 fwrite($handle, $query . "\n"); 562 } 563 $data = serialize($data); 564 565 fwrite($handle, strlen($data) . "\n"); 566 fwrite($handle, $data); 567 } 568 569 fclose($handle); 570 571 if (function_exists('opcache_invalidate')) 572 { 573 @opcache_invalidate($file); 574 } 575 576 if (!function_exists('phpbb_chmod')) 577 { 578 global $phpbb_root_path; 579 include($phpbb_root_path . 'includes/functions.' . $phpEx); 580 } 581 582 phpbb_chmod($file, CHMOD_READ | CHMOD_WRITE); 583 584 $return_value = true; 585 } 586 else 587 { 588 $return_value = false; 589 } 590 591 $lock->release(); 592 593 return $return_value; 594 } 595 596 /** 597 * Replace slashes in the file name 598 * 599 * @param string $varname name of a cache variable 600 * @return string $varname name that is safe to use as a filename 601 */ 602 protected function clean_varname($varname) 603 { 604 return str_replace(array('/', '\\'), '-', $varname); 605 } 606 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jan 11 00:25:41 2018 | Cross-referenced by PHPXref 0.7.1 |