Guest User

module.install.php

a guest
Mar 8th, 2017
53
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 17.82 KB | None | 0 0
  1. <?php
  2. /******************************************************************************
  3.  *
  4.  * Subrion - open source content management system
  5.  * Copyright (C) 2017 Intelliants, LLC <https://intelliants.com>
  6.  *
  7.  * This file is part of Subrion.
  8.  *
  9.  * Subrion is free software: you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation, either version 3 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * Subrion is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with Subrion. If not, see <http://www.gnu.org/licenses/>.
  21.  *
  22.  *
  23.  * @link https://subrion.org/
  24.  *
  25.  ******************************************************************************/
  26.  
  27. define('IA_VER', '411');
  28.  
  29. $iaOutput->layout()->title = 'Installation Wizard';
  30.  
  31. $iaOutput->steps = [
  32.     'check' => 'Pre-Installation Check',
  33.     'license' => 'Subrion License',
  34.     'configuration' => 'Configuration',
  35.     'finish' => 'Script Installation',
  36.     'plugins' => 'Plugins Installation'
  37. ];
  38.  
  39.  
  40. $error = false;
  41. $message = '';
  42.  
  43. $builtinPlugins = ['blog', 'kcaptcha', 'fancybox'];
  44.  
  45. switch ($step)
  46. {
  47.     case 'check':
  48.         $checks = [
  49.             'server' => []
  50.         ];
  51.         $sections = [
  52.             'server' => [
  53.                 'title' => 'Server Configuration',
  54.                 'desc' => 'If any of these items are highlighted in red then please take actions to correct them. Failure to do so could lead to your installation not functioning correctly.',
  55.             ],
  56.             'recommended' => [
  57.                 'title' => 'Recommended Settings',
  58.                 'desc' => 'These settings are recommended for PHP in order to ensure full compatibility with Subrion CMS. However, Subrion CMS will still operate if your settings do not quite match the recommended.',
  59.             ],
  60.             'directory' => [
  61.                 'title' => 'Directory &amp; File Permissions',
  62.                 'desc' => 'In order for Subrion CMS to function correctly it needs to be able to access or write to certain files or directories. If you see "Unwritable" you need to change the permissions on the file or directory to allow Subrion CMS to write to it.',
  63.             ],
  64.         ];
  65.  
  66.         $checks['server']['mysql_version'] = [
  67.             'required' => function_exists('mysqli_connect'),
  68.             'class' => true,
  69.             'name' => 'Mysql version',
  70.             'value' => function_exists('mysqli_connect')
  71.                 ? '<td class="success">' . substr(mysqli_get_client_info(), 0, (false === $pos = strpos(mysqli_get_client_info(), '-')) ? 10 : $pos) . '</td>'
  72.                 : '<td class="danger">MySQL 5.x or upper required</td>'
  73.         ];
  74.         $checks['server']['php_version'] = [
  75.             'required' => version_compare('5.4', PHP_VERSION, '<'),
  76.             'class' => true,
  77.             'name' => 'PHP version',
  78.             'value' => version_compare('5.4', PHP_VERSION, '<')
  79.                 ? '<td class="success">' . PHP_VERSION . '</td>'
  80.                 : '<td class="danger">PHP version is not compatible. PHP 5.4.x needed. (Current version ' . PHP_VERSION . ')</td>'
  81.         ];
  82.         $checks['server']['remote'] = [
  83.             'name' => 'Remote files access support',
  84.             'value' => iaHelper::hasAccessToRemote()
  85.                 ? '<td class="success">Available</td>'
  86.                 : '<td class="danger">Unavailable (highly recommended to enable "CURL" extension or "allow_url_fopen")</td>'
  87.         ];
  88.         $checks['server']['xml'] = [
  89.             'name' => 'XML support',
  90.             'value' => extension_loaded('xml')
  91.                 ? '<td class="success">Available</td>'
  92.                 : '<td class="danger">Unavailable (recommended)</td>'
  93.         ];
  94.         $checks['server']['mysql_support'] = [
  95.             'name' => 'MySQL support (MySQLi)',
  96.             'value' => function_exists('mysqli_connect')
  97.                 ? '<td class="success">Available</td>'
  98.                 : '<td class="danger">Unavailable (required)</td>'
  99.         ];
  100.         $checks['server']['gd'] = [
  101.             'name' => 'GD extension',
  102.             'value' => extension_loaded('gd')
  103.                 ? '<td class="success">Available</td>'
  104.                 : '<td class="danger">Unavailable (highly recommended)</td>'
  105.         ];
  106.         $checks['server']['mbstring'] = [
  107.             'name' => 'Mbstring extension',
  108.             'value' => extension_loaded('mbstring')
  109.                 ? '<td class="success">Available</td>'
  110.                 : '<td class="danger">Unavailable (not required) </td>'
  111.         ];
  112.  
  113.         if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) || isset($_SERVER['HTTP_CF_VISITOR']))
  114.         {
  115.             $checks['server']['flexiblessl'] = [
  116.                 'name' => 'Cloudflare\'s Flexible SSL',
  117.                 'value' => '<td class="warning">Cloudflare is in use. In case you want to push your site behind <em>Flexible SSL</em>, there might be issues with URLs</td>'
  118.             ];
  119.         }
  120.  
  121.  
  122.         $recommendedSettings = [
  123.             ['File Uploads', 'file_uploads', 'ON'],
  124.             ['Magic Quotes GPC', 'magic_quotes_gpc', 'OFF'],
  125.             ['Register Globals', 'register_globals', 'OFF']
  126.         ];
  127.         foreach ($recommendedSettings as $item)
  128.         {
  129.             $checks['recommended'][$item[1]] = [
  130.                 'name' => $item[0] . ':</td><td>' . $item[2] . '',
  131.                 'value' => (iaHelper::getIniSetting($item[1]) == $item[2] ? '<td class="success">' : '<td class="danger">' ) . iaHelper::getIniSetting($item[1]) . '</td>',
  132.             ];
  133.         }
  134.  
  135.         $directory = [
  136.             ['tmp' . IA_DS, '', true],
  137.             ['uploads' . IA_DS, '', true],
  138.             ['backup' . IA_DS, ' (optional)', false],
  139.             ['modules' . IA_DS, ' (optional)', false],
  140.             ['includes' . IA_DS . 'config.inc.php', ' (optional)', false],
  141.         ];
  142.  
  143.         foreach ($directory as $item)
  144.         {
  145.             $text = '';
  146.             $isWritable = false;
  147.             if (file_exists(IA_HOME . $item[0]))
  148.             {
  149.                 $text = is_writable(IA_HOME . $item[0]) ? '<td class="success">Writable</td>' : '<td class="' . (empty($item[1]) ? 'danger' : 'optional') . '">Unwritable ' . $item[1] . '</td>';
  150.                 $isWritable = is_writable(IA_HOME . $item[0]);
  151.             }
  152.             else
  153.             {
  154.                 if ($item[0] == 'includes' . IA_DS . 'config.inc.php')
  155.                 {
  156.                     if (!is_writable(IA_HOME . 'includes' . IA_DS))
  157.                     {
  158.                         $text = '<td class="danger">Does not exist and cannot be created' . $item[1] . '</td>';
  159.                     }
  160.                     else
  161.                     {
  162.                         $text = '<td class="success">Does not exist, but can be created' . $item[1] . '</td>';
  163.                     }
  164.                 }
  165.                 else
  166.                 {
  167.                     $text = '<td class="danger">Does not exist' . $item[1] . '</td>';
  168.                 }
  169.             }
  170.             $checks['directory'][$item[0]] = [
  171.                 'class' => true,
  172.                 'name' => $item[0],
  173.                 'value' => $text
  174.             ];
  175.  
  176.             if ($item[2])
  177.             {
  178.                 $checks['directory'][$item[0]]['required'] = $isWritable;
  179.             }
  180.         }
  181.  
  182.         $nextButtonEnabled = true;
  183.         foreach ($sections as $section => $items)
  184.         {
  185.             foreach ($checks[$section] as $key => $check)
  186.             {
  187.                 if (isset($check['required']) && !$check['required'])
  188.                 {
  189.                     $nextButtonEnabled = false;
  190.                     break 2;
  191.                 }
  192.             }
  193.         }
  194.  
  195.         $iaOutput->nextButton = $nextButtonEnabled;
  196.         $iaOutput->sections = $sections;
  197.         $iaOutput->checks = $checks;
  198.  
  199.         break;
  200.  
  201.     case 'license':
  202.         // EULA step. do nothing
  203.         break;
  204.  
  205.     case 'configuration':
  206.     case 'finish':
  207.         $step = 'configuration';
  208.         $errorList = [];
  209.         $template = 'default';
  210.         $templates = [];
  211.  
  212.         $directory = opendir(IA_HOME . 'templates' . IA_DS);
  213.         while ($file = readdir($directory))
  214.         {
  215.             if (substr($file, 0, 1) != '.' && '_common' != $file)
  216.             {
  217.                 if (is_dir(IA_HOME . 'templates' . IA_DS . $file))
  218.                 {
  219.                     $templates[] = $file;
  220.                 }
  221.             }
  222.         }
  223.         closedir($directory);
  224.         sort($templates);
  225.  
  226.         if (isset($_POST['db_action']))
  227.         {
  228.             $requiredFields = ['dbhost', 'dbuser', 'dbname', 'prefix', 'tmpl', 'admin_username', 'admin_password', 'admin_email'];
  229.  
  230.             foreach ($requiredFields as $fieldName)
  231.             {
  232.                 if (!iaHelper::getPost($fieldName, false))
  233.                 {
  234.                     $errorList[] = $fieldName;
  235.                 }
  236.             }
  237.  
  238.             if (iaHelper::getPost('admin_password') != iaHelper::getPost('admin_password2'))
  239.             {
  240.                 $errorList[] = 'admin_password2';
  241.             }
  242.  
  243.             $port = (int)iaHelper::getPost('dbport', 3306);
  244.             if ($port > 65536 || $port <= 0)
  245.             {
  246.                 $_POST['dbport'] = 3306;
  247.             }
  248.  
  249.             if (!iaHelper::email(iaHelper::getPost('admin_email')))
  250.             {
  251.                 $errorList[] = 'admin_email';
  252.             }
  253.  
  254.             if (!preg_match('/^[a-zA-Z0-9._-]*$/i', iaHelper::getPost('admin_username')))
  255.             {
  256.                 $errorList[] = 'admin_username';
  257.             }
  258.  
  259.             if (empty($errorList))
  260.             {
  261.                 $link = @mysqli_connect(iaHelper::getPost('dbhost'), iaHelper::getPost('dbuser'), iaHelper::getPost('dbpwd'), '', iaHelper::getPost('dbport', 3306));
  262.                 if (mysqli_connect_errno())
  263.                 {
  264.                     $error = true;
  265.                     $message = 'MySQL server: ' . mysqli_connect_error() . '<br>';
  266.                 }
  267.  
  268.                 if (!$error && !mysqli_select_db($link, iaHelper::getPost('dbname')))
  269.                 {
  270.                     $error = true;
  271.                     $message = 'Could not select database ' . iaHelper::_html(iaHelper::getPost('dbname')) . ': ' . mysqli_error($link);
  272.                 }
  273.  
  274.                 $prefix = iaHelper::getPost('prefix');
  275.  
  276.                 if (!$error && !iaHelper::getPost('delete_tables', false))
  277.                 {
  278.                     if ($query = mysqli_query($link, 'SHOW TABLES'))
  279.                     {
  280.                         if (mysqli_num_rows($query) > 0)
  281.                         {
  282.                             while ($array = mysqli_fetch_row($query))
  283.                             {
  284.                                 if (strpos($array[0], iaHelper::_sql($prefix, $link)) !== false)
  285.                                 {
  286.                                     $error = true;
  287.                                     $message = 'Tables with prefix "' . $prefix . '" already exist.';
  288.                                     $errorList[] = 'prefix';
  289.  
  290.                                     break;
  291.                                 }
  292.                             }
  293.                         }
  294.                     }
  295.                     unset($query);
  296.                 }
  297.  
  298.                 if (!$error)
  299.                 {
  300.                     $dbOptions = 'ENGINE=MyISAM DEFAULT CHARSET=utf8';
  301.                     $dumpFile = IA_INSTALL . 'dump' . IA_DS . 'install.sql';
  302.  
  303.                     if (!file_exists($dumpFile))
  304.                     {
  305.                         $error = true;
  306.                         $message = 'Could not open file with sql instructions: install.sql';
  307.                     }
  308.                 }
  309.  
  310.                 if (!$error)
  311.                 {
  312.                     $search = [
  313.                         '{install:dir}' => trim(IA_HOME, '/'),
  314.                         '{install:base}' => IA_HOME,
  315.                         '{install:base_url}' => URL_HOME,
  316.                         '{install:tmpl}' => iaHelper::_sql(iaHelper::getPost('tmpl'), $link),
  317.                         '{install:lang}' => 'en',
  318.                         '{install:admin_username}' => iaHelper::_sql(iaHelper::getPost('admin_username'), $link),
  319.                         '{install:email}' => iaHelper::_sql(iaHelper::getPost('admin_email'), $link),
  320.                         '{install:db_options}' => $dbOptions,
  321.                         '{install:version}' => IA_VERSION,
  322.                         '{install:drop_tables}' => ('on' == iaHelper::getPost('delete_tables')) ? '' : '#',
  323.                         '{install:prefix}' => iaHelper::_sql(iaHelper::getPost('prefix', '', false), $link)
  324.                     ];
  325.                     $message = $s_sql = '';
  326.                     $counter = 0;
  327.                     $file = file($dumpFile);
  328.                     if (count($file) > 0)
  329.                     {
  330.                         mysqli_query($link, "SET NAMES 'utf8'");
  331.  
  332.                         foreach ($file as $s)
  333.                         {
  334.                             $s = trim ($s);
  335.                             if (isset($s[0]) && ($s[0] == '#' || $s[0] == '' || 0 === strpos($s, '--')))
  336.                             {
  337.                                 continue;
  338.                             }
  339.  
  340.                             if ($s && $s[strlen($s) - 1] == ';')
  341.                             {
  342.                                 $s_sql .= $s;
  343.                             }
  344.                             else
  345.                             {
  346.                                 $s_sql .= $s;
  347.                                 continue;
  348.                             }
  349.  
  350.                             $s_sql = str_replace(array_keys($search), array_values($search), $s_sql);
  351.  
  352.                             if (!mysqli_query($link, $s_sql))
  353.                             {
  354.                                 $error = true;
  355.                                 if ($counter == 0)
  356.                                 {
  357.                                     $counter++;
  358.                                     $message .= '<div class="db_errors">';
  359.                                 }
  360.                                 $errorCode = function_exists('mysqli_errno') ? mysqli_errno($link) . ' ' : '';
  361.                                 $message .= "<div class=\"qerror\">'" . $errorCode . mysqli_error($link)
  362.                                     . "' during the following query:</div> <div class=\"query\"><pre>{$s_sql}</pre></div>";
  363.                             }
  364.                             $s_sql = '';
  365.                         }
  366.                         $message .= $message ? '</div>' : '';
  367.                     }
  368.                     else
  369.                     {
  370.                         $error = true;
  371.                         $message = 'Mysql dump is empty! Please check the file!';
  372.                     }
  373.                 }
  374.  
  375.                 $iaModuleInstaller = iaHelper::loadCoreClass('module');
  376.  
  377.                 $templateInstallationFile = IA_HOME . 'templates' . IA_DS . iaHelper::getPost('tmpl', '') . IA_DS . 'install.xml';
  378.                 $iaModuleInstaller->getFromPath($templateInstallationFile);
  379.  
  380.                 $iaModuleInstaller->parse();
  381.                 $iaModuleInstaller->checkValidity(iaHelper::getPost('tmpl', ''));
  382.  
  383.                 if ($notes = $iaModuleInstaller->getNotes())
  384.                 {
  385.                     $error = true;
  386.                     $errorList[] = 'template';
  387.                     $message = sprintf('Template installation error: %s', implode('<br>', $notes));
  388.                 }
  389.  
  390.                 if (!$error)
  391.                 {
  392.                     $config = file_get_contents(IA_INSTALL . 'modules' . IA_DS . 'config.sample');
  393.                     $body = <<<HTML
  394. Congratulations,
  395.  
  396. You have successfully installed Subrion CMS ({version}) on your server.
  397.  
  398. This e-mail contains important information regarding your installation and
  399. should be kept for reference. Your password has been securely stored in our
  400. database and cannot be retrieved. In the event that it is forgotten, you
  401. will be able to reset it using the email address associated with your
  402. account.
  403.  
  404. ----------------------------
  405. Site configuration
  406. ----------------------------
  407.  Username: {username}
  408.  Password: {password}
  409.  Board URL: {url}
  410. ----------------------------
  411. Mysql configuration
  412. ----------------------------
  413.  Hostname: {dbhost}:{dbport}
  414.  Database: {dbname}
  415.  Username: {dbuser}
  416.  Password: {dbpass}
  417.  Prefix: {dbprefix}
  418. ----------------------------
  419.  
  420. Useful information regarding the Subrion CMS can be found in Subrion User Forums -
  421. https://subrion.org/forums/
  422. __________________________
  423. The Subrion Support Team
  424. https://subrion.org
  425. https://intelliants.com
  426. HTML;
  427.                     $salt = '#' . strtoupper(substr(md5(IA_HOME), 21, 10));
  428.                     $params = [
  429.                         '{version}' => IA_VERSION,
  430.                         '{date}' => date('d F Y H:i:s'),
  431.                         '{dbconnector}' => in_array('mysqli', get_loaded_extensions()) && function_exists('mysqli_connect') ? 'mysqli' : 'mysql',
  432.                         '{dbhost}' => iaHelper::getPost('dbhost'),
  433.                         '{dbuser}' => iaHelper::getPost('dbuser'),
  434.                         '{dbpass}' => iaHelper::getPost('dbpwd', '', false),
  435.                         '{dbname}' => iaHelper::getPost('dbname'),
  436.                         '{dbport}' => iaHelper::getPost('dbport'),
  437.                         '{dbprefix}' => iaHelper::getPost('prefix'),
  438.                         '{salt}' => $salt,
  439.                         '{debug}' => iaHelper::getPost('debug', 0, false),
  440.                         '{username}' => iaHelper::_sql(iaHelper::getPost('admin_username'), $link),
  441.                         '{password}' => iaHelper::_sql(iaHelper::getPost('admin_password'), $link),
  442.                         '{url}' => URL_ADMIN_PANEL
  443.                     ];
  444.                     $body = str_replace(array_keys($params), array_values($params), $body);
  445.                     $params['{dbpass}'] = str_replace("'", "\\'", $params['{dbpass}']);
  446.                     $config = str_replace(array_keys($params), array_values($params), $config);
  447.  
  448.                     @mail(iaHelper::_sql(iaHelper::getPost('admin_email')), 'Subrion CMS Installed', $body, 'From: support@subrion.org');
  449.                     $filename = IA_HOME . 'includes' . IA_DS . 'config.inc.php';
  450.                     $configMsg = '';
  451.  
  452.                     // session path test
  453.                     $testResult = false;
  454.                     $filePath = session_save_path() . IA_DS . 'foo';
  455.                     if ($fh = @fopen($filePath, 'w'))
  456.                     {
  457.                         $testResult = fwrite($fh, 'bar');
  458.                         fclose($fh);
  459.                     }
  460.  
  461.                     $testResult = $testResult ? '' : "session_save_path('" . IA_HOME . "tmp');";
  462.                     $config = str_replace('{sessionpath}', $testResult, $config);
  463.                     //
  464.  
  465.                     if (is_writable(IA_HOME . 'includes' . IA_DS) || is_writable($filename))
  466.                     {
  467.                         if (!$handle = fopen($filename, 'w+'))
  468.                         {
  469.                             $configMsg = 'Cannot open file: ' . $filename;
  470.                         }
  471.  
  472.                         if (fwrite($handle, $config) === false)
  473.                         {
  474.                             $configMsg = 'Cannot write to file: ' . $filename;
  475.                         }
  476.  
  477.                         fclose($handle);
  478.                     }
  479.                     else
  480.                     {
  481.                         $configMsg = 'Cannot write to folder.';
  482.                     }
  483.  
  484.                     iaHelper::cleanUpDirectoryContents(IA_HOME . 'tmp' . IA_DS);
  485.  
  486.                     if (!$error)
  487.                     {
  488.                         $step = 'finish';
  489.                         $iaOutput->step = 'finish';
  490.                     }
  491.  
  492.                     $iaOutput->config = $config;
  493.                     $iaOutput->description = $configMsg;
  494.                 }
  495.  
  496.                 if (!$error)
  497.                 {
  498.                     defined('IA_SALT') || define('IA_SALT', $salt);
  499.  
  500.                     $iaUsers = iaHelper::loadCoreClass('users', 'core');
  501.                     $iaUsers->changePassword(['id' => 1], iaHelper::getPost('admin_password'), false);
  502.  
  503.                     iaHelper::cleanUpCacheContents();
  504.  
  505.                     $iaModuleInstaller->install(iaModule::SETUP_INITIAL);
  506.  
  507.                     // writing it to the system log
  508.                     $iaLog = iaHelper::loadCoreClass('log', 'core');
  509.                     $iaLog->write(iaLog::ACTION_INSTALL, ['type' => 'app']);
  510.                 }
  511.  
  512.                 if (!$error)
  513.                 {
  514.                     $iaModuleInstaller = iaHelper::loadCoreClass('module');
  515.  
  516.                     $modulesFolder = IA_HOME . 'modules' . IA_DS;
  517.                     foreach ($builtinPlugins as $pluginName)
  518.                     {
  519.                         $installationFile = file_get_contents($modulesFolder . $pluginName . IA_DS . iaHelper::INSTALLATION_FILE_NAME);
  520.                         if ($installationFile !== false)
  521.                         {
  522.                             $iaModuleInstaller->setXml($installationFile);
  523.                             $iaModuleInstaller->parse();
  524.  
  525.                             if (!$iaModuleInstaller->getNotes())
  526.                             {
  527.                                 $result = $iaModuleInstaller->install();
  528.                             }
  529.                         }
  530.                     }
  531.                 }
  532.  
  533.                 if (!$error)
  534.                 {
  535.                     iaHelper::launchCronTasks();
  536.                 }
  537.             }
  538.  
  539.             $template = iaHelper::getPost('tmpl', $template);
  540.         }
  541.  
  542.         $iaOutput->errorList = $errorList;
  543.         $iaOutput->template = $template;
  544.         $iaOutput->templates = $templates;
  545.  
  546.         break;
  547.  
  548.     case 'download':
  549.         if (class_exists('iaCore')) // iaCore isn't loaded when config file hasn't been written
  550.         {
  551.             iaCore::instance()->iaView->set('nodebug', true);
  552.         }
  553.  
  554.         header('Content-Type: text/x-delimtext; name="config.inc.php"');
  555.         header('Content-disposition: attachment; filename="config.inc.php"');
  556.  
  557.         echo get_magic_quotes_gpc() ? stripslashes($_POST['config_content']) : $_POST['config_content'];
  558.         exit;
  559.  
  560.     case 'plugins':
  561.         if (iaHelper::isAjaxRequest())
  562.         {
  563.             if (isset($_POST['plugin']) && $_POST['plugin'])
  564.             {
  565.                 echo iaHelper::installRemotePlugin($_POST['plugin'])
  566.                     ? 'installed successfully'
  567.                     : 'installation is not performed';
  568.                 exit();
  569.             }
  570.         }
  571.         else
  572.         {
  573.             if ($plugins = iaHelper::getRemotePluginsList(IA_VERSION))
  574.             {
  575.                 $iaOutput->plugins = $plugins;
  576.             }
  577.             else
  578.             {
  579.                 $message = 'Could not get the list of compatible plugins.';
  580.             }
  581.         }
  582.  
  583.         break;
  584.  
  585.     default:
  586.         return;
  587. }
  588.  
  589. $iaOutput->error = $error;
  590. $iaOutput->message = $message;
Add Comment
Please, Sign In to add comment