1<?php 2/** 3 * Caching functions. 4 * 5 * This file contains all of the functions used to generate the cache files used by the site. 6 * 7 * @copyright (C) 2008-2012 PunBB, partially based on code (C) 2008-2009 FluxBB.org 8 * @license http://www.gnu.org/licenses/gpl.html GPL version 2 or higher 9 * @package PunBB 10 */ 11 12 13// Make sure no one attempts to run this script "directly" 14if (!defined('FORUM')) 15 exit; 16 17 18// Safe create or write of cache files 19// Use LOCK 20function write_cache_file($file, $content) 21{ 22 // Open 23 $handle = @fopen($file, 'r+b'); // @ - file may not exist 24 if (!$handle) 25 { 26 $handle = fopen($file, 'wb'); 27 if (!$handle) 28 { 29 return false; 30 } 31 } 32 33 // Lock 34 flock($handle, LOCK_EX); 35 ftruncate($handle, 0); 36 37 // Write 38 if (fwrite($handle, $content) === false) 39 { 40 // Unlock and close 41 flock($handle, LOCK_UN); 42 fclose($handle); 43 44 return false; 45 } 46 47 // Unlock and close 48 flock($handle, LOCK_UN); 49 fclose($handle); 50 51 // Force opcache to recompile this script 52 if (function_exists('opcache_invalidate')) { 53 opcache_invalidate($file, true); 54 } 55 56 return true; 57} 58 59 60// 61// Generate the config cache PHP script 62// 63function generate_config_cache() 64{ 65 global $forum_db; 66 67 $return = ($hook = get_hook('ch_fn_generate_config_cache_start')) ? eval($hook) : null; 68 if ($return !== null) 69 return; 70 71 // Get the forum config from the DB 72 $query = array( 73 'SELECT' => 'c.*', 74 'FROM' => 'config AS c' 75 ); 76 77 ($hook = get_hook('ch_fn_generate_config_cache_qr_get_config')) ? eval($hook) : null; 78 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 79 80 $output = array(); 81 while ($cur_config_item = $forum_db->fetch_assoc($result)) 82 $output[$cur_config_item['conf_name']] = $cur_config_item['conf_value']; 83 84 // Output config as PHP code 85 if (!write_cache_file(FORUM_CACHE_DIR.'cache_config.php', '<?php'."\n\n".'define(\'FORUM_CONFIG_LOADED\', 1);'."\n\n".'$forum_config = '.var_export($output, true).';'."\n\n".'?>')) 86 { 87 error('Unable to write configuration cache file to cache directory.<br />Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__); 88 } 89} 90 91 92// 93// Generate the bans cache PHP script 94// 95function generate_bans_cache() 96{ 97 global $forum_db; 98 99 $return = ($hook = get_hook('ch_fn_generate_bans_cache_start')) ? eval($hook) : null; 100 if ($return !== null) 101 return; 102 103 // Get the ban list from the DB 104 $query = array( 105 'SELECT' => 'b.*, u.username AS ban_creator_username', 106 'FROM' => 'bans AS b', 107 'JOINS' => array( 108 array( 109 'LEFT JOIN' => 'users AS u', 110 'ON' => 'u.id=b.ban_creator' 111 ) 112 ), 113 'ORDER BY' => 'b.id' 114 ); 115 116 ($hook = get_hook('ch_fn_generate_bans_cache_qr_get_bans')) ? eval($hook) : null; 117 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 118 119 $output = array(); 120 while ($cur_ban = $forum_db->fetch_assoc($result)) 121 $output[] = $cur_ban; 122 123 // Output ban list as PHP code 124 if (!write_cache_file(FORUM_CACHE_DIR.'cache_bans.php', '<?php'."\n\n".'define(\'FORUM_BANS_LOADED\', 1);'."\n\n".'$forum_bans = '.var_export($output, true).';'."\n\n".'?>')) 125 { 126 error('Unable to write bans cache file to cache directory.<br />Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__); 127 } 128} 129 130 131// 132// Generate the ranks cache PHP script 133// 134function generate_ranks_cache() 135{ 136 global $forum_db; 137 138 $return = ($hook = get_hook('ch_fn_generate_ranks_cache_start')) ? eval($hook) : null; 139 if ($return !== null) 140 return; 141 142 // Get the rank list from the DB 143 $query = array( 144 'SELECT' => 'r.*', 145 'FROM' => 'ranks AS r', 146 'ORDER BY' => 'r.min_posts' 147 ); 148 149 ($hook = get_hook('ch_fn_generate_ranks_cache_qr_get_ranks')) ? eval($hook) : null; 150 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 151 152 $output = array(); 153 while ($cur_rank = $forum_db->fetch_assoc($result)) 154 $output[] = $cur_rank; 155 156 // Output ranks list as PHP code 157 if (!write_cache_file(FORUM_CACHE_DIR.'cache_ranks.php', '<?php'."\n\n".'define(\'FORUM_RANKS_LOADED\', 1);'."\n\n".'$forum_ranks = '.var_export($output, true).';'."\n\n".'?>')) 158 { 159 error('Unable to write ranks cache file to cache directory.<br />Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__); 160 } 161} 162 163 164// 165// Generate the forum stats cache PHP script 166// 167function generate_stats_cache() 168{ 169 global $forum_db; 170 171 $stats = array(); 172 173 $return = ($hook = get_hook('ch_fn_generate_stats_cache_start')) ? eval($hook) : null; 174 if ($return !== null) 175 return; 176 177 // Collect some statistics from the database 178 $query = array( 179 'SELECT' => 'COUNT(u.id) - 1', 180 'FROM' => 'users AS u', 181 'WHERE' => 'u.group_id != '.FORUM_UNVERIFIED 182 ); 183 184 ($hook = get_hook('ch_fn_generate_stats_cache_qr_get_user_count')) ? eval($hook) : null; 185 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 186 $stats['total_users'] = $forum_db->result($result); 187 188 189 // Get last registered user info 190 $query = array( 191 'SELECT' => 'u.id, u.username', 192 'FROM' => 'users AS u', 193 'WHERE' => 'u.group_id != '.FORUM_UNVERIFIED, 194 'ORDER BY' => 'u.registered DESC', 195 'LIMIT' => '1' 196 ); 197 198 ($hook = get_hook('ch_fn_generate_stats_cache_qr_get_newest_user')) ? eval($hook) : null; 199 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 200 $stats['last_user'] = $forum_db->fetch_assoc($result); 201 202 // Get num topics and posts 203 $query = array( 204 'SELECT' => 'SUM(f.num_topics) AS num_topics, SUM(f.num_posts) AS num_posts', 205 'FROM' => 'forums AS f' 206 ); 207 208 ($hook = get_hook('ch_fn_generate_stats_cache_qr_get_post_stats')) ? eval($hook) : null; 209 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 210 211 $stats_topics_and_posts = $forum_db->fetch_assoc($result); 212 $stats['total_topics'] = $stats_topics_and_posts['num_topics']; 213 $stats['total_posts'] = $stats_topics_and_posts['num_posts']; 214 215 $stats['cached'] = time(); 216 217 // Output ranks list as PHP code 218 if (!write_cache_file(FORUM_CACHE_DIR.'cache_stats.php', '<?php'."\n\n".'if (!defined(\'FORUM_STATS_LOADED\')) define(\'FORUM_STATS_LOADED\', 1);'."\n\n".'$forum_stats = '.var_export($stats, true).';'."\n\n".'?>')) 219 { 220 error('Unable to write stats cache file to cache directory.<br />Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__); 221 } 222 223 unset($stats); 224} 225 226 227// 228// Clean stats cache PHP scripts 229// 230function clean_stats_cache() 231{ 232 $cache_file = FORUM_CACHE_DIR.'cache_stats.php'; 233 if (file_exists($cache_file)) 234 { 235 unlink($cache_file); 236 } 237} 238 239 240// 241// Generate the censor cache PHP script 242// 243function generate_censors_cache() 244{ 245 global $forum_db; 246 247 $return = ($hook = get_hook('ch_fn_generate_censors_cache_start')) ? eval($hook) : null; 248 if ($return !== null) 249 return; 250 251 // Get the censor list from the DB 252 $query = array( 253 'SELECT' => 'c.*', 254 'FROM' => 'censoring AS c', 255 'ORDER BY' => 'c.search_for' 256 ); 257 258 ($hook = get_hook('ch_fn_generate_censors_cache_qr_get_censored_words')) ? eval($hook) : null; 259 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 260 261 $output = array(); 262 while ($cur_censor = $forum_db->fetch_assoc($result)) 263 $output[] = $cur_censor; 264 265 // Output censors list as PHP code 266 if (!write_cache_file(FORUM_CACHE_DIR.'cache_censors.php', '<?php'."\n\n".'define(\'FORUM_CENSORS_LOADED\', 1);'."\n\n".'$forum_censors = '.var_export($output, true).';'."\n\n".'?>')) 267 { 268 error('Unable to write censor cache file to cache directory.<br />Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__); 269 } 270} 271 272 273// 274// Generate quickjump cache PHP scripts 275// 276function generate_quickjump_cache($group_id = false) 277{ 278 global $forum_db, $lang_common, $forum_url, $forum_config, $forum_user, $base_url; 279 280 $return = ($hook = get_hook('ch_fn_generate_quickjump_cache_start')) ? eval($hook) : null; 281 if ($return !== null) 282 return; 283 284 $groups = array(); 285 286 // If a group_id was supplied, we generate the quickjump cache for that group only 287 if ($group_id !== false) 288 $groups[0] = $group_id; 289 else 290 { 291 // A group_id was not supplied, so we generate the quickjump cache for all groups 292 $query = array( 293 'SELECT' => 'g.g_id', 294 'FROM' => 'groups AS g' 295 ); 296 297 ($hook = get_hook('ch_fn_generate_quickjump_cache_qr_get_groups')) ? eval($hook) : null; 298 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 299 300 while ($cur_group = $forum_db->fetch_assoc($result)) 301 { 302 $groups[] = $cur_group['g_id']; 303 } 304 } 305 306 // Loop through the groups in $groups and output the cache for each of them 307 foreach ($groups as $group_id) 308 { 309 $output = '<?php'."\n\n".'if (!defined(\'FORUM\')) exit;'."\n".'define(\'FORUM_QJ_LOADED\', 1);'."\n".'$forum_id = isset($forum_id) ? $forum_id : 0;'."\n\n".'?>'; 310 $output .= '<form id="qjump" method="get" accept-charset="utf-8" action="'.$base_url.'/viewforum.php">'."\n\t".'<div class="frm-fld frm-select">'."\n\t\t".'<label for="qjump-select"><span><?php echo $lang_common[\'Jump to\'] ?>'.'</span></label><br />'."\n\t\t".'<span class="frm-input"><select id="qjump-select" name="id">'."\n"; 311 312 // Get the list of categories and forums from the DB 313 $query = array( 314 'SELECT' => 'c.id AS cid, c.cat_name, f.id AS fid, f.forum_name, f.redirect_url', 315 'FROM' => 'categories AS c', 316 'JOINS' => array( 317 array( 318 'INNER JOIN' => 'forums AS f', 319 'ON' => 'c.id=f.cat_id' 320 ), 321 array( 322 'LEFT JOIN' => 'forum_perms AS fp', 323 'ON' => '(fp.forum_id=f.id AND fp.group_id='.$group_id.')' 324 ) 325 ), 326 'WHERE' => 'fp.read_forum IS NULL OR fp.read_forum=1', 327 'ORDER BY' => 'c.disp_position, c.id, f.disp_position' 328 ); 329 330 ($hook = get_hook('ch_fn_generate_quickjump_cache_qr_get_cats_and_forums')) ? eval($hook) : null; 331 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 332 333 $forums = array(); 334 while ($cur_forum = $forum_db->fetch_assoc($result)) 335 { 336 $forums[] = $cur_forum; 337 } 338 339 $cur_category = 0; 340 $forum_count = 0; 341 $sef_friendly_names = array(); 342 foreach ($forums as $cur_forum) 343 { 344 ($hook = get_hook('ch_fn_generate_quickjump_cache_forum_loop_start')) ? eval($hook) : null; 345 346 if ($cur_forum['cid'] != $cur_category) // A new category since last iteration? 347 { 348 if ($cur_category) 349 $output .= "\t\t\t".'</optgroup>'."\n"; 350 351 $output .= "\t\t\t".'<optgroup label="'.forum_htmlencode($cur_forum['cat_name']).'">'."\n"; 352 $cur_category = $cur_forum['cid']; 353 } 354 355 $sef_friendly_names[$cur_forum['fid']] = sef_friendly($cur_forum['forum_name']); 356 $redirect_tag = ($cur_forum['redirect_url'] != '') ? ' >>>' : ''; 357 $output .= "\t\t\t\t".'<option value="'.$cur_forum['fid'].'"<?php echo ($forum_id == '.$cur_forum['fid'].') ? \' selected="selected"\' : \'\' ?>>'.forum_htmlencode($cur_forum['forum_name']).$redirect_tag.'</option>'."\n"; 358 $forum_count++; 359 360 ($hook = get_hook('ch_fn_generate_quickjump_cache_forum_loop_end')) ? eval($hook) : null; 361 } 362 363 $output .= "\t\t\t".'</optgroup>'."\n\t\t".'</select>'."\n\t\t".'<input type="submit" id="qjump-submit" value="<?php echo $lang_common[\'Go\'] ?>" /></span>'."\n\t".'</div>'."\n".'</form>'."\n"; 364 $output_js = "\n".'(function () {'."\n\t".'var forum_quickjump_url = "'.forum_link($forum_url['forum']).'";'."\n\t".'var sef_friendly_url_array = new Array('.count($forums).');'; 365 366 foreach ($sef_friendly_names as $forum_id => $forum_name) 367 $output_js .= "\n\t".'sef_friendly_url_array['.$forum_id.'] = "'.forum_htmlencode($forum_name).'";'; 368 369 // Add Load Event 370 $output_js .= "\n\n\t".'PUNBB.common.addDOMReadyEvent(function () { PUNBB.common.attachQuickjumpRedirect(forum_quickjump_url, sef_friendly_url_array); });'."\n".'}());'; 371 372 if ($forum_count < 2) 373 $output = '<?php'."\n\n".'if (!defined(\'FORUM\')) exit;'."\n".'define(\'FORUM_QJ_LOADED\', 1);'; 374 else 375 $output .= '<?php'."\n\n".'$forum_javascript_quickjump_code = <<<EOL'.$output_js."\nEOL;\n\n".'$forum_loader->add_js($forum_javascript_quickjump_code, array(\'type\' => \'inline\', \'weight\' => 60, \'group\' => FORUM_JS_GROUP_SYSTEM));'."\n".'?>'."\n"; 376 377 // Output quickjump as PHP code 378 if (!write_cache_file(FORUM_CACHE_DIR.'cache_quickjump_'.$group_id.'.php', $output)) 379 { 380 error('Unable to write quickjump cache file to cache directory.<br />Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__); 381 } 382 } 383} 384 385 386// 387// Clean quickjump cache PHP scripts 388// 389function clean_quickjump_cache($group_id = false) 390{ 391 global $forum_db; 392 393 $return = ($hook = get_hook('ch_fn_clean_quickjump_cache_start')) ? eval($hook) : null; 394 if ($return !== null) 395 return; 396 397 $groups = array(); 398 399 // If a group_id was supplied, we generate the quickjump cache for that group only 400 if ($group_id !== false) 401 $groups[0] = $group_id; 402 else 403 { 404 // A group_id was not supplied, so we generate the quickjump cache for all groups 405 $query = array( 406 'SELECT' => 'g.g_id', 407 'FROM' => 'groups AS g' 408 ); 409 410 ($hook = get_hook('ch_fn_clean_quickjump_cache_qr_get_groups')) ? eval($hook) : null; 411 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 412 413 while ($cur_group = $forum_db->fetch_assoc($result)) 414 { 415 $groups[] = $cur_group['g_id']; 416 } 417 } 418 419 // Loop through the groups in $groups and output the cache for each of them 420 foreach ($groups as $group_id) 421 { 422 // Output quickjump as PHP code 423 $qj_cache_file = FORUM_CACHE_DIR.'cache_quickjump_'.$group_id.'.php'; 424 if (file_exists($qj_cache_file)) 425 { 426 unlink($qj_cache_file); 427 } 428 } 429} 430 431 432 433// 434// Generate the hooks cache PHP script 435// 436function generate_hooks_cache() 437{ 438 global $forum_db, $forum_config, $base_url; 439 440 $return = ($hook = get_hook('ch_fn_generate_hooks_cache_start')) ? eval($hook) : null; 441 if ($return !== null) 442 return; 443 444 // Get the hooks from the DB 445 $query = array( 446 'SELECT' => 'eh.id, eh.code, eh.extension_id, e.dependencies', 447 'FROM' => 'extension_hooks AS eh', 448 'JOINS' => array( 449 array( 450 'INNER JOIN' => 'extensions AS e', 451 'ON' => 'e.id=eh.extension_id' 452 ) 453 ), 454 'WHERE' => 'e.disabled=0', 455 'ORDER BY' => 'eh.priority, eh.installed' 456 ); 457 458 ($hook = get_hook('ch_fn_generate_hooks_cache_qr_get_hooks')) ? eval($hook) : null; 459 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 460 461 $output = array(); 462 while ($cur_hook = $forum_db->fetch_assoc($result)) 463 { 464 $load_ext_info = '$GLOBALS[\'ext_info_stack\'][] = array('."\n". 465 '\'id\' => \''.$cur_hook['extension_id'].'\','."\n". 466 '\'path\' => FORUM_ROOT.\'extensions/'.$cur_hook['extension_id'].'\','."\n". 467 '\'url\' => $GLOBALS[\'base_url\'].\'/extensions/'.$cur_hook['extension_id'].'\','."\n". 468 '\'dependencies\' => array ('."\n"; 469 470 $dependencies = explode('|', substr($cur_hook['dependencies'], 1, -1)); 471 foreach ($dependencies as $cur_dependency) 472 { 473 // This happens if there are no dependencies because explode ends up returning an array with one empty element 474 if (empty($cur_dependency)) 475 continue; 476 477 $load_ext_info .= '\''.$cur_dependency.'\' => array('."\n". 478 '\'id\' => \''.$cur_dependency.'\','."\n". 479 '\'path\' => FORUM_ROOT.\'extensions/'.$cur_dependency.'\','."\n". 480 '\'url\' => $GLOBALS[\'base_url\'].\'/extensions/'.$cur_dependency.'\'),'."\n"; 481 } 482 483 $load_ext_info .= ')'."\n".');'."\n".'$ext_info = $GLOBALS[\'ext_info_stack\'][count($GLOBALS[\'ext_info_stack\']) - 1];'; 484 $unload_ext_info = 'array_pop($GLOBALS[\'ext_info_stack\']);'."\n".'$ext_info = empty($GLOBALS[\'ext_info_stack\']) ? array() : $GLOBALS[\'ext_info_stack\'][count($GLOBALS[\'ext_info_stack\']) - 1];'; 485 486 $output[$cur_hook['id']][] = $load_ext_info."\n\n".$cur_hook['code']."\n\n".$unload_ext_info."\n"; 487 } 488 489 // Output hooks as PHP code 490 if (!write_cache_file(FORUM_CACHE_DIR.'cache_hooks.php', '<?php'."\n\n".'define(\'FORUM_HOOKS_LOADED\', 1);'."\n\n".'$forum_hooks = '.var_export($output, true).';'."\n\n".'?>')) 491 { 492 error('Unable to write hooks cache file to cache directory.<br />Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__); 493 } 494} 495 496 497// 498// Generate the updates cache PHP script 499// 500function generate_updates_cache() 501{ 502 global $forum_db, $forum_config; 503 504 $return = ($hook = get_hook('ch_fn_generate_updates_cache_start')) ? eval($hook) : null; 505 if ($return !== null) 506 return; 507 508 // Get a list of installed hotfix extensions 509 $query = array( 510 'SELECT' => 'e.id', 511 'FROM' => 'extensions AS e', 512 'WHERE' => 'e.id LIKE \'hotfix_%\'' 513 ); 514 515 ($hook = get_hook('ch_fn_generate_updates_cache_qr_get_hotfixes')) ? eval($hook) : null; 516 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 517 518 $hotfixes = array(); 519 while ($cur_ext_hotfix = $forum_db->fetch_assoc($result)) 520 { 521 $hotfixes[] = urlencode($cur_ext_hotfix['id']); 522 } 523 524 // Contact the punbb.informer.com updates service 525 $result = get_remote_file('https://punbb.informer.com/update/?type=xml&version='.urlencode($forum_config['o_cur_version']).'&hotfixes='.implode(',', $hotfixes), 8); 526 527 // Make sure we got everything we need 528 if ($result != null && strpos($result['content'], '</updates>') !== false) 529 { 530 if (!defined('FORUM_XML_FUNCTIONS_LOADED')) 531 require FORUM_ROOT.'include/xml.php'; 532 533 $output = xml_to_array(forum_trim($result['content'])); 534 $output = current($output); 535 536 if (!empty($output['hotfix']) && is_array($output['hotfix']) && !is_array(current($output['hotfix']))) 537 $output['hotfix'] = array($output['hotfix']); 538 539 $output['cached'] = time(); 540 $output['fail'] = false; 541 } 542 else // If the update check failed, set the fail flag 543 $output = array('cached' => time(), 'fail' => true); 544 545 // This hook could potentially (and responsibly) be used by an extension to do its own little update check 546 ($hook = get_hook('ch_fn_generate_updates_cache_write')) ? eval($hook) : null; 547 548 // Output update status as PHP code 549 if (!write_cache_file(FORUM_CACHE_DIR.'cache_updates.php', '<?php'."\n\n".'if (!defined(\'FORUM_UPDATES_LOADED\')) define(\'FORUM_UPDATES_LOADED\', 1);'."\n\n".'$forum_updates = '.var_export($output, true).';'."\n\n".'?>')) 550 { 551 error('Unable to write updates cache file to cache directory.<br />Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__); 552 } 553} 554 555function generate_ext_versions_cache($inst_exts, $repository_urls, $repository_url_by_extension) 556{ 557 $forum_ext_last_versions = array(); 558 $forum_ext_repos = array(); 559 560 foreach (array_unique(array_merge($repository_urls, $repository_url_by_extension)) as $url) 561 { 562 // Get repository timestamp 563 $remote_file = get_remote_file($url.'/timestamp', 2); 564 $repository_timestamp = empty($remote_file['content']) ? '' : forum_trim($remote_file['content']); 565 unset($remote_file); 566 if (!is_numeric($repository_timestamp)) 567 continue; 568 569 if (!isset($forum_ext_repos[$url]['timestamp'])) 570 $forum_ext_repos[$url]['timestamp'] = $repository_timestamp; 571 572 if ($forum_ext_repos[$url]['timestamp'] <= $repository_timestamp) 573 { 574 foreach ($inst_exts as $ext) 575 { 576 577 if ((0 === strpos($ext['id'], 'pun_') AND FORUM_PUN_EXTENSION_REPOSITORY_URL != $url) OR 578 ((FALSE === strpos($ext['id'], 'pun_') AND !isset($ext['repo_url'])) OR (isset($ext['repo_url']) AND $ext['repo_url'] != $url))) 579 continue; 580 581 $remote_file = get_remote_file($url.'/'.$ext['id'].'/lastversion', 2); 582 $version = empty($remote_file['content']) ? '' : forum_trim($remote_file['content']); 583 unset($remote_file); 584 if (empty($version) || !preg_match('~^[0-9a-zA-Z\. +-]+$~u', $version)) 585 continue; 586 587 $forum_ext_repos[$url]['extension_versions'][$ext['id']] = $version; 588 589 // If key with current extension exist in array, compare it with version in repository 590 if (!isset($forum_ext_last_versions[$ext['id']]) || (version_compare($forum_ext_last_versions[$ext['id']]['version'], $version, '<'))) 591 { 592 $forum_ext_last_versions[$ext['id']] = array('version' => $version, 'repo_url' => $url); 593 594 $remote_file = get_remote_file($url.'/'.$ext['id'].'/lastchanges', 2); 595 $last_changes = empty($remote_file['content']) ? '' : forum_trim($remote_file['content']); 596 unset($remote_file); 597 if (!empty($last_changes)) 598 $forum_ext_last_versions[$ext['id']]['changes'] = $last_changes; 599 } 600 } 601 602 // Write timestamp to cache 603 $forum_ext_repos[$url]['timestamp'] = $repository_timestamp; 604 } 605 } 606 607 if (array_keys($forum_ext_last_versions) != array_keys($inst_exts)) 608 foreach ($inst_exts as $ext) 609 if (!in_array($ext['id'], array_keys($forum_ext_last_versions))) 610 $forum_ext_last_versions[$ext['id']] = array('version' => $ext['version'], 'repo_url' => '', 'changes' => ''); 611 612 ($hook = get_hook('ch_generate_ext_versions_cache_check_repository')) ? eval($hook) : null; 613 614 // Output config as PHP code 615 if (!write_cache_file(FORUM_CACHE_DIR.'cache_ext_version_notifications.php', '<?php'."\n\n".'if (!defined(\'FORUM_EXT_VERSIONS_LOADED\')) define(\'FORUM_EXT_VERSIONS_LOADED\', 1);'."\n\n".'$forum_ext_repos = '.var_export($forum_ext_repos, true).';'."\n\n".' $forum_ext_last_versions = '.var_export($forum_ext_last_versions, true).";\n\n".'$forum_ext_versions_update_cache = '.time().";\n\n".'?>')) 616 { 617 error('Unable to write configuration cache file to cache directory.<br />Please make sure PHP has write access to the directory \'cache\'.', __FILE__, __LINE__); 618 } 619} 620 621define('FORUM_CACHE_FUNCTIONS_LOADED', 1); 622