Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

file.php

Zuletzt modifiziert: 02.04.2025, 15:02 - Dateigröße: 11.90 KiB


001  <?php
002  /**
003  *
004  * This file is part of the phpBB Forum Software package.
005  *
006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
007  * @license GNU General Public License, version 2 (GPL-2.0)
008  *
009  * For full copyright and license information, please see
010  * the docs/CREDITS.txt file.
011  *
012  */
013   
014  namespace phpbb\cache\driver;
015   
016  /**
017  * ACM File Based Caching
018  */
019  class file extends \phpbb\cache\driver\base
020  {
021      var $var_expires = array();
022   
023      /**
024       * @var    \phpbb\filesystem\filesystem_interface
025       */
026      protected $filesystem;
027   
028      /**
029      * Set cache path
030      *
031      * @param string $cache_dir Define the path to the cache directory (default: $phpbb_root_path . 'cache/')
032      */
033      function __construct($cache_dir = null)
034      {
035          global $phpbb_container;
036   
037          $this->cache_dir = !is_null($cache_dir) ? $cache_dir : $phpbb_container->getParameter('core.cache_dir');
038          $this->filesystem = new \phpbb\filesystem\filesystem();
039   
040          if ($this->filesystem->is_writable(dirname($this->cache_dir)) && !is_dir($this->cache_dir))
041          {
042              mkdir($this->cache_dir, 0777, true);
043          }
044      }
045   
046      /**
047      * {@inheritDoc}
048      */
049      function load()
050      {
051          return $this->_read('data_global');
052      }
053   
054      /**
055      * {@inheritDoc}
056      */
057      function unload()
058      {
059          parent::unload();
060          unset($this->var_expires);
061          $this->var_expires = array();
062      }
063   
064      /**
065      * {@inheritDoc}
066      */
067      function save()
068      {
069          if (!$this->is_modified)
070          {
071              return;
072          }
073   
074          global $phpEx;
075   
076          if (!$this->_write('data_global'))
077          {
078              // Now, this occurred how often? ... phew, just tell the user then...
079              if (!$this->filesystem->is_writable($this->cache_dir))
080              {
081                  // We need to use die() here, because else we may encounter an infinite loop (the message handler calls $cache->unload())
082                  die('Fatal: ' . $this->cache_dir . ' is NOT writable.');
083                  exit;
084              }
085   
086              die('Fatal: Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx);
087              exit;
088          }
089   
090          $this->is_modified = false;
091      }
092   
093      /**
094      * {@inheritDoc}
095      */
096      function tidy()
097      {
098          global $config, $phpEx;
099   
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  }
636