/** * Allow the admin to reset permissions on files. */ public function action_perms() { global $context, $txt, $modSettings, $package_ftp; // Let's try and be good, yes? checkSession('get'); // If we're restoring permissions this is just a pass through really. if (isset($_GET['restore'])) { create_chmod_control(array(), array(), true); fatal_lang_error('no_access', false); } // This is a time and memory eating ... setMemoryLimit('128M'); @set_time_limit(600); // Load up some FTP stuff. create_chmod_control(); if (empty($package_ftp) && !isset($_POST['skip_ftp'])) { require_once SUBSDIR . '/FtpConnection.class.php'; $ftp = new Ftp_Connection(null); list($username, $detect_path, $found_path) = $ftp->detect_path(BOARDDIR); $context['package_ftp'] = array('server' => isset($modSettings['package_server']) ? $modSettings['package_server'] : 'localhost', 'port' => isset($modSettings['package_port']) ? $modSettings['package_port'] : '21', 'username' => empty($username) ? isset($modSettings['package_username']) ? $modSettings['package_username'] : '' : $username, 'path' => $detect_path, 'form_elements_only' => true); } else { $context['ftp_connected'] = true; } // Define the template. $context['page_title'] = $txt['package_file_perms']; $context['sub_template'] = 'file_permissions'; // Define what files we're interested in, as a tree. $context['file_tree'] = array(strtr(BOARDDIR, array('\\' => '/')) => array('type' => 'dir', 'contents' => array('agreement.txt' => array('type' => 'file', 'writable_on' => 'standard'), 'Settings.php' => array('type' => 'file', 'writable_on' => 'restrictive'), 'Settings_bak.php' => array('type' => 'file', 'writable_on' => 'restrictive'), 'attachments' => array('type' => 'dir', 'writable_on' => 'restrictive'), 'avatars' => array('type' => 'dir', 'writable_on' => 'standard'), 'cache' => array('type' => 'dir', 'writable_on' => 'restrictive'), 'custom_avatar_dir' => array('type' => 'dir', 'writable_on' => 'restrictive'), 'smileys' => array('type' => 'dir_recursive', 'writable_on' => 'standard'), 'sources' => array('type' => 'dir', 'list_contents' => true, 'writable_on' => 'standard'), 'themes' => array('type' => 'dir_recursive', 'writable_on' => 'standard', 'contents' => array('default' => array('type' => 'dir_recursive', 'list_contents' => true, 'contents' => array('languages' => array('type' => 'dir', 'list_contents' => true))))), 'packages' => array('type' => 'dir', 'writable_on' => 'standard', 'contents' => array('temp' => array('type' => 'dir'), 'backup' => array('type' => 'dir'), 'installed.list' => array('type' => 'file', 'writable_on' => 'standard')))))); // Directories that can move. if (substr(SOURCEDIR, 0, strlen(BOARDDIR)) != BOARDDIR) { unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['sources']); $context['file_tree'][strtr(SOURCEDIR, array('\\' => '/'))] = array('type' => 'dir', 'list_contents' => true, 'writable_on' => 'standard'); } // Moved the cache? if (substr(CACHEDIR, 0, strlen(BOARDDIR)) != BOARDDIR) { unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['cache']); $context['file_tree'][strtr(CACHEDIR, array('\\' => '/'))] = array('type' => 'dir', 'list_contents' => false, 'writable_on' => 'restrictive'); } // Are we using multiple attachment directories? if (!empty($modSettings['currentAttachmentUploadDir'])) { unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['attachments']); if (!is_array($modSettings['attachmentUploadDir'])) { $modSettings['attachmentUploadDir'] = unserialize($modSettings['attachmentUploadDir']); } // @todo Should we suggest non-current directories be read only? foreach ($modSettings['attachmentUploadDir'] as $dir) { $context['file_tree'][strtr($dir, array('\\' => '/'))] = array('type' => 'dir', 'writable_on' => 'restrictive'); } } elseif (substr($modSettings['attachmentUploadDir'], 0, strlen(BOARDDIR)) != BOARDDIR) { unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['attachments']); $context['file_tree'][strtr($modSettings['attachmentUploadDir'], array('\\' => '/'))] = array('type' => 'dir', 'writable_on' => 'restrictive'); } if (substr($modSettings['smileys_dir'], 0, strlen(BOARDDIR)) != BOARDDIR) { unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['smileys']); $context['file_tree'][strtr($modSettings['smileys_dir'], array('\\' => '/'))] = array('type' => 'dir_recursive', 'writable_on' => 'standard'); } if (substr($modSettings['avatar_directory'], 0, strlen(BOARDDIR)) != BOARDDIR) { unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['avatars']); $context['file_tree'][strtr($modSettings['avatar_directory'], array('\\' => '/'))] = array('type' => 'dir', 'writable_on' => 'standard'); } if (isset($modSettings['custom_avatar_dir']) && substr($modSettings['custom_avatar_dir'], 0, strlen(BOARDDIR)) != BOARDDIR) { unset($context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['custom_avatar_dir']); $context['file_tree'][strtr($modSettings['custom_avatar_dir'], array('\\' => '/'))] = array('type' => 'dir', 'writable_on' => 'restrictive'); } // Load up any custom themes. require_once SUBSDIR . '/Themes.subs.php'; $themes = getCustomThemes(); foreach ($themes as $id => $theme) { // Skip the default if ($id == 1) { continue; } if (substr(strtolower(strtr($theme['theme_dir'], array('\\' => '/'))), 0, strlen(BOARDDIR) + 7) === strtolower(strtr(BOARDDIR, array('\\' => '/')) . '/themes')) { $context['file_tree'][strtr(BOARDDIR, array('\\' => '/'))]['contents']['themes']['contents'][substr($theme['theme_dir'], strlen(BOARDDIR) + 8)] = array('type' => 'dir_recursive', 'list_contents' => true, 'contents' => array('languages' => array('type' => 'dir', 'list_contents' => true))); } else { $context['file_tree'][strtr($theme['theme_dir'], array('\\' => '/'))] = array('type' => 'dir_recursive', 'list_contents' => true, 'contents' => array('languages' => array('type' => 'dir', 'list_contents' => true))); } } // If we're submitting then let's move on to another function to keep things cleaner.. if (isset($_POST['action_changes'])) { return $this->action_perms_save(); } $context['look_for'] = array(); // Are we looking for a particular tree - normally an expansion? if (!empty($_REQUEST['find'])) { $context['look_for'][] = base64_decode($_REQUEST['find']); } // Only that tree? $context['only_find'] = isset($_GET['xml']) && !empty($_REQUEST['onlyfind']) ? $_REQUEST['onlyfind'] : ''; if ($context['only_find']) { $context['look_for'][] = $context['only_find']; } // Have we got a load of back-catalogue trees to expand from a submit etc? if (!empty($_GET['back_look'])) { $potententialTrees = unserialize(base64_decode($_GET['back_look'])); foreach ($potententialTrees as $tree) { $context['look_for'][] = $tree; } } // ... maybe posted? if (!empty($_POST['back_look'])) { $context['only_find'] = array_merge($context['only_find'], $_POST['back_look']); } $context['back_look_data'] = base64_encode(serialize(array_slice($context['look_for'], 0, 15))); // Are we finding more files than first thought? $context['file_offset'] = !empty($_REQUEST['fileoffset']) ? (int) $_REQUEST['fileoffset'] : 0; // Don't list more than this many files in a directory. $context['file_limit'] = 150; // How many levels shall we show? $context['default_level'] = empty($context['only_find']) ? 2 : 25; // This will be used if we end up catching XML data. $context['xml_data'] = array('roots' => array('identifier' => 'root', 'children' => array(array('value' => preg_replace('~[^A-Za-z0-9_\\-=:]~', ':-:', $context['only_find'])))), 'folders' => array('identifier' => 'folder', 'children' => array())); foreach ($context['file_tree'] as $path => $data) { // Run this directory. if (file_exists($path) && (empty($context['only_find']) || substr($context['only_find'], 0, strlen($path)) == $path)) { // Get the first level down only. fetchPerms__recursive($path, $context['file_tree'][$path], 1); $context['file_tree'][$path]['perms'] = array('chmod' => @is_writable($path), 'perms' => @fileperms($path)); } else { unset($context['file_tree'][$path]); } } // Is this actually xml? if (isset($_GET['xml'])) { loadTemplate('Xml'); $context['sub_template'] = 'generic_xml'; Template_Layers::getInstance()->removeAll(); } }
/** * Check files are writable - make them writable if necessary... * * @param array $files */ function makeFilesWritable(&$files) { global $upcontext; if (empty($files)) { return true; } $failure = false; // On linux, it's easy - just use is_writable! if (substr(__FILE__, 1, 2) != ':\\') { foreach ($files as $k => $file) { if (!is_writable($file)) { @chmod($file, 0755); // Well, 755 hopefully worked... if not, try 777. if (!is_writable($file) && !@chmod($file, 0777)) { $failure = true; } else { unset($files[$k]); } } else { unset($files[$k]); } } } else { foreach ($files as $k => $file) { // Folders can't be opened for write... but the index.php in them can ;). if (is_dir($file)) { $file .= '/index.php'; } // Funny enough, chmod actually does do something on windows - it removes the read only attribute. @chmod($file, 0777); $fp = @fopen($file, 'r+'); // Hmm, okay, try just for write in that case... if (!$fp) { $fp = @fopen($file, 'w'); } if (!$fp) { $failure = true; } else { unset($files[$k]); } @fclose($fp); } } if (empty($files)) { return true; } if (!isset($_SERVER)) { return !$failure; } // What still needs to be done? $upcontext['chmod']['files'] = $files; // If it's windows it's a mess... if ($failure && substr(__FILE__, 1, 2) == ':\\') { $upcontext['chmod']['ftp_error'] = 'total_mess'; return false; } elseif ($failure) { // Load any session data we might have... if (!isset($_POST['ftp_username']) && isset($_SESSION['installer_temp_ftp'])) { $upcontext['chmod']['server'] = $_SESSION['installer_temp_ftp']['server']; $upcontext['chmod']['port'] = $_SESSION['installer_temp_ftp']['port']; $upcontext['chmod']['username'] = $_SESSION['installer_temp_ftp']['username']; $upcontext['chmod']['password'] = $_SESSION['installer_temp_ftp']['password']; $upcontext['chmod']['path'] = $_SESSION['installer_temp_ftp']['path']; } elseif (isset($_POST['ftp_username'])) { $upcontext['chmod']['server'] = $_POST['ftp_server']; $upcontext['chmod']['port'] = $_POST['ftp_port']; $upcontext['chmod']['username'] = $_POST['ftp_username']; $upcontext['chmod']['password'] = $_POST['ftp_password']; $upcontext['chmod']['path'] = $_POST['ftp_path']; } if (isset($upcontext['chmod']['username'])) { $ftp = new Ftp_Connection($upcontext['chmod']['server'], $upcontext['chmod']['port'], $upcontext['chmod']['username'], $upcontext['chmod']['password']); if ($ftp->error === false) { // Try it without /home/abc just in case they messed up. if (!$ftp->chdir($upcontext['chmod']['path'])) { $upcontext['chmod']['ftp_error'] = $ftp->last_message; $ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $upcontext['chmod']['path'])); } } } if (!isset($ftp) || $ftp->error !== false) { if (!isset($ftp)) { $ftp = new Ftp_Connection(null); } elseif ($ftp->error !== false && !isset($upcontext['chmod']['ftp_error'])) { $upcontext['chmod']['ftp_error'] = $ftp->last_message === null ? '' : $ftp->last_message; } list($username, $detect_path, $found_path) = $ftp->detect_path(dirname(__FILE__)); if ($found_path || !isset($upcontext['chmod']['path'])) { $upcontext['chmod']['path'] = $detect_path; } if (!isset($upcontext['chmod']['username'])) { $upcontext['chmod']['username'] = $username; } return false; } else { // We want to do a relative path for FTP. if (!in_array($upcontext['chmod']['path'], array('', '/'))) { $ftp_root = strtr(BOARDDIR, array($upcontext['chmod']['path'] => '')); if (substr($ftp_root, -1) == '/' && ($upcontext['chmod']['path'] == '' || $upcontext['chmod']['path'][0] === '/')) { $ftp_root = substr($ftp_root, 0, -1); } } else { $ftp_root = BOARDDIR; } // Save the info for next time! $_SESSION['installer_temp_ftp'] = array('server' => $upcontext['chmod']['server'], 'port' => $upcontext['chmod']['port'], 'username' => $upcontext['chmod']['username'], 'password' => $upcontext['chmod']['password'], 'path' => $upcontext['chmod']['path'], 'root' => $ftp_root); foreach ($files as $k => $file) { if (!is_writable($file)) { $ftp->chmod($file, 0755); } if (!is_writable($file)) { $ftp->chmod($file, 0777); } // Assuming that didn't work calculate the path without the boarddir. if (!is_writable($file)) { if (strpos($file, BOARDDIR) === 0) { $ftp_file = strtr($file, array($_SESSION['installer_temp_ftp']['root'] => '')); $ftp->chmod($ftp_file, 0755); if (!is_writable($file)) { $ftp->chmod($ftp_file, 0777); } // Sometimes an extra slash can help... $ftp_file = '/' . $ftp_file; if (!is_writable($file)) { $ftp->chmod($ftp_file, 0755); } if (!is_writable($file)) { $ftp->chmod($ftp_file, 0777); } } } if (is_writable($file)) { unset($files[$k]); } } $ftp->close(); } } // What remains? $upcontext['chmod']['files'] = $files; if (empty($files)) { return true; } return false; }
/** * Delete the installer and its additional files. * Called by ?delete */ function action_deleteInstaller() { global $databases; if (isset($_SESSION['installer_temp_ftp'])) { $ftp = new Ftp_Connection($_SESSION['installer_temp_ftp']['server'], $_SESSION['installer_temp_ftp']['port'], $_SESSION['installer_temp_ftp']['username'], $_SESSION['installer_temp_ftp']['password']); $ftp->chdir($_SESSION['installer_temp_ftp']['path']); $ftp->unlink('install.php'); foreach ($databases as $key => $dummy) { $ftp->unlink('install_' . DB_SCRIPT_VERSION . '_' . $key . '.sql'); } $ftp->close(); unset($_SESSION['installer_temp_ftp']); } else { @unlink(__FILE__); foreach ($databases as $key => $dummy) { @unlink(dirname(__FILE__) . '/install_' . DB_SCRIPT_VERSION . '_' . $key . '.sql'); } } // Now just redirect to a blank.png... header('Location: http://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']) . dirname($_SERVER['PHP_SELF']) . '/themes/default/images/blank.png'); exit; }
/** * Get the contents of a URL, irrespective of allow_url_fopen. * * - reads the contents of an http or ftp address and retruns the page in a string * - will accept up to 3 page redirections (redirectio_level in the function call is private) * - if post_data is supplied, the value and lenght is posted to the given url as form data * - URL must be supplied in lowercase * * @package Packages * @param string $url * @param string $post_data = '' * @param bool $keep_alive = false * @param int $redirection_level = 2 * @return string */ function fetch_web_data($url, $post_data = '', $keep_alive = false, $redirection_level = 2) { global $webmaster_email; static $keep_alive_dom = null, $keep_alive_fp = null; preg_match('~^(http|ftp)(s)?://([^/:]+)(:(\\d+))?(.+)$~', $url, $match); // An FTP url. We should try connecting and RETRieving it... if (empty($match[1])) { return false; } elseif ($match[1] == 'ftp') { // Include the file containing the Ftp_Connection class. require_once SOURCEDIR . '/FtpConnection.class.php'; // Establish a connection and attempt to enable passive mode. $ftp = new Ftp_Connection(($match[2] ? 'ssl://' : '') . $match[3], empty($match[5]) ? 21 : $match[5], 'anonymous', $webmaster_email); if ($ftp->error !== false || !$ftp->passive()) { return false; } // I want that one *points*! fwrite($ftp->connection, 'RETR ' . $match[6] . "\r\n"); // Since passive mode worked (or we would have returned already!) open the connection. $fp = @fsockopen($ftp->pasv['ip'], $ftp->pasv['port'], $err, $err, 5); if (!$fp) { return false; } // The server should now say something in acknowledgement. $ftp->check_response(150); $data = ''; while (!feof($fp)) { $data .= fread($fp, 4096); } fclose($fp); // All done, right? Good. $ftp->check_response(226); $ftp->close(); } elseif (isset($match[1]) && $match[1] === 'http' && function_exists('curl_init')) { // Include the file containing the Curl_Fetch_Webdata class. require_once SOURCEDIR . '/CurlFetchWebdata.class.php'; $fetch_data = new Curl_Fetch_Webdata(array(), $redirection_level); $fetch_data->get_url_data($url, $post_data); // no errors and a 200 result, then we have a good dataset, well we at least have data ;) if ($fetch_data->result('code') == 200 && !$fetch_data->result('error')) { $data = $fetch_data->result('body'); } else { return false; } } elseif (isset($match[1]) && $match[1] == 'http') { if ($keep_alive && $match[3] == $keep_alive_dom) { $fp = $keep_alive_fp; } if (empty($fp)) { // Open the socket on the port we want... $fp = @fsockopen(($match[2] ? 'ssl://' : '') . $match[3], empty($match[5]) ? $match[2] ? 443 : 80 : $match[5], $err, $err, 5); if (!$fp) { return false; } } if ($keep_alive) { $keep_alive_dom = $match[3]; $keep_alive_fp = $fp; } // I want this, from there, and I'm not going to be bothering you for more (probably.) if (empty($post_data)) { fwrite($fp, 'GET ' . ($match[6] !== '/' ? str_replace(' ', '%20', $match[6]) : '') . ' HTTP/1.0' . "\r\n"); fwrite($fp, 'Host: ' . $match[3] . (empty($match[5]) ? $match[2] ? ':443' : '' : ':' . $match[5]) . "\r\n"); fwrite($fp, 'User-Agent: PHP/ELK' . "\r\n"); if ($keep_alive) { fwrite($fp, 'Connection: Keep-Alive' . "\r\n\r\n"); } else { fwrite($fp, 'Connection: close' . "\r\n\r\n"); } } else { fwrite($fp, 'POST ' . ($match[6] !== '/' ? $match[6] : '') . ' HTTP/1.0' . "\r\n"); fwrite($fp, 'Host: ' . $match[3] . (empty($match[5]) ? $match[2] ? ':443' : '' : ':' . $match[5]) . "\r\n"); fwrite($fp, 'User-Agent: PHP/ELK' . "\r\n"); if ($keep_alive) { fwrite($fp, 'Connection: Keep-Alive' . "\r\n"); } else { fwrite($fp, 'Connection: close' . "\r\n"); } fwrite($fp, 'Content-Type: application/x-www-form-urlencoded' . "\r\n"); fwrite($fp, 'Content-Length: ' . strlen($post_data) . "\r\n\r\n"); fwrite($fp, $post_data); } $response = fgets($fp, 768); // Redirect in case this location is permanently or temporarily moved. if ($redirection_level < 3 && preg_match('~^HTTP/\\S+\\s+30[127]~i', $response) === 1) { $header = ''; $location = ''; while (!feof($fp) && trim($header = fgets($fp, 4096)) != '') { if (strpos($header, 'Location:') !== false) { $location = trim(substr($header, strpos($header, ':') + 1)); } } if (empty($location)) { return false; } else { if (!$keep_alive) { fclose($fp); } return fetch_web_data($location, $post_data, $keep_alive, $redirection_level + 1); } } elseif (preg_match('~^HTTP/\\S+\\s+20[01]~i', $response) === 0) { return false; } // Skip the headers... while (!feof($fp) && trim($header = fgets($fp, 4096)) != '') { if (preg_match('~content-length:\\s*(\\d+)~i', $header, $match) != 0) { $content_length = $match[1]; } elseif (preg_match('~connection:\\s*close~i', $header) != 0) { $keep_alive_dom = null; $keep_alive = false; } continue; } $data = ''; if (isset($content_length)) { while (!feof($fp) && strlen($data) < $content_length) { $data .= fread($fp, $content_length - strlen($data)); } } else { while (!feof($fp)) { $data .= fread($fp, 4096); } } if (!$keep_alive) { fclose($fp); } } else { // Umm, this shouldn't happen? trigger_error('fetch_web_data(): Bad URL', E_USER_NOTICE); $data = false; } return $data; }
/** * Handling function for the backup stuff. * * - It requires an administrator and the session hash by post. * - This method simply forwards to DumpDatabase2(). */ public function action_backup_display() { global $context, $txt, $user_info; validateToken('admin-maint'); // Administrators only! if (!allowedTo('admin_forum')) { fatal_lang_error('no_dump_database', 'critical'); } checkSession('post'); if (empty($iknowitmaybeunsafe)) { require_once SUBSDIR . '/FtpConnection.class.php'; $ftp = new Ftp_Connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']); if ($ftp->error === false) { // I know, I know... but a lot of people want to type /home/xyz/... which is wrong, but logical. if (!$ftp->chdir($_POST['ftp_path'])) { $ftp_error = $ftp->error; $ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path'])); } } // If we had an error... if ($ftp->error !== false) { loadLanguage('Packages'); $ftp_error = $ftp->last_message === null ? isset($txt['package_ftp_' . $ftp->error]) ? $txt['package_ftp_' . $ftp->error] : '' : $ftp->last_message; // Fill the boxes for a FTP connection with data from the previous attempt $context['package_ftp'] = array('form_elements_only' => 1, 'server' => $_POST['ftp_server'], 'port' => $_POST['ftp_port'], 'username' => $_POST['ftp_username'], 'path' => $_POST['ftp_path'], 'error' => empty($ftp_error) ? null : $ftp_error); return $this->action_database(); } } require_once SUBSDIR . '/Admin.subs.php'; emailAdmins('admin_backup_database', array('BAK_REALNAME' => $user_info['name'])); logAction('database_backup', array('member' => $user_info['id']), 'admin'); require_once SOURCEDIR . '/DumpDatabase.php'; DumpDatabase2(); }
/** * This method attempts to chmod packages and installed.list * * - uses FTP if necessary. * - It sets the $context['package_download_broken'] status for the template. * - Used by package servers pages. */ public function ftp_connect() { global $context, $modSettings; // Try to chmod from PHP first @chmod(BOARDDIR . '/packages', 0777); @chmod(BOARDDIR . '/packages/installed.list', 0777); $unwritable = !is_writable(BOARDDIR . '/packages') || !is_writable(BOARDDIR . '/packages/installed.list'); // Let's initialize $context $context['package_ftp'] = array('server' => '', 'port' => '', 'username' => '', 'path' => '', 'error' => ''); if ($unwritable) { // Are they connecting to their FTP account already? if (isset($_POST['ftp_username'])) { require_once SUBSDIR . '/FtpConnection.class.php'; $ftp = new Ftp_Connection($_POST['ftp_server'], $_POST['ftp_port'], $_POST['ftp_username'], $_POST['ftp_password']); if ($ftp->error === false) { // I know, I know... but a lot of people want to type /home/xyz/... which is wrong, but logical. if (!$ftp->chdir($_POST['ftp_path'])) { $ftp_error = $ftp->error; $ftp->chdir(preg_replace('~^/home[2]?/[^/]+?~', '', $_POST['ftp_path'])); } } } // No attempt yet, or we had an error last time if (!isset($ftp) || $ftp->error !== false) { // Maybe we didn't even try yet if (!isset($ftp)) { require_once SUBSDIR . '/FtpConnection.class.php'; $ftp = new Ftp_Connection(null); } elseif ($ftp->error !== false && !isset($ftp_error)) { $ftp_error = $ftp->last_message === null ? '' : $ftp->last_message; } list($username, $detect_path, $found_path) = $ftp->detect_path(BOARDDIR); if ($found_path || !isset($_POST['ftp_path'])) { $_POST['ftp_path'] = $detect_path; } if (!isset($_POST['ftp_username'])) { $_POST['ftp_username'] = $username; } // Fill the boxes for a FTP connection with data from the previous attempt too, if any $context['package_ftp'] = array('server' => isset($_POST['ftp_server']) ? $_POST['ftp_server'] : (isset($modSettings['package_server']) ? $modSettings['package_server'] : 'localhost'), 'port' => isset($_POST['ftp_port']) ? $_POST['ftp_port'] : (isset($modSettings['package_port']) ? $modSettings['package_port'] : '21'), 'username' => isset($_POST['ftp_username']) ? $_POST['ftp_username'] : (isset($modSettings['package_username']) ? $modSettings['package_username'] : ''), 'path' => $_POST['ftp_path'], 'error' => empty($ftp_error) ? null : $ftp_error); // Announce the template it's time to display the ftp connection box. $context['package_download_broken'] = true; } else { // FTP connection has succeeded $context['package_download_broken'] = false; // Try to chmod packages folder and our list file. $ftp->chmod('packages', 0777); $ftp->chmod('packages/installed.list', 0777); $ftp->close(); } } }