[ Index ]

PHP Cross Reference of phpBB-3.1.12-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      * 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  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1