Changeset 702 for trunk/forum/includes/acm/acm_file.php
- Timestamp:
- Mar 31, 2010, 6:32:40 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/forum/includes/acm/acm_file.php
r400 r702 3 3 * 4 4 * @package acm 5 * @version $Id : acm_file.php 9076 2008-11-22 19:06:42Z acydburn$6 * @copyright (c) 2005 phpBB Group5 * @version $Id$ 6 * @copyright (c) 2005, 2009 phpBB Group 7 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 8 8 * … … 45 45 function load() 46 46 { 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'); 58 48 } 59 49 … … 87 77 global $phpEx; 88 78 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')) 105 80 { 106 81 // Now, this occurred how often? ... phew, just tell the user then... 107 82 if (!@is_writable($this->cache_dir)) 108 83 { 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; 113 91 } 114 92 … … 130 108 } 131 109 110 $time = time(); 111 132 112 while (($entry = readdir($dir)) !== false) 133 113 { … … 137 117 } 138 118 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) 142 133 { 143 134 $this->remove_file($this->cache_dir . $entry); … … 155 146 foreach ($this->var_expires as $var_name => $expires) 156 147 { 157 if ( time() >$expires)148 if ($time >= $expires) 158 149 { 159 150 $this->destroy($var_name); … … 179 170 } 180 171 181 @include($this->cache_dir . "data{$var_name}.$phpEx"); 182 return (isset($data)) ? $data : false; 172 return $this->_read('data' . $var_name); 183 173 } 184 174 else … … 195 185 if ($var_name[0] == '_') 196 186 { 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); 214 188 } 215 189 else … … 286 260 } 287 261 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'))) 292 263 { 293 264 continue; 294 265 } 295 266 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 300 278 foreach ($table as $check_table) 301 279 { 302 280 // Better catch partial table names than no table names. ;) 303 if (strpos($ check_line, $check_table) !== false)281 if (strpos($query, $check_table) !== false) 304 282 { 305 $ found = true;283 $this->remove_file($this->cache_dir . $entry); 306 284 break; 307 285 } 308 }309 310 if ($found)311 {312 $this->remove_file($this->cache_dir . $entry);313 286 } 314 287 } … … 369 342 function sql_load($query) 370 343 { 371 global $phpEx;372 373 344 // Remove extra spaces and tabs 374 345 $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); 346 347 if (($rowset = $this->_read('sql_' . md5($query))) === false) 348 { 349 return false; 350 } 351 375 352 $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; 394 354 $this->sql_row_pointer[$query_id] = 0; 395 355 … … 402 362 function sql_save($query, &$query_result, $ttl) 403 363 { 404 global $db , $phpEx;364 global $db; 405 365 406 366 // Remove extra spaces and tabs 407 367 $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); 430 690 431 691 if (!function_exists('phpbb_chmod')) … … 435 695 } 436 696 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; 459 700 } 460 701 461 702 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;505 703 } 506 704
Note:
See TracChangeset
for help on using the changeset viewer.