[ Index ]

PHP Cross Reference of phpBB-3.2.11-deutsch

title

Body

[close]

/phpbb/cache/driver/ -> file.php (source)

   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  }


Generated: Wed Nov 11 20:33:01 2020 Cross-referenced by PHPXref 0.7.1