/** * 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; }
/** * 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; }
/** * 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; }
/** * 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(); } } }