[ Index ] |
PHP Cross Reference of phpBB-3.3.14-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 ($this->filesystem->is_writable(dirname($this->cache_dir)) && !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 * Cleanup when loading invalid data global file 335 * 336 * @param string $file Filename 337 * @param resource $handle 338 * 339 * @return void 340 */ 341 private function cleanup_invalid_data_global(string $file, $handle): void 342 { 343 if (is_resource($handle)) 344 { 345 fclose($handle); 346 } 347 348 $this->vars = $this->var_expires = []; 349 $this->is_modified = false; 350 351 $this->remove_file($file); 352 } 353 354 /** 355 * Read cached data from a specified file 356 * 357 * @access private 358 * @param string $filename Filename to write 359 * @return mixed False if an error was encountered, otherwise the data type of the cached data 360 */ 361 function _read($filename) 362 { 363 global $phpEx; 364 365 $filename = $this->clean_varname($filename); 366 $file = "{$this->cache_dir}$filename.$phpEx"; 367 368 $type = substr($filename, 0, strpos($filename, '_')); 369 370 if (!file_exists($file)) 371 { 372 return false; 373 } 374 375 if (!($handle = @fopen($file, 'rb'))) 376 { 377 return false; 378 } 379 380 // Skip the PHP header 381 fgets($handle); 382 383 if ($filename == 'data_global') 384 { 385 $this->vars = $this->var_expires = array(); 386 387 $time = time(); 388 389 while (($expires = (int) fgets($handle)) && !feof($handle)) 390 { 391 // Number of bytes of data 392 $bytes = substr(fgets($handle), 0, -1); 393 394 if (!is_numeric($bytes) || ($bytes = (int) $bytes) === 0) 395 { 396 $this->cleanup_invalid_data_global($file, $handle); 397 398 return false; 399 } 400 401 if ($time >= $expires) 402 { 403 fseek($handle, $bytes, SEEK_CUR); 404 405 continue; 406 } 407 408 $var_name = substr(fgets($handle), 0, -1); 409 $data_length = $bytes - strlen($var_name); 410 411 if ($data_length <= 0) 412 { 413 $this->cleanup_invalid_data_global($file, $handle); 414 415 return false; 416 } 417 418 // Read the length of bytes that consists of data. 419 $data = fread($handle, $data_length); 420 $data = @unserialize($data); 421 422 // Don't use the data if it was invalid 423 if ($data !== false) 424 { 425 $this->vars[$var_name] = $data; 426 $this->var_expires[$var_name] = $expires; 427 } 428 429 // Absorb the LF 430 fgets($handle); 431 } 432 433 fclose($handle); 434 435 $this->is_modified = false; 436 437 return true; 438 } 439 else 440 { 441 $data = false; 442 $line = 0; 443 444 while (($buffer = fgets($handle)) && !feof($handle)) 445 { 446 $buffer = substr($buffer, 0, -1); // Remove the LF 447 448 // $buffer is only used to read integers 449 // if it is non numeric we have an invalid 450 // cache file, which we will now remove. 451 if (!is_numeric($buffer)) 452 { 453 break; 454 } 455 456 if ($line == 0) 457 { 458 $expires = (int) $buffer; 459 460 if (time() >= $expires) 461 { 462 break; 463 } 464 465 if ($type == 'sql') 466 { 467 // Skip the query 468 fgets($handle); 469 } 470 } 471 else if ($line == 1) 472 { 473 $bytes = (int) $buffer; 474 475 // Never should have 0 bytes 476 if (!$bytes) 477 { 478 break; 479 } 480 481 // Grab the serialized data 482 $data = fread($handle, $bytes); 483 484 // Read 1 byte, to trigger EOF 485 fread($handle, 1); 486 487 if (!feof($handle)) 488 { 489 // Somebody tampered with our data 490 $data = false; 491 } 492 break; 493 } 494 else 495 { 496 // Something went wrong 497 break; 498 } 499 $line++; 500 } 501 fclose($handle); 502 503 // unserialize if we got some data 504 $data = ($data !== false) ? @unserialize($data) : $data; 505 506 if ($data === false) 507 { 508 $this->remove_file($file); 509 return false; 510 } 511 512 return $data; 513 } 514 } 515 516 /** 517 * Write cache data to a specified file 518 * 519 * 'data_global' is a special case and the generated format is different for this file: 520 * <code> 521 * <?php exit; ?> 522 * (expiration) 523 * (length of var and serialised data) 524 * (var) 525 * (serialised data) 526 * ... (repeat) 527 * </code> 528 * 529 * The other files have a similar format: 530 * <code> 531 * <?php exit; ?> 532 * (expiration) 533 * (query) [SQL files only] 534 * (length of serialised data) 535 * (serialised data) 536 * </code> 537 * 538 * @access private 539 * @param string $filename Filename to write 540 * @param mixed $data Data to store 541 * @param int $expires Timestamp when the data expires 542 * @param string $query Query when caching SQL queries 543 * @return bool True if the file was successfully created, otherwise false 544 */ 545 function _write($filename, $data = null, $expires = 0, $query = '') 546 { 547 global $phpEx; 548 549 $filename = $this->clean_varname($filename); 550 $file = "{$this->cache_dir}$filename.$phpEx"; 551 552 $lock = new \phpbb\lock\flock($file); 553 $lock->acquire(); 554 555 if ($handle = @fopen($file, 'wb')) 556 { 557 // File header 558 fwrite($handle, '<' . '?php exit; ?' . '>'); 559 560 if ($filename == 'data_global') 561 { 562 // Global data is a different format 563 foreach ($this->vars as $var => $data) 564 { 565 if (strpos($var, "\r") !== false || strpos($var, "\n") !== false) 566 { 567 // CR/LF would cause fgets() to read the cache file incorrectly 568 // do not cache test entries, they probably won't be read back 569 // the cache keys should really be alphanumeric with a few symbols. 570 continue; 571 } 572 $data = serialize($data); 573 574 // Write out the expiration time 575 fwrite($handle, "\n" . $this->var_expires[$var] . "\n"); 576 577 // Length of the remaining data for this var (ignoring two LF's) 578 fwrite($handle, strlen($data . $var) . "\n"); 579 fwrite($handle, $var . "\n"); 580 fwrite($handle, $data); 581 } 582 } 583 else 584 { 585 fwrite($handle, "\n" . $expires . "\n"); 586 587 if (strpos($filename, 'sql_') === 0) 588 { 589 fwrite($handle, $query . "\n"); 590 } 591 $data = serialize($data); 592 593 fwrite($handle, strlen($data) . "\n"); 594 fwrite($handle, $data); 595 } 596 597 fclose($handle); 598 599 if (function_exists('opcache_invalidate')) 600 { 601 @opcache_invalidate($file); 602 } 603 604 try 605 { 606 $this->filesystem->phpbb_chmod($file, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE); 607 } 608 catch (\phpbb\filesystem\exception\filesystem_exception $e) 609 { 610 // Do nothing 611 } 612 613 $return_value = true; 614 } 615 else 616 { 617 $return_value = false; 618 } 619 620 $lock->release(); 621 622 return $return_value; 623 } 624 625 /** 626 * Replace slashes in the file name 627 * 628 * @param string $varname name of a cache variable 629 * @return string $varname name that is safe to use as a filename 630 */ 631 protected function clean_varname($varname) 632 { 633 return str_replace(array('/', '\\'), '-', $varname); 634 } 635 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |