Textpattern PHP Cross Reference Content Management Systems

Source: /textpattern/setup/setup_lib.php - 383 lines - 12942 bytes - Summary - Text - Print

   1  <?php
   2  
   3  /*
   4   * Textpattern Content Management System
   5   * https://textpattern.com/
   6   *
   7   * Copyright (C) 2020 The Textpattern Development Team
   8   *
   9   * This file is part of Textpattern.
  10   *
  11   * Textpattern is free software; you can redistribute it and/or
  12   * modify it under the terms of the GNU General Public License
  13   * as published by the Free Software Foundation, version 2.
  14   *
  15   * Textpattern is distributed in the hope that it will be useful,
  16   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18   * GNU General Public License for more details.
  19   *
  20   * You should have received a copy of the GNU General Public License
  21   * along with Textpattern. If not, see <https://www.gnu.org/licenses/>.
  22   */
  23  
  24  function setup_db($cfg = array())
  25  {
  26      global $txpcfg, $DB, $prefs, $txp_user, $txp_groups;
  27      global $permlink_mode, $siteurl, $adminurl, $theme_name, $public_themes, $step;
  28      include_once txpath.'/lib/txplib_db.php';
  29      include_once txpath.'/lib/admin_config.php';
  30  
  31      $siteurl = rtrim(@$cfg['site']['public_url'], '/');
  32  
  33      if (!preg_match('%^https?://%', $siteurl)) {
  34          $siteurl = 'http://'.$siteurl;
  35      }
  36  
  37      if (empty($cfg['site']['admin_url'])) {
  38          $adminurl = $siteurl.'/textpattern';
  39      } else {
  40          $adminurl = rtrim(@$cfg['site']['admin_url'], '/');
  41  
  42          if (!preg_match('%^https?://%', $adminurl)) {
  43              $adminurl = 'http://'.$adminurl;
  44          }
  45      }
  46  
  47      // Determine the mode of permanent links.
  48      ini_set('default_socket_timeout', 10);
  49      $s = md5(uniqid(rand(), true));
  50      $pretext_data = @file("{$siteurl}/{$s}/?txpcleantest=1");
  51  
  52      if (trim(@$pretext_data[0]) == md5("/{$s}/?txpcleantest=1")) {
  53          $permlink_mode = 'section_title';
  54      } else {
  55          $permlink_mode = 'messy';
  56      }
  57  
  58      // Variable set.
  59      @define('hu', $siteurl.'/');
  60      $siteurl = preg_replace('%^https?://%', '', $siteurl);
  61      $siteurl = str_replace(' ', '%20', $siteurl);
  62      $theme_name = empty($cfg['site']['admin_theme']) ? 'hive' : $cfg['site']['admin_theme'];
  63  
  64      $Skin = Txp::get('Textpattern\Skin\Skin');
  65  
  66      $setup_path = txpath.DS.'setup';
  67      $setup_themes_path = $setup_path.DS.'themes';
  68      $Skin->setDirPath($setup_themes_path);
  69      $setup_public_themes = $Skin->getUploaded();
  70  
  71      $root_themes_path = txpath.DS.'..'.DS.'themes';
  72      $Skin->setDirPath($root_themes_path);
  73      $root_public_themes = $Skin->getUploaded();
  74  
  75      $public_themes = array_merge($root_public_themes, $setup_public_themes);
  76  
  77      if (empty($cfg['site']['public_theme']) || !array_key_exists($cfg['site']['public_theme'], $public_themes)) {
  78          $public_theme = current(array_keys($public_themes));
  79      } else {
  80          $public_theme = $cfg['site']['public_theme'];
  81      }
  82  
  83      $is_from_setup = in_array($public_theme, array_keys($setup_public_themes));
  84  
  85      if (empty($cfg['site']['content_directory'])) {
  86          /*  Option 'txp-data' in manifest.json:
  87              <default>           - Import /articles and /data from setup dir
  88              txp-data == 'theme' - Import /articles and /data from theme dir
  89              txp-data == 'none'  - Nothing to import.
  90          */
  91  
  92          if (@$public_themes[$public_theme]['txp-data'] == 'theme') {
  93              $datadir = $is_from_setup ? $setup_themes_path.DS.$public_theme : $root_public_themes.DS.$public_theme;
  94          } elseif (@$public_themes[$public_theme]['txp-data'] == 'none') {
  95              $datadir = '';
  96          } else {
  97              $datadir = $setup_path;
  98          }
  99      } else {
 100          $datadir = $cfg['site']['content_directory'];
 101      }
 102  
 103      if (numRows(safe_query("SHOW TABLES LIKE '".PFX."textpattern'"))) {
 104          if (! empty($step)) {
 105              $step = 'step_printConfig';
 106              echo txp_setup_progress_meter(4).n.'<div class="txp-setup">';
 107          }
 108  
 109          msg(gTxt('tables_exist', array('{dbname}' => @$txpcfg['db'])), MSG_ERROR, true);
 110      }
 111  
 112      $setup = new \Textpattern\DB\Core();
 113  
 114      // Create tables
 115      $setup->createAllTables();
 116  
 117      // Initial mandatory data
 118      $setup->initData();
 119      msg(gTxt('creating_db_tables'));
 120  
 121      setup_txp_lang($cfg['site']['language_code']);
 122  
 123      // Create core prefs
 124      $setup->initPrefs();
 125  
 126      $prefs = get_prefs();
 127      $txp_user = $cfg['user']['login_name'];
 128  
 129      create_user($txp_user, $cfg['user']['email'], $cfg['user']['password'], $cfg['user']['full_name'], 1);
 130  
 131      if ($datadir) {
 132          /*  Load theme prefs:
 133                  /data/core.prefs    - Allow override some core prefs. Used only in setup theme.
 134                  /data/theme.prefs   - Theme global and private prefs.
 135                                          global  - Used in setup and for AutoCreate missing prefs.
 136                                          private - Will be created after user login
 137          */
 138          foreach (get_files_content($datadir.'/data', 'prefs') as $key => $data) {
 139              if ($out = @json_decode($data, true)) {
 140                  msg("Prefs: 'data/{$key}'");
 141  
 142                  foreach ($out as $name => $p) {
 143                      if (empty($p['private'])) {
 144                          @set_pref($name, $p['val'], $p['event'], $p['type'], $p['html'], $p['position']);
 145                      }
 146                  }
 147              }
 148          }
 149  
 150          $prefs = get_prefs();
 151          $plugin = new \Textpattern\Plugin\Plugin();
 152  
 153          foreach (get_files_content($datadir.'/plugin', 'txt') as $key => $data) {
 154              $result = $plugin->install($data, 1);
 155              msg("Plugin: '{$key}' - ".(is_array($result) ? $result[0] : $result));
 156          }
 157  
 158          $import = new \Textpattern\Import\TxpXML();
 159  
 160          foreach (get_files_content($datadir.'/data', 'xml') as $key => $data) {
 161              $import->importXml($data);
 162              msg("Import: 'data/{$key}'");
 163          }
 164  
 165          foreach (get_files_content($datadir.'/articles', 'xml') as $key => $data) {
 166              $import->importXml($data);
 167              msg("Import: 'articles/{$key}'");
 168          }
 169      }
 170  
 171      // --- Theme setup.
 172      // Import theme assets.
 173      msg(gTxt('public_theme').": '{$public_theme}'");
 174      $is_from_setup ? $Skin->setDirPath($setup_themes_path) : '';
 175      $Skin->setNames(array($public_theme))
 176           ->import()
 177           ->setBase('default')
 178           ->updateSections();
 179  
 180      // --- Theme setup end
 181  
 182      // Final rebuild category trees
 183      rebuild_tree_full('article');
 184      rebuild_tree_full('link');
 185      rebuild_tree_full('image');
 186      rebuild_tree_full('file');
 187  }
 188  
 189  /**
 190   * Installing Language Files
 191   *
 192   * @param  string $langs The desired language code or comma separated string
 193   */
 194  
 195  function setup_txp_lang($langs)
 196  {
 197      global $language;
 198  
 199      Txp::getContainer()->remove('\Textpattern\L10n\Lang');
 200  
 201      $langs = array_flip(do_list_unique($langs));
 202      unset($langs[$language]);
 203  
 204      if (!Txp::get('\Textpattern\L10n\Lang')->installFile($language)) {
 205          // If cannot install from lang file, setup the Default lang. `language` pref changed too.
 206          $language = TEXTPATTERN_DEFAULT_LANG;
 207          Txp::get('\Textpattern\L10n\Lang')->installFile($language);
 208          unset($langs[$language]);
 209      }
 210  
 211      msg("Lang: '{$language}'");
 212  
 213      foreach (array_flip($langs) as $lang) {
 214          Txp::get('\Textpattern\L10n\Lang')->installFile($lang);
 215          msg("Lang: '{$lang}'");
 216      }
 217  }
 218  
 219  /**
 220   * Merge the desired lang strings with fallbacks.
 221   *
 222   * The fallback language is guaranteed to exist, so any unknown strings
 223   * will be used from that pack to fill in any gaps.
 224   *
 225   * @param  string $langs The desired language code or comma separated string
 226   * @return array         The language-specific name-value pairs
 227   */
 228  
 229  function setup_load_lang($langs)
 230  {
 231      global $language;
 232  
 233      $langs = do_list($langs);
 234      $lang = $langs[0];
 235      $lang_path = txpath.DS.'setup'.DS.'lang'.DS;
 236      $group = 'common, setup';
 237      $strings = array();
 238  
 239      // Load the desired lang strings and default strings as fallbacks.
 240      $default_textpack = Txp::get('\Textpattern\L10n\Lang', $lang_path)->getPack(TEXTPATTERN_DEFAULT_LANG, $group);
 241      $lang_textpack = Txp::get('\Textpattern\L10n\Lang', $lang_path)->getPack($lang, $group);
 242  
 243      $language = empty($lang_textpack) ? TEXTPATTERN_DEFAULT_LANG : $lang;
 244      @define('LANG', $language);
 245  
 246      $allStrings = array_merge($default_textpack, $lang_textpack);
 247  
 248      // Merge the arrays, using the default language to fill in the blanks.
 249      foreach ($allStrings as $meta) {
 250          if (empty($strings[$meta['name']])) {
 251              $strings[$meta['name']] = $meta['data'];
 252          }
 253      }
 254  
 255      Txp::get('\Textpattern\L10n\Lang')->setPack($strings)
 256          ->setPack(array('help' => gTxt('setup_help')), true);
 257  
 258      return $strings;
 259  }
 260  
 261  /**
 262   * Generate a config.php file from the known info.
 263   */
 264  
 265  function setup_makeConfig($cfg, $doSpecial = false)
 266  {
 267      define("nl", "';\n");
 268      define("o", '$txpcfg[\'');
 269      define("m", "'] = '");
 270  
 271      // Escape single quotes and backslashes in literal PHP strings.
 272      foreach ($cfg['database'] as $k => $v) {
 273          $cfg['database'][$k] = addcslashes($cfg['database'][$k], "'\\");
 274      }
 275  
 276      if ($doSpecial) {
 277          $cfg['database'] = doSpecial($cfg['database']);
 278      }
 279  
 280      $config_details =
 281      "<"."?php\n"
 282      .o.'db'.m.$cfg['database']['db_name'].nl
 283      .o.'user'.m.$cfg['database']['user'].nl
 284      .o.'pass'.m.$cfg['database']['password'].nl
 285      .o.'host'.m.$cfg['database']['host'].nl
 286      .(empty($cfg['database']['client_flags']) ? '' : o.'client_flags'."'] = ".$cfg['database']['client_flags'].";\n")
 287      .o.'table_prefix'.m.$cfg['database']['table_prefix'].nl
 288      .o.'txpath'.m.txpath.nl
 289      .o.'dbcharset'.m.$cfg['database']['charset'].nl;
 290  
 291      if (defined('is_multisite')) {
 292          $config_details .=
 293               o.'multisite_root_path'.m.multisite_root_path.nl
 294              .o.'admin_url'.m.$cfg['site']['admin_url'].nl
 295              .o.'cookie_domain'.m.$cfg['site']['cookie_domain'].nl
 296              .'if (!defined(\'txpath\')) { define(\'txpath\', $txpcfg[\'txpath\']); }'."\n";
 297      }
 298  
 299      $config_details .=
 300      "// For more customization options, please consult config-dist.php file.";
 301  
 302      return $config_details;
 303  }
 304  
 305  /**
 306   * Try to connect to the database.
 307   *
 308   * Check the database and the table prefix.
 309   */
 310  
 311  function setup_connect()
 312  {
 313      global $cfg;
 314  
 315      if (strpos($cfg['database']['host'], ':') === false) {
 316          $dhost = $cfg['database']['host'];
 317          $dport = ini_get("mysqli.default_port");
 318      } else {
 319          list($dhost, $dport) = explode(':', $cfg['database']['host'], 2);
 320          $dport = intval($dport);
 321      }
 322  
 323      $dsocket = ini_get("mysqli.default_socket");
 324  
 325      $mylink = mysqli_init();
 326  
 327      if (@mysqli_real_connect($mylink, $dhost, $cfg['database']['user'], $cfg['database']['password'], '', $dport, $dsocket)) {
 328          $cfg['database']['client_flags'] = 0;
 329      } elseif (@mysqli_real_connect($mylink, $dhost, $cfg['database']['user'], $cfg['database']['password'], '', $dport, $dsocket, MYSQLI_CLIENT_SSL)) {
 330          $cfg['database']['client_flags'] = 'MYSQLI_CLIENT_SSL';
 331      } else {
 332          msg(gTxt('db_cant_connect'), MSG_ERROR, true);
 333      }
 334  
 335      echo msg(gTxt('db_connected'));
 336  
 337      if (!($cfg['database']['table_prefix'] == '' || preg_match('#^[a-zA-Z_][a-zA-Z0-9_]*$#', $cfg['database']['table_prefix']))) {
 338          msg(gTxt('prefix_bad_characters',
 339              array('{dbprefix}' => strong(txpspecialchars($cfg['database']['table_prefix']))), 'raw'),
 340              MSG_ERROR, true
 341          );
 342      }
 343  
 344      if (!$mydb = mysqli_select_db($mylink, $cfg['database']['db_name'])) {
 345          msg(gTxt('db_doesnt_exist',
 346              array('{dbname}' => strong(txpspecialchars($cfg['database']['db_name']))), 'raw'),
 347              MSG_ERROR, true
 348          );
 349      }
 350  
 351      $tables_exist = mysqli_query($mylink, "DESCRIBE `".$cfg['database']['table_prefix']."textpattern`");
 352      if ($tables_exist) {
 353          msg(gTxt('tables_exist',
 354              array('{dbname}' => strong(txpspecialchars($cfg['database']['db_name']))), 'raw'),
 355              MSG_ERROR, true
 356          );
 357      }
 358  
 359      // On MySQL 5.5.3+ use real UTF-8 tables, if the client supports it.
 360      $cfg['database']['charset'] = "utf8mb4";
 361  
 362      // Lower versions only support UTF-8 limited to 3 bytes per character
 363      if (mysqli_get_server_version($mylink) < 50503) {
 364          $cfg['database']['charset'] = "utf8";
 365      } else {
 366          if (false !== strpos(mysqli_get_client_info($mylink), 'mysqlnd')) {
 367              // mysqlnd 5.0.9+ required
 368              if (mysqli_get_client_version($mylink) < 50009) {
 369                  $cfg['database']['charset'] = "utf8";
 370              }
 371          } else {
 372              // libmysqlclient 5.5.3+ required
 373              if (mysqli_get_client_version($mylink) < 50503) {
 374                  $cfg['database']['charset'] = "utf8";
 375              }
 376          }
 377      }
 378      @mysqli_close($mylink);
 379      echo msg(gTxt('using_db', array(
 380          '{dbname}' => strong(txpspecialchars($cfg['database']['db_name'])), ), 'raw').' <bdi dir="ltr">('.$cfg['database']['charset'].')</bdi>');
 381  
 382      return true;
 383  }

title

Description

title

Description

title

Description

title

title

Body