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