/** * Test Settings */ function test_upload(&$error, $upload_dir, $create_directory = false) { global $user, $phpbb_root_path; // Does the target directory exist, is it a directory and writable. if ($create_directory) { if (!file_exists($phpbb_root_path . $upload_dir)) { @mkdir($phpbb_root_path . $upload_dir, 0777); try { $this->filesystem->phpbb_chmod($phpbb_root_path . $upload_dir, CHMOD_READ | CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } } if (!file_exists($phpbb_root_path . $upload_dir)) { $error[] = sprintf($user->lang['NO_UPLOAD_DIR'], $upload_dir); return; } if (!is_dir($phpbb_root_path . $upload_dir)) { $error[] = sprintf($user->lang['UPLOAD_NOT_DIR'], $upload_dir); return; } if (!$this->filesystem->is_writable($phpbb_root_path . $upload_dir)) { $error[] = sprintf($user->lang['NO_WRITE_UPLOAD'], $upload_dir); return; } }
/** * {@inheritdoc} */ public function run() { $config_written = true; // Create config.php $path_to_config = $this->phpbb_root_path . 'config.' . $this->php_ext; $fp = @fopen($path_to_config, 'w'); if (!$fp) { $config_written = false; } $config_content = $this->get_config_data(); if (!@fwrite($fp, $config_content)) { $config_written = false; } @fclose($fp); // chmod config.php to be only readable if ($config_written) { try { $this->filesystem->phpbb_chmod($path_to_config, \phpbb\filesystem\filesystem_interface::CHMOD_READ); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing, the user will get a notice later } } else { $this->iohandler->add_error_message('UNABLE_TO_WRITE_CONFIG_FILE'); $this->iohandler->send_response(); throw new user_interaction_required_exception(); } // Create a lock file to indicate that there is an install in progress $fp = @fopen($this->phpbb_root_path . 'cache/install_lock', 'wb'); if ($fp === false) { // We were unable to create the lock file - abort $this->iohandler->add_error_message('UNABLE_TO_WRITE_LOCK'); $this->iohandler->send_response(); throw new user_interaction_required_exception(); } @fclose($fp); try { $this->filesystem->phpbb_chmod($this->phpbb_root_path . 'cache/install_lock', 0777); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing, the user will get a notice later } }
/** * Write cache data to a specified file * * 'data_global' is a special case and the generated format is different for this file: * <code> * <?php exit; ?> * (expiration) * (length of var and serialised data) * (var) * (serialised data) * ... (repeat) * </code> * * The other files have a similar format: * <code> * <?php exit; ?> * (expiration) * (query) [SQL files only] * (length of serialised data) * (serialised data) * </code> * * @access private * @param string $filename Filename to write * @param mixed $data Data to store * @param int $expires Timestamp when the data expires * @param string $query Query when caching SQL queries * @return bool True if the file was successfully created, otherwise false */ function _write($filename, $data = null, $expires = 0, $query = '') { global $phpEx; $filename = $this->clean_varname($filename); $file = "{$this->cache_dir}{$filename}.{$phpEx}"; $lock = new \phpbb\lock\flock($file); $lock->acquire(); if ($handle = @fopen($file, 'wb')) { // File header fwrite($handle, '<' . '?php exit; ?' . '>'); if ($filename == 'data_global') { // Global data is a different format foreach ($this->vars as $var => $data) { if (strpos($var, "\r") !== false || strpos($var, "\n") !== false) { // CR/LF would cause fgets() to read the cache file incorrectly // do not cache test entries, they probably won't be read back // the cache keys should really be alphanumeric with a few symbols. continue; } $data = serialize($data); // Write out the expiration time fwrite($handle, "\n" . $this->var_expires[$var] . "\n"); // Length of the remaining data for this var (ignoring two LF's) fwrite($handle, strlen($data . $var) . "\n"); fwrite($handle, $var . "\n"); fwrite($handle, $data); } } else { fwrite($handle, "\n" . $expires . "\n"); if (strpos($filename, 'sql_') === 0) { fwrite($handle, $query . "\n"); } $data = serialize($data); fwrite($handle, strlen($data) . "\n"); fwrite($handle, $data); } fclose($handle); if (function_exists('opcache_invalidate')) { @opcache_invalidate($this->cache_file); } try { $this->filesystem->phpbb_chmod($file, CHMOD_READ | CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } $return_value = true; } else { $return_value = false; } $lock->release(); return $return_value; }
/** * Check if a directory is readable and writable * * @param string $dir Filename * @param bool $failable Whether failing test should abort the installation process */ protected function check_dir($dir, $failable = false) { $path = $this->phpbb_root_path . $dir; $exists = $writable = false; // Try to create the directory if it does not exist if (!file_exists($path)) { try { $this->filesystem->mkdir($path, 0777); $this->filesystem->phpbb_chmod($path, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE); $exists = true; } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } // Now really check if (file_exists($path) && is_dir($path)) { try { $exists = true; $this->filesystem->phpbb_chmod($path, \phpbb\filesystem\filesystem_interface::CHMOD_READ | \phpbb\filesystem\filesystem_interface::CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } if ($this->filesystem->is_writable($path)) { $writable = true; } $this->set_test_passed($exists && $writable || $failable); if (!($exists && $writable)) { $title = $exists ? 'DIRECTORY_NOT_WRITABLE' : 'DIRECTORY_NOT_EXISTS'; $lang_suffix = '_EXPLAIN'; $lang_suffix .= $failable ? '_OPTIONAL' : ''; $description = array($title . $lang_suffix, $dir); if ($failable) { $this->response->add_warning_message($title, $description); } else { $this->response->add_error_message($title, $description); } } }
/** * Save queue */ function save() { if (!sizeof($this->data)) { return; } $lock = new \phpbb\lock\flock($this->cache_file); $lock->acquire(); if (file_exists($this->cache_file)) { include $this->cache_file; foreach ($this->queue_data as $object => $data_ary) { if (isset($this->data[$object]) && sizeof($this->data[$object])) { $this->data[$object]['data'] = array_merge($data_ary['data'], $this->data[$object]['data']); } else { $this->data[$object]['data'] = $data_ary['data']; } } } if ($fp = @fopen($this->cache_file, 'w')) { fwrite($fp, "<?php\nif (!defined('IN_PHPBB')) exit;\n\$this->queue_data = unserialize(" . var_export(serialize($this->data), true) . ");\n\n?>"); fclose($fp); try { $this->filesystem->phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } $this->data = array(); } $lock->release(); }
/** * Extract archive */ function extract($dst) { $fzread = $this->isbz && function_exists('bzread') ? 'bzread' : ($this->isgz && @extension_loaded('zlib') ? 'gzread' : 'fread'); // Run through the file and grab directory entries while ($buffer = $fzread($this->fp, 512)) { $tmp = unpack('A6magic', substr($buffer, 257, 6)); if (trim($tmp['magic']) == 'ustar') { $tmp = unpack('A100name', $buffer); $filename = trim($tmp['name']); $tmp = unpack('Atype', substr($buffer, 156, 1)); $filetype = (int) trim($tmp['type']); $tmp = unpack('A12size', substr($buffer, 124, 12)); $filesize = octdec((int) trim($tmp['size'])); $target_filename = "{$dst}{$filename}"; if ($filetype == 5) { if (!is_dir($target_filename)) { $str = ''; $folders = explode('/', $target_filename); // Create and folders and subfolders if they do not exist foreach ($folders as $folder) { $folder = trim($folder); if (!$folder) { continue; } $str = !empty($str) ? $str . '/' . $folder : $folder; if (!is_dir($str)) { if (!@mkdir($str, 0777)) { trigger_error("Could not create directory {$folder}"); } try { $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } } } } else { if ($filesize >= 0 && ($filetype == 0 || $filetype == "")) { // Some archivers are punks, they don't properly order the folders in their archives! $str = ''; $folders = explode('/', pathinfo($target_filename, PATHINFO_DIRNAME)); // Create and folders and subfolders if they do not exist foreach ($folders as $folder) { $folder = trim($folder); if (!$folder) { continue; } $str = !empty($str) ? $str . '/' . $folder : $folder; if (!is_dir($str)) { if (!@mkdir($str, 0777)) { trigger_error("Could not create directory {$folder}"); } try { $this->filesystem->phpbb_chmod($str, CHMOD_READ | CHMOD_WRITE); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } } // Write out the files if (!($fp = fopen($target_filename, 'wb'))) { trigger_error("Couldn't create file {$filename}"); } try { $this->filesystem->phpbb_chmod($target_filename, CHMOD_READ); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } // Grab the file contents fwrite($fp, $filesize ? $fzread($this->fp, $filesize + 511 & ~511) : '', $filesize); fclose($fp); } } } } }
/** * Writes the config file to disk, or if unable to do so offers alternative methods */ function create_config_file($mode, $sub) { global $lang, $template, $phpbb_root_path, $phpEx; $this->page_title = $lang['STAGE_CONFIG_FILE']; // Obtain any submitted data $data = $this->get_submitted_data(); if ($data['dbms'] == '') { // Someone's been silly and tried calling this page direct // So we send them back to the start to do it again properly $this->p_master->redirect("index.{$phpEx}?mode=install"); } $s_hidden_fields = $data['img_imagick'] ? '<input type="hidden" name="img_imagick" value="' . addslashes($data['img_imagick']) . '" />' : ''; $s_hidden_fields .= '<input type="hidden" name="language" value="' . $data['language'] . '" />'; $written = false; // Create a list of any PHP modules we wish to have loaded $available_dbms = get_available_dbms($data['dbms']); // Create a lock file to indicate that there is an install in progress $fp = @fopen($phpbb_root_path . 'cache/install_lock', 'wb'); if ($fp === false) { // We were unable to create the lock file - abort $this->p_master->error($lang['UNABLE_WRITE_LOCK'], __LINE__, __FILE__); } @fclose($fp); @chmod($phpbb_root_path . 'cache/install_lock', 0777); // Time to convert the data provided into a config file $config_data = phpbb_create_config_file_data($data, $available_dbms[$data['dbms']]['DRIVER']); // Attempt to write out the config file directly. If it works, this is the easiest way to do it ... if (file_exists($phpbb_root_path . 'config.' . $phpEx) && $this->filesystem->is_writable($phpbb_root_path . 'config.' . $phpEx) || $this->filesystem->is_writable($phpbb_root_path)) { // Assume it will work ... if nothing goes wrong below $written = true; if (!($fp = @fopen($phpbb_root_path . 'config.' . $phpEx, 'w'))) { // Something went wrong ... so let's try another method $written = false; } if (!@fwrite($fp, $config_data)) { // Something went wrong ... so let's try another method $written = false; } @fclose($fp); if ($written) { // We may revert back to chmod() if we see problems with users not able to change their config.php file directly try { $this->filesystem->phpbb_chmod($phpbb_root_path . 'config.' . $phpEx, CHMOD_READ); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } } if (isset($_POST['dldone'])) { // Do a basic check to make sure that the file has been uploaded // Note that all we check is that the file has _something_ in it // We don't compare the contents exactly - if they can't upload // a single file correctly, it's likely they will have other problems.... if (filesize($phpbb_root_path . 'config.' . $phpEx) > 10) { $written = true; } } $config_options = array_merge($this->db_config_options, $this->admin_config_options); foreach ($config_options as $config_key => $vars) { if (!is_array($vars)) { continue; } $s_hidden_fields .= '<input type="hidden" name="' . $config_key . '" value="' . $data[$config_key] . '" />'; } if (!$written) { // OK, so it didn't work let's try the alternatives if (isset($_POST['dlconfig'])) { // They want a copy of the file to download, so send the relevant headers and dump out the data header("Content-Type: text/x-delimtext; name=\"config.{$phpEx}\""); header("Content-disposition: attachment; filename=config.{$phpEx}"); echo $config_data; exit; } // The option to download the config file is always available, so output it here $template->assign_vars(array('BODY' => $lang['CONFIG_FILE_UNABLE_WRITE'], 'L_DL_CONFIG' => $lang['DL_CONFIG'], 'L_DL_CONFIG_EXPLAIN' => $lang['DL_CONFIG_EXPLAIN'], 'L_DL_DONE' => $lang['DONE'], 'L_DL_DOWNLOAD' => $lang['DL_DOWNLOAD'], 'S_HIDDEN' => $s_hidden_fields, 'S_SHOW_DOWNLOAD' => true, 'U_ACTION' => $this->p_master->module_url . "?mode={$mode}&sub=config_file")); return; } else { $template->assign_vars(array('BODY' => $lang['CONFIG_FILE_WRITTEN'], 'L_SUBMIT' => $lang['NEXT_STEP'], 'S_HIDDEN' => $s_hidden_fields, 'U_ACTION' => $this->p_master->module_url . "?mode={$mode}&sub=advanced")); return; } }
/** * Move file to destination folder * The phpbb_root_path variable will be applied to the destination path * * @param string $destination Destination path, for example $config['avatar_path'] * @param bool $overwrite If set to true, an already existing file will be overwritten * @param bool $skip_image_check If set to true, the check for the file to be a valid image is skipped * @param string $chmod Permission mask for chmodding the file after a successful move. The mode entered here reflects the mode defined by {@link phpbb_chmod()} * * @access public */ function move_file($destination, $overwrite = false, $skip_image_check = false, $chmod = false) { global $user, $phpbb_root_path; if (sizeof($this->error)) { return false; } $chmod = $chmod === false ? CHMOD_READ | CHMOD_WRITE : $chmod; // We need to trust the admin in specifying valid upload directories and an attacker not being able to overwrite it... $this->destination_path = $phpbb_root_path . $destination; // Check if the destination path exist... if (!file_exists($this->destination_path)) { @unlink($this->filename); return false; } $upload_mode = @ini_get('open_basedir') || @ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'on' ? 'move' : 'copy'; $upload_mode = $this->local ? 'local' : $upload_mode; $this->destination_file = $this->destination_path . '/' . utf8_basename($this->realname); // Check if the file already exist, else there is something wrong... if (file_exists($this->destination_file) && !$overwrite) { @unlink($this->filename); $this->error[] = $user->lang($this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR', $this->destination_file); $this->file_moved = false; return false; } else { if (file_exists($this->destination_file)) { @unlink($this->destination_file); } switch ($upload_mode) { case 'copy': if (!@copy($this->filename, $this->destination_file)) { if (!@move_uploaded_file($this->filename, $this->destination_file)) { $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file); } } break; case 'move': if (!@move_uploaded_file($this->filename, $this->destination_file)) { if (!@copy($this->filename, $this->destination_file)) { $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file); } } break; case 'local': if (!@copy($this->filename, $this->destination_file)) { $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file); } break; } // Remove temporary filename @unlink($this->filename); if (sizeof($this->error)) { return false; } try { $this->filesystem->phpbb_chmod($this->destination_file, $chmod); } catch (\phpbb\filesystem\exception\filesystem_exception $e) { // Do nothing } } // Try to get real filesize from destination folder $this->filesize = @filesize($this->destination_file) ? @filesize($this->destination_file) : $this->filesize; // Get mimetype of supplied file $this->mimetype = $this->get_mimetype($this->destination_file); if ($this->is_image() && !$skip_image_check) { $this->width = $this->height = 0; // Get imagesize class $imagesize = new \fastImageSize\fastImageSize(); $this->image_info = $imagesize->getImageSize($this->destination_file, $this->mimetype); if ($this->image_info !== false) { $this->width = $this->image_info['width']; $this->height = $this->image_info['height']; // Check image type $types = fileupload::image_types(); if (!isset($types[$this->image_info['type']]) || !in_array($this->extension, $types[$this->image_info['type']])) { if (!isset($types[$this->image_info['type']])) { $this->error[] = $user->lang('IMAGE_FILETYPE_INVALID', $this->image_info['type'], $this->mimetype); } else { $this->error[] = $user->lang('IMAGE_FILETYPE_MISMATCH', $types[$this->image_info['type']][0], $this->extension); } } // Make sure the dimensions match a valid image if (empty($this->width) || empty($this->height)) { $this->error[] = $user->lang['ATTACHED_IMAGE_NOT_IMAGE']; } } else { $this->error[] = $user->lang['UNABLE_GET_IMAGE_SIZE']; } } $this->file_moved = true; $this->additional_checks(); unset($this->upload); return true; }