Ignore:
Timestamp:
Mar 31, 2010, 6:32:40 PM (15 years ago)
Author:
george
Message:
  • Upraveno: Aktualizace fóra.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/forum/includes/acm/acm_file.php

    r400 r702  
    33*
    44* @package acm
    5 * @version $Id: acm_file.php 9076 2008-11-22 19:06:42Z acydburn $
    6 * @copyright (c) 2005 phpBB Group
     5* @version $Id$
     6* @copyright (c) 2005, 2009 phpBB Group
    77* @license http://opensource.org/licenses/gpl-license.php GNU Public License
    88*
     
    4545        function load()
    4646        {
    47                 global $phpEx;
    48                 if (file_exists($this->cache_dir . 'data_global.' . $phpEx))
    49                 {
    50                         @include($this->cache_dir . 'data_global.' . $phpEx);
    51                 }
    52                 else
    53                 {
    54                         return false;
    55                 }
    56 
    57                 return true;
     47                return $this->_read('data_global');
    5848        }
    5949
     
    8777                global $phpEx;
    8878
    89                 if ($fp = @fopen($this->cache_dir . 'data_global.' . $phpEx, 'wb'))
    90                 {
    91                         @flock($fp, LOCK_EX);
    92                         fwrite($fp, "<?php\n\$this->vars = " . var_export($this->vars, true) . ";\n\n\$this->var_expires = " . var_export($this->var_expires, true) . "\n?>");
    93                         @flock($fp, LOCK_UN);
    94                         fclose($fp);
    95 
    96                         if (!function_exists('phpbb_chmod'))
    97                         {
    98                                 global $phpbb_root_path;
    99                                 include($phpbb_root_path . 'includes/functions.' . $phpEx);
    100                         }
    101 
    102                         phpbb_chmod($this->cache_dir . 'data_global.' . $phpEx, CHMOD_WRITE);
    103                 }
    104                 else
     79                if (!$this->_write('data_global'))
    10580                {
    10681                        // Now, this occurred how often? ... phew, just tell the user then...
    10782                        if (!@is_writable($this->cache_dir))
    10883                        {
    109                                 trigger_error($this->cache_dir . ' is NOT writable.', E_USER_ERROR);
    110                         }
    111 
    112                         trigger_error('Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx, E_USER_ERROR);
     84                                // We need to use die() here, because else we may encounter an infinite loop (the message handler calls $cache->unload())
     85                                die($this->cache_dir . ' is NOT writable.');
     86                                exit;
     87                        }
     88
     89                        die('Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx);
     90                        exit;
    11391                }
    11492
     
    130108                }
    131109
     110                $time = time();
     111
    132112                while (($entry = readdir($dir)) !== false)
    133113                {
     
    137117                        }
    138118
    139                         $expired = true;
    140                         @include($this->cache_dir . $entry);
    141                         if ($expired)
     119                        if (!($handle = @fopen($this->cache_dir . $entry, 'rb')))
     120                        {
     121                                continue;
     122                        }
     123
     124                        // Skip the PHP header
     125                        fgets($handle);
     126
     127                        // Skip expiration
     128                        $expires = (int) fgets($handle);
     129
     130                        fclose($handle);
     131
     132                        if ($time >= $expires)
    142133                        {
    143134                                $this->remove_file($this->cache_dir . $entry);
     
    155146                        foreach ($this->var_expires as $var_name => $expires)
    156147                        {
    157                                 if (time() > $expires)
     148                                if ($time >= $expires)
    158149                                {
    159150                                        $this->destroy($var_name);
     
    179170                        }
    180171
    181                         @include($this->cache_dir . "data{$var_name}.$phpEx");
    182                         return (isset($data)) ? $data : false;
     172                        return $this->_read('data' . $var_name);
    183173                }
    184174                else
     
    195185                if ($var_name[0] == '_')
    196186                {
    197                         global $phpEx;
    198 
    199                         if ($fp = @fopen($this->cache_dir . "data{$var_name}.$phpEx", 'wb'))
    200                         {
    201                                 @flock($fp, LOCK_EX);
    202                                 fwrite($fp, "<?php\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n\n\$data =  " . (sizeof($var) ? "unserialize(" . var_export(serialize($var), true) . ");" : 'array();') . "\n\n?>");
    203                                 @flock($fp, LOCK_UN);
    204                                 fclose($fp);
    205 
    206                                 if (!function_exists('phpbb_chmod'))
    207                                 {
    208                                         global $phpbb_root_path;
    209                                         include($phpbb_root_path . 'includes/functions.' . $phpEx);
    210                                 }
    211 
    212                                 phpbb_chmod($this->cache_dir . "data{$var_name}.$phpEx", CHMOD_WRITE);
    213                         }
     187                        $this->_write('data' . $var_name, $var, time() + $ttl);
    214188                }
    215189                else
     
    286260                                }
    287261
    288                                 // The following method is more failproof than simply assuming the query is on line 3 (which it should be)
    289                                 $check_line = @file_get_contents($this->cache_dir . $entry);
    290 
    291                                 if (empty($check_line))
     262                                if (!($handle = @fopen($this->cache_dir . $entry, 'rb')))
    292263                                {
    293264                                        continue;
    294265                                }
    295266
    296                                 // Now get the contents between /* and */
    297                                 $check_line = substr($check_line, strpos($check_line, '/* ') + 3, strpos($check_line, ' */') - strpos($check_line, '/* ') - 3);
    298 
    299                                 $found = false;
     267                                // Skip the PHP header
     268                                fgets($handle);
     269
     270                                // Skip expiration
     271                                fgets($handle);
     272
     273                                // Grab the query, remove the LF
     274                                $query = substr(fgets($handle), 0, -1);
     275
     276                                fclose($handle);
     277
    300278                                foreach ($table as $check_table)
    301279                                {
    302280                                        // Better catch partial table names than no table names. ;)
    303                                         if (strpos($check_line, $check_table) !== false)
     281                                        if (strpos($query, $check_table) !== false)
    304282                                        {
    305                                                 $found = true;
     283                                                $this->remove_file($this->cache_dir . $entry);
    306284                                                break;
    307285                                        }
    308                                 }
    309 
    310                                 if ($found)
    311                                 {
    312                                         $this->remove_file($this->cache_dir . $entry);
    313286                                }
    314287                        }
     
    369342        function sql_load($query)
    370343        {
    371                 global $phpEx;
    372 
    373344                // Remove extra spaces and tabs
    374345                $query = preg_replace('/[\n\r\s\t]+/', ' ', $query);
     346
     347                if (($rowset = $this->_read('sql_' . md5($query))) === false)
     348                {
     349                        return false;
     350                }
     351
    375352                $query_id = sizeof($this->sql_rowset);
    376 
    377                 if (!file_exists($this->cache_dir . 'sql_' . md5($query) . ".$phpEx"))
    378                 {
    379                         return false;
    380                 }
    381 
    382                 @include($this->cache_dir . 'sql_' . md5($query) . ".$phpEx");
    383 
    384                 if (!isset($expired))
    385                 {
    386                         return false;
    387                 }
    388                 else if ($expired)
    389                 {
    390                         $this->remove_file($this->cache_dir . 'sql_' . md5($query) . ".$phpEx", true);
    391                         return false;
    392                 }
    393 
     353                $this->sql_rowset[$query_id] = $rowset;
    394354                $this->sql_row_pointer[$query_id] = 0;
    395355
     
    402362        function sql_save($query, &$query_result, $ttl)
    403363        {
    404                 global $db, $phpEx;
     364                global $db;
    405365
    406366                // Remove extra spaces and tabs
    407367                $query = preg_replace('/[\n\r\s\t]+/', ' ', $query);
    408                 $filename = $this->cache_dir . 'sql_' . md5($query) . '.' . $phpEx;
    409 
    410                 if ($fp = @fopen($filename, 'wb'))
    411                 {
    412                         @flock($fp, LOCK_EX);
    413 
    414                         $query_id = sizeof($this->sql_rowset);
    415                         $this->sql_rowset[$query_id] = array();
    416                         $this->sql_row_pointer[$query_id] = 0;
    417 
    418                         while ($row = $db->sql_fetchrow($query_result))
    419                         {
    420                                 $this->sql_rowset[$query_id][] = $row;
    421                         }
    422                         $db->sql_freeresult($query_result);
    423 
    424                         $file = "<?php\n\n/* " . str_replace('*/', '*\/', $query) . " */\n";
    425                         $file .= "\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n";
    426 
    427                         fwrite($fp, $file . "\n\$this->sql_rowset[\$query_id] = " . (sizeof($this->sql_rowset[$query_id]) ? "unserialize(" . var_export(serialize($this->sql_rowset[$query_id]), true) . ");" : 'array();') . "\n\n?>");
    428                         @flock($fp, LOCK_UN);
    429                         fclose($fp);
     368
     369                $query_id = sizeof($this->sql_rowset);
     370                $this->sql_rowset[$query_id] = array();
     371                $this->sql_row_pointer[$query_id] = 0;
     372
     373                while ($row = $db->sql_fetchrow($query_result))
     374                {
     375                        $this->sql_rowset[$query_id][] = $row;
     376                }
     377                $db->sql_freeresult($query_result);
     378
     379                if ($this->_write('sql_' . md5($query), $this->sql_rowset[$query_id], $ttl + time(), $query))
     380                {
     381                        $query_result = $query_id;
     382                }
     383        }
     384
     385        /**
     386        * Ceck if a given sql query exist in cache
     387        */
     388        function sql_exists($query_id)
     389        {
     390                return isset($this->sql_rowset[$query_id]);
     391        }
     392
     393        /**
     394        * Fetch row from cache (database)
     395        */
     396        function sql_fetchrow($query_id)
     397        {
     398                if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id]))
     399                {
     400                        return $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++];
     401                }
     402
     403                return false;
     404        }
     405
     406        /**
     407        * Fetch a field from the current row of a cached database result (database)
     408        */
     409        function sql_fetchfield($query_id, $field)
     410        {
     411                if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id]))
     412                {
     413                        return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false;
     414                }
     415
     416                return false;
     417        }
     418
     419        /**
     420        * Seek a specific row in an a cached database result (database)
     421        */
     422        function sql_rowseek($rownum, $query_id)
     423        {
     424                if ($rownum >= sizeof($this->sql_rowset[$query_id]))
     425                {
     426                        return false;
     427                }
     428
     429                $this->sql_row_pointer[$query_id] = $rownum;
     430                return true;
     431        }
     432
     433        /**
     434        * Free memory used for a cached database result (database)
     435        */
     436        function sql_freeresult($query_id)
     437        {
     438                if (!isset($this->sql_rowset[$query_id]))
     439                {
     440                        return false;
     441                }
     442
     443                unset($this->sql_rowset[$query_id]);
     444                unset($this->sql_row_pointer[$query_id]);
     445
     446                return true;
     447        }
     448
     449        /**
     450        * Read cached data from a specified file
     451        *
     452        * @access private
     453        * @param string $filename Filename to write
     454        * @return mixed False if an error was encountered, otherwise the data type of the cached data
     455        */
     456        function _read($filename)
     457        {
     458                global $phpEx;
     459
     460                $file = "{$this->cache_dir}$filename.$phpEx";
     461
     462                $type = substr($filename, 0, strpos($filename, '_'));
     463
     464                if (!file_exists($file))
     465                {
     466                        return false;
     467                }
     468
     469                if (!($handle = @fopen($file, 'rb')))
     470                {
     471                        return false;
     472                }
     473
     474                // Skip the PHP header
     475                fgets($handle);
     476
     477                if ($filename == 'data_global')
     478                {
     479                        $this->vars = $this->var_expires = array();
     480
     481                        $time = time();
     482
     483                        while (($expires = (int) fgets($handle)) && !feof($handle))
     484                        {
     485                                // Number of bytes of data
     486                                $bytes = substr(fgets($handle), 0, -1);
     487
     488                                if (!is_numeric($bytes) || ($bytes = (int) $bytes) === 0)
     489                                {
     490                                        // We cannot process the file without a valid number of bytes
     491                                        // so we discard it
     492                                        fclose($handle);
     493
     494                                        $this->vars = $this->var_expires = array();
     495                                        $this->is_modified = false;
     496
     497                                        $this->remove_file($file);
     498
     499                                        return false;
     500                                }
     501
     502                                if ($time >= $expires)
     503                                {
     504                                        fseek($handle, $bytes, SEEK_CUR);
     505
     506                                        continue;
     507                                }
     508
     509                                $var_name = substr(fgets($handle), 0, -1);
     510
     511                                // Read the length of bytes that consists of data.
     512                                $data = fread($handle, $bytes - strlen($var_name));
     513                                $data = @unserialize($data);
     514
     515                                // Don't use the data if it was invalid
     516                                if ($data !== false)
     517                                {
     518                                        $this->vars[$var_name] = $data;
     519                                        $this->var_expires[$var_name] = $expires;
     520                                }
     521
     522                                // Absorb the LF
     523                                fgets($handle);
     524                        }
     525
     526                        fclose($handle);
     527
     528                        $this->is_modified = false;
     529
     530                        return true;
     531                }
     532                else
     533                {
     534                        $data = false;
     535                        $line = 0;
     536
     537                        while (($buffer = fgets($handle)) && !feof($handle))
     538                        {
     539                                $buffer = substr($buffer, 0, -1); // Remove the LF
     540
     541                                // $buffer is only used to read integers
     542                                // if it is non numeric we have an invalid
     543                                // cache file, which we will now remove.
     544                                if (!is_numeric($buffer))
     545                                {
     546                                        break;
     547                                }
     548
     549                                if ($line == 0)
     550                                {
     551                                        $expires = (int) $buffer;
     552
     553                                        if (time() >= $expires)
     554                                        {
     555                                                break;
     556                                        }
     557
     558                                        if ($type == 'sql')
     559                                        {
     560                                                // Skip the query
     561                                                fgets($handle);
     562                                        }
     563                                }
     564                                else if ($line == 1)
     565                                {
     566                                        $bytes = (int) $buffer;
     567
     568                                        // Never should have 0 bytes
     569                                        if (!$bytes)
     570                                        {
     571                                                break;
     572                                        }
     573
     574                                        // Grab the serialized data
     575                                        $data = fread($handle, $bytes);
     576
     577                                        // Read 1 byte, to trigger EOF
     578                                        fread($handle, 1);
     579
     580                                        if (!feof($handle))
     581                                        {
     582                                                // Somebody tampered with our data
     583                                                $data = false;
     584                                        }
     585                                        break;
     586                                }
     587                                else
     588                                {
     589                                        // Something went wrong
     590                                        break;
     591                                }
     592                                $line++;
     593                        }
     594                        fclose($handle);
     595
     596                        // unserialize if we got some data
     597                        $data = ($data !== false) ? @unserialize($data) : $data;
     598
     599                        if ($data === false)
     600                        {
     601                                $this->remove_file($file);
     602                                return false;
     603                        }
     604
     605                        return $data;
     606                }
     607        }
     608
     609        /**
     610        * Write cache data to a specified file
     611        *
     612        * 'data_global' is a special case and the generated format is different for this file:
     613        * <code>
     614        * <?php exit; ?>
     615        * (expiration)
     616        * (length of var and serialised data)
     617        * (var)
     618        * (serialised data)
     619        * ... (repeat)
     620        * </code>
     621        *
     622        * The other files have a similar format:
     623        * <code>
     624        * <?php exit; ?>
     625        * (expiration)
     626        * (query) [SQL files only]
     627        * (length of serialised data)
     628        * (serialised data)
     629        * </code>
     630        *
     631        * @access private
     632        * @param string $filename Filename to write
     633        * @param mixed $data Data to store
     634        * @param int $expires Timestamp when the data expires
     635        * @param string $query Query when caching SQL queries
     636        * @return bool True if the file was successfully created, otherwise false
     637        */
     638        function _write($filename, $data = null, $expires = 0, $query = '')
     639        {
     640                global $phpEx;
     641
     642                $file = "{$this->cache_dir}$filename.$phpEx";
     643
     644                if ($handle = @fopen($file, 'wb'))
     645                {
     646                        @flock($handle, LOCK_EX);
     647
     648                        // File header
     649                        fwrite($handle, '<' . '?php exit; ?' . '>');
     650
     651                        if ($filename == 'data_global')
     652                        {
     653                                // Global data is a different format
     654                                foreach ($this->vars as $var => $data)
     655                                {
     656                                        if (strpos($var, "\r") !== false || strpos($var, "\n") !== false)
     657                                        {
     658                                                // CR/LF would cause fgets() to read the cache file incorrectly
     659                                                // do not cache test entries, they probably won't be read back
     660                                                // the cache keys should really be alphanumeric with a few symbols.
     661                                                continue;
     662                                        }
     663                                        $data = serialize($data);
     664
     665                                        // Write out the expiration time
     666                                        fwrite($handle, "\n" . $this->var_expires[$var] . "\n");
     667
     668                                        // Length of the remaining data for this var (ignoring two LF's)
     669                                        fwrite($handle, strlen($data . $var) . "\n");
     670                                        fwrite($handle, $var . "\n");
     671                                        fwrite($handle, $data);
     672                                }
     673                        }
     674                        else
     675                        {
     676                                fwrite($handle, "\n" . $expires . "\n");
     677
     678                                if (strpos($filename, 'sql_') === 0)
     679                                {
     680                                        fwrite($handle, $query . "\n");
     681                                }
     682                                $data = serialize($data);
     683
     684                                fwrite($handle, strlen($data) . "\n");
     685                                fwrite($handle, $data);
     686                        }
     687
     688                        @flock($handle, LOCK_UN);
     689                        fclose($handle);
    430690
    431691                        if (!function_exists('phpbb_chmod'))
     
    435695                        }
    436696
    437                         phpbb_chmod($filename, CHMOD_WRITE);
    438 
    439                         $query_result = $query_id;
    440                 }
    441         }
    442 
    443         /**
    444         * Ceck if a given sql query exist in cache
    445         */
    446         function sql_exists($query_id)
    447         {
    448                 return isset($this->sql_rowset[$query_id]);
    449         }
    450 
    451         /**
    452         * Fetch row from cache (database)
    453         */
    454         function sql_fetchrow($query_id)
    455         {
    456                 if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id]))
    457                 {
    458                         return $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++];
     697                        phpbb_chmod($file, CHMOD_READ | CHMOD_WRITE);
     698
     699                        return true;
    459700                }
    460701
    461702                return false;
    462         }
    463 
    464         /**
    465         * Fetch a field from the current row of a cached database result (database)
    466         */
    467         function sql_fetchfield($query_id, $field)
    468         {
    469                 if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id]))
    470                 {
    471                         return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field] : false;
    472                 }
    473 
    474                 return false;
    475         }
    476 
    477         /**
    478         * Seek a specific row in an a cached database result (database)
    479         */
    480         function sql_rowseek($rownum, $query_id)
    481         {
    482                 if ($rownum >= sizeof($this->sql_rowset[$query_id]))
    483                 {
    484                         return false;
    485                 }
    486 
    487                 $this->sql_row_pointer[$query_id] = $rownum;
    488                 return true;
    489         }
    490 
    491         /**
    492         * Free memory used for a cached database result (database)
    493         */
    494         function sql_freeresult($query_id)
    495         {
    496                 if (!isset($this->sql_rowset[$query_id]))
    497                 {
    498                         return false;
    499                 }
    500 
    501                 unset($this->sql_rowset[$query_id]);
    502                 unset($this->sql_row_pointer[$query_id]);
    503 
    504                 return true;
    505703        }
    506704
Note: See TracChangeset for help on using the changeset viewer.