Textpattern PHP Cross Reference Content Management Systems

Source: /textpattern/include/txp_diag.php - 675 lines - 21636 bytes - Summary - Text - Print

Description: Diagnostics panel.

   1  <?php
   2  
   3  /*
   4   * Textpattern Content Management System
   5   * http://textpattern.com
   6   *
   7   * Copyright (C) 2005 Dean Allen
   8   * Copyright (C) 2016 The Textpattern Development Team
   9   *
  10   * This file is part of Textpattern.
  11   *
  12   * Textpattern is free software; you can redistribute it and/or
  13   * modify it under the terms of the GNU General Public License
  14   * as published by the Free Software Foundation, version 2.
  15   *
  16   * Textpattern is distributed in the hope that it will be useful,
  17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19   * GNU General Public License for more details.
  20   *
  21   * You should have received a copy of the GNU General Public License
  22   * along with Textpattern. If not, see <http://www.gnu.org/licenses/>.
  23   */
  24  
  25  /**
  26   * Diagnostics panel.
  27   *
  28   * @package Admin\Diag
  29   */
  30  
  31  if (!defined('txpinterface')) {
  32      die('txpinterface is undefined.');
  33  }
  34  
  35  /**
  36   * @ignore
  37   */
  38  
  39  define("cs", ': ');
  40  
  41  /**
  42   * @ignore
  43   */
  44  
  45  define("ln", str_repeat('-', 24).n);
  46  
  47  global $files;
  48  
  49  $files = check_file_integrity();
  50  
  51  if (!$files) {
  52      $files = array();
  53  } else {
  54      $files = array_keys($files);
  55  }
  56  
  57  if ($event == 'diag') {
  58      require_privs('diag');
  59  
  60      $step = gps('step');
  61      doDiagnostics();
  62  }
  63  
  64  /**
  65   * Checks if the given Apache module is installed and active.
  66   *
  67   * @param  string $m The module
  68   * @return bool|null TRUE on success, NULL or FALSE on error
  69   */
  70  
  71  function apache_module($m)
  72  {
  73      $modules = @apache_get_modules();
  74  
  75      if (is_array($modules)) {
  76          return in_array($m, $modules);
  77      }
  78  }
  79  
  80  /**
  81   * Verifies temporary directory status.
  82   *
  83   * This function verifies that the given temporary directory is writeable.
  84   *
  85   * @param  string $dir The directory to check
  86   * @return bool|null NULL on error, TRUE on success
  87   */
  88  
  89  function test_tempdir($dir)
  90  {
  91      $f = realpath(tempnam($dir, 'txp_'));
  92  
  93      if (is_file($f)) {
  94          @unlink($f);
  95  
  96          return true;
  97      }
  98  }
  99  
 100  /**
 101   * Lists all database tables used by the Textpattern core.
 102   *
 103   * Returned tables include prefixes.
 104   *
 105   * @return array
 106   */
 107  
 108  function list_txp_tables()
 109  {
 110      $table_names = array(PFX.'textpattern');
 111      $rows = getRows("SHOW TABLES LIKE '".PFX."txp\_%'");
 112  
 113      foreach ($rows as $row) {
 114          $table_names[] = array_shift($row);
 115      }
 116  
 117      return $table_names;
 118  }
 119  
 120  /**
 121   * Checks the status of the given database tables.
 122   *
 123   * @param  array  $tables   The tables to check
 124   * @param  string $type     Check type, either FOR UPGRADE, QUICK, FAST, MEDIUM, EXTENDED, CHANGED
 125   * @param  bool   $warnings If TRUE, displays warnings
 126   * @return array An array of table statuses
 127   * @example
 128   * print_r(
 129   *     check_tables(list_txp_tables())
 130   * );
 131   */
 132  
 133  function check_tables($tables, $type = 'FAST', $warnings = 0)
 134  {
 135      $msgs = array();
 136  
 137      foreach ($tables as $table) {
 138          $rs = getRows("CHECK TABLE `$table` $type");
 139          if ($rs) {
 140              foreach ($rs as $r) {
 141                  if ($r['Msg_type'] != 'status' and ($warnings or $r['Msg_type'] != 'warning')) {
 142                      $msgs[] = $table.cs.$r['Msg_type'].cs.$r['Msg_text'];
 143                  }
 144              }
 145          }
 146      }
 147  
 148      return $msgs;
 149  }
 150  
 151  /**
 152   * Renders a diagnostics message block.
 153   *
 154   * @param  string $msg  The message
 155   * @param  string $type The message type
 156   * @return string HTML
 157   * @access private
 158   */
 159  
 160  function diag_msg_wrap($msg, $type = 'error')
 161  {
 162      return span($msg, array('class' => $type));
 163  }
 164  
 165  /**
 166   * Outputs a diagnostics report.
 167   *
 168   * This is the main panel.
 169   */
 170  
 171  function doDiagnostics()
 172  {
 173      global $prefs, $files, $txpcfg, $event, $step, $theme, $DB, $txp_using_svn;
 174      extract(get_prefs());
 175  
 176      $urlparts = parse_url(hu);
 177      $mydomain = $urlparts['host'];
 178  
 179      $is_apache = stristr(serverSet('SERVER_SOFTWARE'), 'Apache') || is_callable('apache_get_version');
 180      $real_doc_root = (isset($_SERVER['DOCUMENT_ROOT'])) ? realpath($_SERVER['DOCUMENT_ROOT']) : '';
 181  
 182      // ini_get() returns string values passed via php_value as a string,
 183      // not boolean.
 184      $is_register_globals = ((strcasecmp(ini_get('register_globals'), 'on') === 0) or (ini_get('register_globals') === '1'));
 185  
 186      $fail = array();
 187      $now = time();
 188  
 189      if (!$txp_using_svn) {
 190          // Check for Textpattern updates, at most once every 24 hours.
 191          $updateInfo = unserialize(get_pref('last_update_check', ''));
 192  
 193          if (!$updateInfo || ($now > ($updateInfo['when'] + (60 * 60 * 24)))) {
 194              $updates = checkUpdates();
 195              $updateInfo['msg'] = ($updates) ? gTxt($updates['msg'], array('{version}' => $updates['version'])) : '';
 196              $updateInfo['when'] = $now;
 197              set_pref('last_update_check', serialize($updateInfo), 'publish', PREF_HIDDEN, 'text_input');
 198          }
 199  
 200          if (!empty($updateInfo['msg'])) {
 201              $fail['textpattern_version_update'] = diag_msg_wrap($updateInfo['msg'], 'information');
 202          }
 203      }
 204  
 205      if (!is_callable('version_compare') || version_compare(PHP_VERSION, REQUIRED_PHP_VERSION, '<')) {
 206          $fail['php_version_required'] = diag_msg_wrap(gTxt('php_version_required', array('{version}' => REQUIRED_PHP_VERSION)));
 207      }
 208  
 209      if (@gethostbyname($mydomain) === $mydomain) {
 210          $fail['dns_lookup_fails'] = diag_msg_wrap(gTxt('dns_lookup_fails').cs.$mydomain, 'warning');
 211      }
 212  
 213      if (!@is_dir($path_to_site)) {
 214          $fail['path_to_site_inacc'] = diag_msg_wrap(gTxt('path_to_site_inacc').cs.$path_to_site);
 215      }
 216  
 217      if (rtrim($siteurl, '/') != $siteurl) {
 218          $fail['site_trailing_slash'] = diag_msg_wrap(gTxt('site_trailing_slash').cs.$path_to_site, 'warning');
 219      }
 220  
 221      if (!@is_file($path_to_site."/index.php") || !@is_readable($path_to_site."/index.php")) {
 222          $fail['index_inaccessible'] = diag_msg_wrap("{$path_to_site}/index.php ".gTxt('is_inaccessible'));
 223      }
 224  
 225      $not_readable = array();
 226  
 227      if (!@is_writable($path_to_site.'/'.$img_dir)) {
 228          $not_readable[] = diag_msg_wrap(str_replace('{dirtype}', gTxt('img_dir'), gTxt('dir_not_writable')).": {$path_to_site}/{$img_dir}", 'warning');
 229      }
 230  
 231      if (!@is_writable($file_base_path)) {
 232          $not_readable[] = diag_msg_wrap(str_replace('{dirtype}', gTxt('file_base_path'), gTxt('dir_not_writable')).": {$file_base_path}", 'warning');
 233      }
 234  
 235      if (!@is_writable($tempdir)) {
 236          $not_readable[] = diag_msg_wrap(str_replace('{dirtype}', gTxt('tempdir'), gTxt('dir_not_writable')).": {$tempdir}", 'warning');
 237      }
 238  
 239      if ($not_readable) {
 240          $fail['dir_not_writable'] = join(n, $not_readable);
 241      }
 242  
 243      if ($permlink_mode != 'messy' && !$is_apache) {
 244          $fail['cleanurl_only_apache'] = diag_msg_wrap(gTxt('cleanurl_only_apache'), 'information');
 245      }
 246  
 247      if ($permlink_mode != 'messy' and !@is_readable($path_to_site.'/.htaccess')) {
 248          $fail['htaccess_missing'] = diag_msg_wrap(gTxt('htaccess_missing'));
 249      }
 250  
 251      if ($permlink_mode != 'messy' and is_callable('apache_get_modules') and !apache_module('mod_rewrite')) {
 252          $fail['mod_rewrite_missing'] = diag_msg_wrap(gTxt('mod_rewrite_missing'));
 253      }
 254  
 255      if (!ini_get('file_uploads')) {
 256          $fail['file_uploads_disabled'] = diag_msg_wrap(gTxt('file_uploads_disabled'), 'information');
 257      }
 258  
 259      if (@is_dir(txpath.DS.'setup')) {
 260          $fail['setup_still_exists'] = diag_msg_wrap(txpath.DS."setup".DS.' '.gTxt('still_exists'), 'warning');
 261      }
 262  
 263      if (empty($tempdir)) {
 264          $fail['no_temp_dir'] = diag_msg_wrap(gTxt('no_temp_dir'), 'warning');
 265      }
 266  
 267      if (is_disabled('mail')) {
 268          $fail['warn_mail_unavailable'] = diag_msg_wrap(gTxt('warn_mail_unavailable'), 'warning');
 269      }
 270  
 271      if ($is_register_globals) {
 272          $fail['warn_register_globals_or_update'] = diag_msg_wrap(gTxt('warn_register_globals_or_update'), 'warning');
 273      }
 274  
 275      if ($permlink_mode != 'messy') {
 276          $rs = safe_column("name", 'txp_section', "1 = 1");
 277  
 278          foreach ($rs as $name) {
 279              if ($name and @file_exists($path_to_site.'/'.$name)) {
 280                  $fail['old_placeholder_exists'] = diag_msg_wrap(gTxt('old_placeholder').": {$path_to_site}/{$name}");
 281              }
 282          }
 283      }
 284  
 285      $cs = check_file_integrity(INTEGRITY_REALPATH);
 286  
 287      if (!$cs) {
 288          $cs = array();
 289      }
 290  
 291      // Files that don't match their checksums.
 292      if (!$txp_using_svn and $modified_files = array_keys($cs, INTEGRITY_MODIFIED)) {
 293          $fail['modified_files'] = diag_msg_wrap(gTxt('modified_files').cs.n.t.join(', '.n.t, $modified_files), 'warning');
 294      }
 295  
 296      // Running development code in live mode is not recommended.
 297      if (preg_match('/-dev$/', txp_version) and $production_status == 'live') {
 298          $fail['dev_version_live'] = diag_msg_wrap(gTxt('dev_version_live'), 'warning');
 299      }
 300  
 301      // Missing files.
 302      if ($missing = array_merge(
 303          array_keys($cs, INTEGRITY_MISSING),
 304          array_keys($cs, INTEGRITY_NOT_FILE),
 305          array_keys($cs, INTEGRITY_NOT_READABLE)
 306      )) {
 307          $fail['missing_files'] = diag_msg_wrap(gTxt('missing_files').cs.n.t.join(', '.n.t, $missing));
 308      }
 309  
 310      // Anything might break if arbitrary functions are disabled.
 311      if (ini_get('disable_functions')) {
 312          $disabled_funcs = array_map('trim', explode(',', ini_get('disable_functions')));
 313          // Commonly disabled functions that we don't need.
 314          $disabled_funcs = array_diff($disabled_funcs, array(
 315              'imagefilltoborder',
 316              'escapeshellarg',
 317              'escapeshellcmd',
 318              'exec',
 319              'passthru',
 320              'proc_close',
 321              'proc_get_status',
 322              'proc_nice',
 323              'proc_open',
 324              'proc_terminate',
 325              'shell_exec',
 326              'system',
 327              'popen',
 328              'dl',
 329              'chown',
 330          ));
 331  
 332          if ($disabled_funcs) {
 333              $fail['some_php_functions_disabled'] = diag_msg_wrap(gTxt('some_php_functions_disabled').cs.join(', ', $disabled_funcs), 'warning');
 334          }
 335      }
 336  
 337      // Not sure about this one.
 338  //    if (strncmp(php_sapi_name(), 'cgi', 3) == 0 and ini_get('cgi.rfc2616_headers'))
 339  //    $fail['cgi_header_config'] = gTxt('cgi_header_config');
 340  
 341      $guess_site_url = $_SERVER['HTTP_HOST'].preg_replace('#[/\\\\]$#', '', dirname(dirname($_SERVER['SCRIPT_NAME'])));
 342  
 343      if ($siteurl and strip_prefix($siteurl, 'www.') != strip_prefix($guess_site_url, 'www.')) {
 344          $fail['site_url_mismatch'] = diag_msg_wrap(gTxt('site_url_mismatch').cs.$guess_site_url, 'warning');
 345      }
 346  
 347      // Test clean URL server vars.
 348      if (hu) {
 349          if (ini_get('allow_url_fopen') and ($permlink_mode != 'messy')) {
 350              $s = md5(uniqid(rand(), true));
 351              ini_set('default_socket_timeout', 10);
 352  
 353              $pretext_data = @file(hu.$s.'/?txpcleantest=1');
 354  
 355              if ($pretext_data) {
 356                  $pretext_req = trim(@$pretext_data[0]);
 357  
 358                  if ($pretext_req != md5('/'.$s.'/?txpcleantest=1')) {
 359                      $fail['clean_url_data_failed'] = diag_msg_wrap(gTxt('clean_url_data_failed').cs.txpspecialchars($pretext_req), 'warning');
 360                  }
 361              } else {
 362                  $fail['clean_url_test_failed'] = diag_msg_wrap(gTxt('clean_url_test_failed'), 'warning');
 363              }
 364          }
 365      }
 366  
 367      if ($tables = list_txp_tables()) {
 368          $table_errors = check_tables($tables);
 369          if ($table_errors) {
 370              $fail['mysql_table_errors'] = diag_msg_wrap(gTxt('mysql_table_errors').cs.n.t.join(', '.n.t, $table_errors));
 371          }
 372      }
 373  
 374      $active_plugins = array();
 375      if ($rows = safe_rows("name, version, code_md5, MD5(code) AS md5", 'txp_plugin', "status > 0")) {
 376          foreach ($rows as $row) {
 377              $n = $row['name'].'-'.$row['version'];
 378  
 379              if (strtolower($row['md5']) != strtolower($row['code_md5'])) {
 380                  $n .= 'm';
 381              }
 382  
 383              $active_plugins[] = $n;
 384          }
 385      }
 386  
 387      $theme_manifest = $theme->manifest();
 388  
 389      // Check GD info.
 390      if (function_exists('gd_info')) {
 391          $gd_info = gd_info();
 392  
 393          $gd_support = array();
 394  
 395          if ($gd_info['GIF Create Support']) {
 396              $gd_support[] = 'GIF';
 397          }
 398  
 399           // Aside: In PHP 5.3, they chose to add a previously unemployed capital
 400           // "E" to the array key.
 401          if (!empty($gd_info['JPEG Support']) || !empty($gd_info['JPG Support'])) {
 402              $gd_support[] = 'JPG';
 403          }
 404  
 405          if ($gd_info['PNG Support']) {
 406              $gd_support[] = 'PNG';
 407          }
 408  
 409          if ($gd_support) {
 410              $gd_support = join(', ', $gd_support);
 411          } else {
 412              $gd_support = gTxt('none');
 413          }
 414  
 415          $gd = gTxt('gd_info', array(
 416              '{version}'   => $gd_info['GD Version'],
 417              '{supported}' => $gd_support,
 418          ));
 419      } else {
 420          $gd = gTxt('gd_unavailable');
 421      }
 422  
 423      if (realpath($prefs['tempdir']) === realpath($prefs['plugin_cache_dir'])) {
 424          $fail['tmp_plugin_paths_match'] = diag_msg_wrap(gTxt('tmp_plugin_paths_match'));
 425      }
 426  
 427      // Database server time.
 428      extract(doSpecial(getRow("SELECT @@global.time_zone AS db_global_timezone, @@session.time_zone AS db_session_timezone, NOW() AS db_server_time, UNIX_TIMESTAMP(NOW()) AS db_server_timestamp")));
 429      $db_server_timeoffset = $db_server_timestamp - $now;
 430  
 431      echo pagetop(gTxt('tab_diagnostics'), '');
 432  
 433      echo n.'<div class="txp-layout">'.
 434          n.tag(
 435              hed(gTxt('tab_diagnostics'), 1, array('class' => 'txp-heading')),
 436              'div', array('class' => 'txp-layout-1col')
 437          ).
 438          n.tag_start('div', array(
 439              'class' => 'txp-layout-1col',
 440              'id'    => $event.'_container',
 441          )).
 442          n.tag_start('div', array('id' => 'pre_flight_check')).
 443          hed(gTxt('preflight_check'), 2);
 444  
 445      if ($fail) {
 446          foreach ($fail as $help => $message) {
 447              echo graf(nl2br($message).popHelp($help));
 448          }
 449      } else {
 450          echo graf(diag_msg_wrap(gTxt('all_checks_passed'), 'success'));
 451      }
 452  
 453      echo n.tag_end('div'). // End of #pre_flight_check.
 454          n.tag_start('div', array('id' => 'diagnostics')).
 455          hed(gTxt('diagnostic_info'), 2);
 456  
 457      $fmt_date = '%Y-%m-%d %H:%M:%S';
 458  
 459      $dets = array(
 460          'low'  => gTxt('low'),
 461          'high' => gTxt('high'),
 462      );
 463  
 464      $out = array(
 465          form(
 466              eInput('diag').
 467              inputLabel(
 468                  'diag_detail_level',
 469                  selectInput('step', $dets, $step, 0, 1, 'diag_detail_level'),
 470                  'detail',
 471                  '',
 472                  array('class' => 'txp-form-field diagnostic-details-level'),
 473                  ''
 474              )
 475          ),
 476  
 477          '<textarea class="code" id="diagnostics-detail" cols="'.INPUT_LARGE.'" rows="'.TEXTAREA_HEIGHT_LARGE.'" dir="ltr" readonly>',
 478  
 479          gTxt('txp_version').cs.txp_version.' ('.check_file_integrity(INTEGRITY_DIGEST).')'.n,
 480  
 481          gTxt('last_update').cs.gmstrftime($fmt_date, $dbupdatetime).'/'.gmstrftime($fmt_date, @filemtime(txpath.'/update/_update.php')).n,
 482  
 483          gTxt('document_root').cs.@$_SERVER['DOCUMENT_ROOT'].(($real_doc_root != @$_SERVER['DOCUMENT_ROOT']) ? ' ('.$real_doc_root.')' : '').n,
 484  
 485          '$path_to_site'.cs.$path_to_site.n,
 486  
 487          gTxt('txp_path').cs.txpath.n,
 488  
 489          gTxt('permlink_mode').cs.$permlink_mode.n,
 490  
 491          (ini_get('open_basedir')) ? 'open_basedir: '.ini_get('open_basedir').n : '',
 492  
 493          (ini_get('upload_tmp_dir')) ? 'upload_tmp_dir: '.ini_get('upload_tmp_dir').n : '',
 494  
 495          gTxt('tempdir').cs.$tempdir.n,
 496  
 497          gTxt('web_domain').cs.$siteurl.n,
 498  
 499          gTxt('php_version').cs.phpversion().n,
 500  
 501          ($is_register_globals) ? gTxt('register_globals').cs.$is_register_globals.n : '',
 502  
 503          gTxt('gd_library').cs.$gd.n,
 504  
 505          gTxt('server').' TZ: '.Txp::get('\Textpattern\Date\Timezone')->getTimeZone().n,
 506          gTxt('server_time').cs.strftime('%Y-%m-%d %H:%M:%S').n,
 507          strip_tags(gTxt('is_dst')).cs.$is_dst.n,
 508          strip_tags(gTxt('auto_dst')).cs.$auto_dst.n,
 509          strip_tags(gTxt('gmtoffset')).cs.$timezone_key.sp."($gmtoffset)".n,
 510  
 511          'MySQL'.cs.mysqli_get_server_info($DB->link).n,
 512          gTxt('db_server_time').cs.$db_server_time.n,
 513          gTxt('db_server_timeoffset').cs.$db_server_timeoffset.' s'.n,
 514          gTxt('db_global_timezone').cs.$db_global_timezone.n,
 515          gTxt('db_session_timezone').cs.$db_session_timezone.n,
 516  
 517          gTxt('locale').cs.$locale.n,
 518  
 519          (isset($_SERVER['SERVER_SOFTWARE'])) ? gTxt('server').cs.$_SERVER['SERVER_SOFTWARE'].n : '',
 520  
 521          (is_callable('apache_get_version')) ? gTxt('apache_version').cs.@apache_get_version().n : '',
 522  
 523          gTxt('php_sapi_mode').cs.PHP_SAPI.n,
 524  
 525          gTxt('rfc2616_headers').cs.ini_get('cgi.rfc2616_headers').n,
 526  
 527          gTxt('os_version').cs.php_uname('s').' '.php_uname('r').n,
 528  
 529          ($active_plugins ? gTxt('active_plugins').cs.join(', ', $active_plugins).n : ''),
 530  
 531          gTxt('theme_name').cs.$theme_name.sp.$theme_manifest['version'].n,
 532  
 533          $fail
 534          ? n.gTxt('preflight_check').cs.n.ln.join("\n", doStripTags($fail)).n.ln
 535          : '',
 536  
 537          (is_readable($path_to_site.'/.htaccess'))
 538          ?    n.gTxt('htaccess_contents').cs.n.ln.txpspecialchars(join('', file($path_to_site.'/.htaccess'))).n.ln
 539          :    '',
 540      );
 541  
 542      if ($step == 'high') {
 543          $out[] = n.'Charset (default/config)'.cs.$DB->default_charset.'/'.$DB->charset.n;
 544  
 545          $result = safe_query("SHOW variables LIKE 'character_se%'");
 546  
 547          while ($row = mysqli_fetch_row($result)) {
 548              $out[] = $row[0].cs.$row[1].n;
 549  
 550              if ($row[0] == 'character_set_connection') {
 551                  $conn_char = $row[1];
 552              }
 553          }
 554  
 555          $table_names = array(PFX.'textpattern');
 556          $result = safe_query("SHOW TABLES LIKE '".PFX."txp\_%'");
 557  
 558          while ($row = mysqli_fetch_row($result)) {
 559              $table_names[] = $row[0];
 560          }
 561  
 562          $table_msg = array();
 563  
 564          foreach ($table_names as $table) {
 565              $ctr = safe_query("SHOW CREATE TABLE $table");
 566              if (!$ctr) {
 567                  unset($table_names[$table]);
 568                  continue;
 569              }
 570  
 571              $row = mysqli_fetch_assoc($ctr);
 572              $ctcharset = preg_replace('#^CREATE TABLE.*SET=([^ ]+)[^)]*$#is', '\\1', $row['Create Table']);
 573              if (isset($conn_char) && !stristr($ctcharset, 'CREATE') && ($conn_char != $ctcharset)) {
 574                  $table_msg[] = "$table is $ctcharset";
 575              }
 576  
 577              $ctr = safe_query("CHECK TABLE $table");
 578              $row = mysqli_fetch_assoc($ctr);
 579              if (in_array($row['Msg_type'], array('error', 'warning'))) {
 580                  $table_msg[] = $table.cs.$row['Msg_Text'];
 581              }
 582          }
 583  
 584          if ($table_msg == array()) {
 585              $table_msg = (count($table_names) < 17) ?  array('-') : array('OK');
 586          }
 587  
 588          $out[] = count($table_names).' Tables'.cs.implode(', ', $table_msg).n;
 589  
 590          $cf = preg_grep('/^custom_\d+/', getThings("DESCRIBE `".PFX."textpattern`"));
 591          $out[] = n.get_pref('max_custom_fields', 10).sp.gTxt('custom').cs.
 592                      implode(', ', $cf).sp.'('.count($cf).')'.n;
 593  
 594          $extns = get_loaded_extensions();
 595          $extv = array();
 596  
 597          foreach ($extns as $e) {
 598              $extv[] = $e.(phpversion($e) ? '/'.phpversion($e) : '');
 599          }
 600  
 601          $out[] = n.gTxt('php_extensions').cs.join(', ', $extv).n;
 602  
 603          if (is_callable('apache_get_modules')) {
 604              $out[] = n.gTxt('apache_modules').cs.join(', ', apache_get_modules()).n;
 605          }
 606  
 607          if (@is_array($pretext_data) and count($pretext_data) > 1) {
 608              $out[] = n.gTxt('pretext_data').cs.txpspecialchars(join('', array_slice($pretext_data, 1, 20))).n;
 609          }
 610  
 611          $out[] = n;
 612  
 613          if ($md5s = check_file_integrity(INTEGRITY_MD5)) {
 614              foreach ($md5s as $f => $checksum) {
 615                  $out[] = $f.cs.n.t.(!$checksum ? gTxt('unknown') : $checksum).n;
 616              }
 617          }
 618  
 619          $out[] = n.ln;
 620      }
 621  
 622      $out[] = callback_event('diag_results', $step).n;
 623      $out[] = '</textarea>';
 624  
 625      echo join('', $out),
 626          n.tag_end('div'). // End of #diagnostics.
 627          n.tag_end('div'). // End of .txp-layout-1col.
 628          n.'</div>'; // End of .txp-layout.;
 629  }
 630  
 631  /**
 632   * Checks for Textpattern updates.
 633   *
 634   * This function uses XML-RPC to do an active remote connection to
 635   * rpc.textpattern.com. Created connections are not cached, scheduled or
 636   * delayed, and each subsequent call to the function creates a new connection.
 637   *
 638   * These connections do not transmit any identifiable information. Just an
 639   * anonymous UID assigned for the installation on the first run.
 640   *
 641   * @return  array|null When updates are found returns an array consisting keys 'version', 'msg'
 642   * @example
 643   * if ($updates = checkUpdates())
 644   * {
 645   *     echo "New version: {$updates['version']}";
 646   * }
 647   */
 648  
 649  function checkUpdates()
 650  {
 651      require_once txpath.'/lib/IXRClass.php';
 652      $client = new IXR_Client('http://rpc.textpattern.com');
 653  
 654      if (!$client->query('tups.getTXPVersion', get_pref('blog_uid'))) {
 655          return array('version' => 0, 'msg' => 'problem_connecting_rpc_server');
 656      } else {
 657          $out = array();
 658          $response = $client->getResponse();
 659  
 660          if (is_array($response)) {
 661              ksort($response);
 662              $version = get_pref('version');
 663  
 664              // Go through each available branch (x.y), but only return the
 665              // _highest_ version.
 666              foreach ($response as $key => $val) {
 667                  if (version_compare($version, $val) < 0) {
 668                      $out = array('version' => $val, 'msg' => 'textpattern_update_available');
 669                  }
 670              }
 671  
 672              return $out;
 673          }
 674      }
 675  }

title

Description

title

Description

title

Description

title

title

Body