diff options
70 files changed, 1189 insertions, 201 deletions
diff --git a/.gitignore b/.gitignore index 3e0f454e0c..b825007244 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ +*~ phpBB/cache/*.php -*~
\ No newline at end of file +phpBB/config.php +tests/phpbb_unit_tests.sqlite2 +tests/test_config.php diff --git a/git-tools/hooks/commit-msg b/git-tools/hooks/commit-msg new file mode 100755 index 0000000000..a6777ff9c9 --- /dev/null +++ b/git-tools/hooks/commit-msg @@ -0,0 +1,258 @@ +#!/bin/sh +# +# A hook to check syntax of a phpBB3 commit message, per: +# * <http://wiki.phpbb.com/display/DEV/Git> +# * <http://area51.phpbb.com/phpBB/viewtopic.php?p=209919#p209919> +# +# This is a commit-msg hook. +# +# To install this you can either copy or symlink it to +# $GIT_DIR/hooks, example: +# +# ln -s ../../git-tools/hooks/commit-msg \\ +# .git/hooks/commit-msg + +config_ns="phpbb.hooks.commit-msg"; + +if [ "$(git config --bool $config_ns.fatal)" = "false" ] +then + fatal=0; +else + fatal=1; +fi + +debug_level=$(git config --int $config_ns.debug || echo 0); + +# Error codes +ERR_LENGTH=1; +ERR_HEADER=2; +ERR_EMPTY=3; +ERR_DESCRIPTION=4; +ERR_FOOTER=5; +ERR_EOF=6; +ERR_UNKNOWN=42; + +debug() +{ + local level; + + level=$1; + shift; + + if [ $debug_level -ge $level ] + then + echo $@; + fi +} + +quit() +{ + if [ $1 -gt 0 ] && [ $1 -ne $ERR_UNKNOWN ] && [ $fatal -eq 0 ] + then + exit 0; + else + exit $1; + fi +} + +msg=$(grep -nE '.{81,}' "$1"); + +if [ $? -eq 0 ] +then + echo "The following lines are greater than 80 characters long:\n" >&2; + echo $msg >&2; + + quit $ERR_LENGTH; +fi + +lines=$(wc -l "$1" | awk '{ print $1; }'); +expecting=header; +in_description=0; +in_empty=0; +ticket=0; +branch_regex="[a-z]+[a-z0-9-]*[a-z0-9]+"; +i=1; +tickets=""; + +while [ $i -le $lines ] +do + # Grab the line we are studying + line=$(head -n$i "$1" | tail -n1); + + debug 1 "==> [$i] $line (description: $in_description, empty: $in_empty)"; + + err=$ERR_UNKNOWN; + + if [ -z "$expecting" ] + then + quit $err; + fi + + if [ "${expecting#comment}" = "$expecting" ] + then + # Prefix comments to the expected tokens list + expecting="comment $expecting"; + fi + + debug 2 "Expecting: $expecting"; + + # Loop over each of the expected line formats + for expect in $expecting + do + # Reset the error code each iteration + err=$ERR_UNKNOWN; + + # Test for validity of each line format + # This is done first so $? contains the result + case $expect in + "header") + err=$ERR_HEADER; + echo "$line" | grep -Eq "^\[(ticket/[0-9]+|feature/$branch_regex|task/$branch_regex)\] [A-Z].+$" + ;; + "empty") + err=$ERR_EMPTY; + echo "$line" | grep -Eq "^$" + ;; + "description") + err=$ERR_DESCRIPTION; + # Free flow text, the line length was constrained by the initial check + echo "$line" | grep -Eq "^.+$"; + ;; + "footer") + err=$ERR_FOOTER; + # Each ticket is on its own line + echo "$line" | grep -Eq "^PHPBB3-[0-9]+$"; + ;; + "eof") + err=$ERR_EOF; + # Should not end up here + false + ;; + "comment") + echo "$line" | grep -Eq "^#"; + ;; + *) + echo "Unrecognised token $expect" >&2; + quit $err; + ;; + esac + + # Preserve the result of the line check + result=$?; + + debug 2 "$expect - '$line' - $result"; + + if [ $result -eq 0 ] + then + # Break out the loop on success + # otherwise roll on round and keep looking for a match + break; + fi + done + + if [ $result -eq 0 ] + then + # Have we switched out of description mode? + if [ $in_description -eq 1 ] && [ "$expect" != "description" ] && [ "$expect" != "empty" ] && [ "$expect" != "comment" ] + then + # Yes, okay we need to backtrace one line and reanalyse + in_description=0; + i=$(( $i - $in_empty )); + + # Reset the empty counter + in_empty=0; + continue; + fi + + # Successful match, but on which line format + case $expect in + "header") + expecting="empty"; + + echo "$line" | grep -Eq "^\[ticket/[0-9]+\]$" && ( + ticket=$(echo "$line" | sed 's,\[ticket/\([0-9]*\)\].*,\1,'); + ) + ;; + "empty") + # Description might have empty lines as spacing + expecting="footer description"; + in_empty=$(($in_empty + 1)); + + if [ $in_description -eq 1 ] + then + expecting="$expecting empty"; + fi + ;; + "description") + expecting="description empty"; + in_description=1; + ;; + "footer") + expecting="footer eof"; + if [ "$tickets" = "" ] + then + tickets="$line"; + else + tickets="$tickets $line"; + fi + ;; + "comment") + # Comments should expect the same thing again + ;; + *) + echo "Unrecognised token $expect" >&2; + quit 254; + ;; + esac + + if [ "$expect" != "empty" ] + then + in_empty=0; + fi + + debug 3 "Now expecting: $expecting"; + else + # None of the expected line formats matched + # Guess we'll call it a day here then + echo "Syntax error on line $i:" >&2; + echo ">> $line" >&2; + echo -n "Expecting: " >&2; + echo "$expecting" | sed 's/ /, /g' >&2; + exit $err; + fi + + i=$(( $i + 1 )); +done + +# If EOF is expected exit cleanly +echo "$expecting" | grep -q "eof" || ( + # Unexpected EOF, error + echo "Unexpected EOF encountered" >&2; + quit $ERR_EOF; +) && ( + # Do post scan checks + if [ ! -z "$tickets" ] + then + # Check for duplicate tickets + dupes=$(echo "$tickets" | sed 's/ /\n/g' | sort | uniq -d); + + if [ ! -z "$dupes" ] + then + echo "The following tickets are repeated:" >&2; + echo "$dupes" | sed 's/ /\n/g;s/^/* /g' >&2; + quit $ERR_FOOTER; + fi + fi + # Check the branch ticket is mentioned, doesn't make sense otherwise + if [ $ticket -gt 0 ] + then + echo "$tickets" | grep -Eq "\bPHPBB3-$ticket\b" || ( + echo "Ticket ID [$ticket] of branch missing from list of tickets:" >&2; + echo "$tickets" | sed 's/ /\n/g;s/^/* /g' >&2; + quit $ERR_FOOTER; + ) || exit $?; + fi + # Got here okay exit to reality + exit 0; +); +exit $?; diff --git a/git-tools/hooks/install b/git-tools/hooks/install new file mode 100755 index 0000000000..a42c55a769 --- /dev/null +++ b/git-tools/hooks/install @@ -0,0 +1,17 @@ +#!/bin/sh +# +# Script to install the git hooks +# by symlinking them into the .git/hooks directory +# +# Usage (from within git-tools/hooks): +# ./install + +dir=$(dirname $0) + +for file in $(ls $dir) +do + if [ $file != "install" ] && [ $file != "uninstall" ] + then + ln -s "../../git-tools/hooks/$file" "$dir/../../.git/hooks/$file" + fi +done diff --git a/git-tools/hooks/pre-commit b/git-tools/hooks/pre-commit index 9719b91746..4d03359773 100755 --- a/git-tools/hooks/pre-commit +++ b/git-tools/hooks/pre-commit @@ -27,6 +27,13 @@ fi error=0 errors="" +if ! which $PHP_BIN >/dev/null 2>&1 +then + echo "PHP Syntax check failed:" + echo "PHP binary does not exist or is not in path: $PHP_BIN" + exit 1 +fi + # dash does not support $'\n': # http://forum.soft32.com/linux2/Bug-409179-DASH-Settings-IFS-work-properly-ftopict70039.html IFS=' diff --git a/git-tools/hooks/prepare-commit-msg b/git-tools/hooks/prepare-commit-msg index 033cb187c7..2bf25e58a4 100755 --- a/git-tools/hooks/prepare-commit-msg +++ b/git-tools/hooks/prepare-commit-msg @@ -30,5 +30,13 @@ branch="$(echo "$branch" | sed "s/refs\/heads\///g")" # * also make sure the branch name begins with bug/ or feature/ if [ "$2" = "" ] then - echo "[$branch] $(cat "$1")" > "$1" + tail=""; + + # Branch is prefixed with 'ticket/', append ticket ID to message + if [ "$branch" != "${branch##ticket/}" ]; + then + tail="\n\nPHPBB3-${branch##ticket/}"; + fi + + echo "[$branch]$tail $(cat "$1")" > "$1" fi diff --git a/git-tools/hooks/uninstall b/git-tools/hooks/uninstall new file mode 100755 index 0000000000..1b3b7fd2c9 --- /dev/null +++ b/git-tools/hooks/uninstall @@ -0,0 +1,16 @@ +#!/bin/sh +# +# Script to uninstall the git hooks +# +# Usage (from within git-tools/hooks): +# ./uninstall + +dir=$(dirname $0) + +for file in $(ls $dir) +do + if [ $file != "install" ] && [ $file != "uninstall" ] + then + rm -f "$dir/../../.git/hooks/$file" + fi +done diff --git a/phpBB/adm/index.php b/phpBB/adm/index.php index 26f934f6bf..92bcf90039 100644 --- a/phpBB/adm/index.php +++ b/phpBB/adm/index.php @@ -432,6 +432,20 @@ function validate_config_vars($config_vars, &$cfg_array, &$error) { $error[] = sprintf($user->lang['SETTING_TOO_BIG'], $user->lang[$config_definition['lang']], $validator[$max]); } + + if (strpos($config_name, '_max') !== false) + { + // Min/max pairs of settings should ensure that min <= max + // Replace _max with _min to find the name of the minimum + // corresponding configuration variable + $min_name = str_replace('_max', '_min', $config_name); + + if (isset($cfg_array[$min_name]) && is_numeric($cfg_array[$min_name]) && $cfg_array[$config_name] < $cfg_array[$min_name]) + { + // A minimum value exists and the maximum value is less than it + $error[] = sprintf($user->lang['SETTING_TOO_LOW'], $user->lang[$config_definition['lang']], (int) $cfg_array[$min_name]); + } + } break; // Absolute path @@ -533,7 +547,7 @@ function validate_config_vars($config_vars, &$cfg_array, &$error) // Check if the path is writable if ($config_definition['validate'] == 'wpath' || $config_definition['validate'] == 'rwpath') { - if (file_exists($phpbb_root_path . $cfg_array[$config_name]) && !@is_writable($phpbb_root_path . $cfg_array[$config_name])) + if (file_exists($phpbb_root_path . $cfg_array[$config_name]) && !phpbb_is_writable($phpbb_root_path . $cfg_array[$config_name])) { $error[] = sprintf($user->lang['DIRECTORY_NOT_WRITABLE'], $cfg_array[$config_name]); } diff --git a/phpBB/adm/style/admin.css b/phpBB/adm/style/admin.css index 5f1f01c0a9..4c3fa51af3 100644 --- a/phpBB/adm/style/admin.css +++ b/phpBB/adm/style/admin.css @@ -670,14 +670,10 @@ legend { position: relative; text-transform: none; line-height: 1.2em; - top: 0; + top: -.2em; vertical-align: middle; } -/* Hide from macIE \*/ -legend { top: -1.2em; } -/* end */ - * html legend { margin: 0 0 -10px -7px; line-height: 1em; diff --git a/phpBB/common.php b/phpBB/common.php index 9b6913e95f..c8b2fb9609 100644 --- a/phpBB/common.php +++ b/phpBB/common.php @@ -123,13 +123,11 @@ if (defined('IN_CRON')) $phpbb_root_path = dirname(__FILE__) . DIRECTORY_SEPARATOR; } -if (!file_exists($phpbb_root_path . 'config.' . $phpEx)) +if (file_exists($phpbb_root_path . 'config.' . $phpEx)) { - die("<p>The config.$phpEx file could not be found.</p><p><a href=\"{$phpbb_root_path}install/index.$phpEx\">Click here to install phpBB</a></p>"); + require($phpbb_root_path . 'config.' . $phpEx); } -require($phpbb_root_path . 'config.' . $phpEx); - if (!defined('PHPBB_INSTALLED')) { // Redirect the user to the installer diff --git a/phpBB/config.php b/phpBB/config.php deleted file mode 100644 index e69de29bb2..0000000000 --- a/phpBB/config.php +++ /dev/null diff --git a/phpBB/docs/AUTHORS b/phpBB/docs/AUTHORS index 84677c4e15..b3166313c3 100644 --- a/phpBB/docs/AUTHORS +++ b/phpBB/docs/AUTHORS @@ -26,8 +26,8 @@ phpBB Developers: A_Jelly_Doughnut (Josh Woody) Acyd Burn (Meik Sievertsen) [Lead 09/2005 - 01/2010] APTX (Marek A. R.) bantu (Andreas Fischer) - DavidMJ (David M.) dhn (Dominik Dröscher) + igorw (Igor Wiedler) kellanved (Henry Sudhof) nickvergessen (Joas Schilling) rxu (Ruslan Uzdenov) @@ -49,6 +49,7 @@ phpBB Lead Developer: psoTFX (Paul S. Owen) [2001 - 09/2005] phpBB Developers: Ashe (Ludovic Arnaud) [10/2002 - 11/2003, 06/2006 - 10/2006] BartVB (Bart van Bragt) [11/2000 - 03/2006] + DavidMJ (David M.) [12/2005 - 08/2009] GrahamJE (Graham Eames) [09/2005 - 11/2006] Vic D'Elfant (Vic D'Elfant) [04/2007 - 04/2009] diff --git a/phpBB/docs/README.html b/phpBB/docs/README.html index 3510bc448e..bb88fdc01f 100644 --- a/phpBB/docs/README.html +++ b/phpBB/docs/README.html @@ -242,7 +242,7 @@ <p>The phpBB Group uses a bug tracking system to store, list and manage all reported bugs, it can be found at the location listed below. Please <strong>DO NOT</strong> post bug reports to our forums, they will be locked. In addition please <strong>DO NOT</strong> use the bug tracker for support requests. Posting such a request will only see you directed to the support forums (while taking time away from working on real bugs).</p> - <p><a href="http://www.phpbb.com/bugs/">http://www.phpbb.com/bugs/</a></p> + <p><a href="http://tracker.phpbb.com/">http://tracker.phpbb.com/</a></p> <p>While we very much appreciate receiving bug reports (the more reports the more stable phpBB will be) we ask you carry out a few steps before adding new entries:</p> diff --git a/phpBB/download/file.php b/phpBB/download/file.php index 2154847865..5f45b88359 100644 --- a/phpBB/download/file.php +++ b/phpBB/download/file.php @@ -31,6 +31,12 @@ else if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT' if (isset($_GET['avatar'])) { + if (!defined('E_DEPRECATED')) + { + define('E_DEPRECATED', 8192); + } + error_reporting(E_ALL ^ E_NOTICE ^ E_DEPRECATED); + require($phpbb_root_path . 'config.' . $phpEx); if (!defined('PHPBB_INSTALLED') || empty($dbms) || empty($acm_type)) @@ -42,6 +48,7 @@ if (isset($_GET['avatar'])) require($phpbb_root_path . 'includes/cache.' . $phpEx); require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); + require($phpbb_root_path . 'includes/functions.' . $phpEx); $db = new $sql_db(); $cache = new cache(); @@ -61,7 +68,7 @@ if (isset($_GET['avatar'])) $avatar_group = false; $exit = false; - if ($filename[0] === 'g') + if (isset($filename[0]) && $filename[0] === 'g') { $avatar_group = true; $filename = substr($filename, 1); @@ -70,7 +77,7 @@ if (isset($_GET['avatar'])) // '==' is not a bug - . as the first char is as bad as no dot at all if (strpos($filename, '.') == false) { - header('HTTP/1.0 403 Forbidden'); + send_status_line(403, 'Forbidden'); $exit = true; } @@ -84,7 +91,7 @@ if (isset($_GET['avatar'])) if (!$exit && !in_array($ext, array('png', 'gif', 'jpg', 'jpeg'))) { // no way such an avatar could exist. They are not following the rules, stop the show. - header("HTTP/1.0 403 Forbidden"); + send_status_line(403, 'Forbidden'); $exit = true; } @@ -94,7 +101,7 @@ if (isset($_GET['avatar'])) if (!$filename) { // no way such an avatar could exist. They are not following the rules, stop the show. - header("HTTP/1.0 403 Forbidden"); + send_status_line(403, 'Forbidden'); } else { @@ -192,7 +199,7 @@ else $row['forum_id'] = false; if (!$auth->acl_get('u_pm_download')) { - header('HTTP/1.0 403 Forbidden'); + send_status_line(403, 'Forbidden'); trigger_error('SORRY_AUTH_VIEW_ATTACH'); } @@ -215,7 +222,7 @@ else if (!$allowed) { - header('HTTP/1.0 403 Forbidden'); + send_status_line(403, 'Forbidden'); trigger_error('ERROR_NO_ATTACHMENT'); } } @@ -230,7 +237,7 @@ else if (!download_allowed()) { - header('HTTP/1.0 403 Forbidden'); + send_status_line(403, 'Forbidden'); trigger_error($user->lang['LINKAGE_FORBIDDEN']); } @@ -376,7 +383,7 @@ function send_avatar_to_browser($file, $browser) } else { - header('HTTP/1.0 404 Not Found'); + send_status_line(404, 'Not Found'); } } diff --git a/phpBB/includes/acm/acm_file.php b/phpBB/includes/acm/acm_file.php index 5a758aa2bb..5c1876d006 100644 --- a/phpBB/includes/acm/acm_file.php +++ b/phpBB/includes/acm/acm_file.php @@ -78,8 +78,14 @@ class acm if (!$this->_write('data_global')) { + if (!function_exists('phpbb_is_writable')) + { + global $phpbb_root_path; + include($phpbb_root_path . 'includes/functions.' . $phpEx); + } + // Now, this occurred how often? ... phew, just tell the user then... - if (!@is_writable($this->cache_dir)) + if (!phpbb_is_writable($this->cache_dir)) { // We need to use die() here, because else we may encounter an infinite loop (the message handler calls $cache->unload()) die($this->cache_dir . ' is NOT writable.'); @@ -707,7 +713,13 @@ class acm */ function remove_file($filename, $check = false) { - if ($check && !@is_writable($this->cache_dir)) + if (!function_exists('phpbb_is_writable')) + { + global $phpbb_root_path, $phpEx; + include($phpbb_root_path . 'includes/functions.' . $phpEx); + } + + if ($check && !phpbb_is_writable($this->cache_dir)) { // E_USER_ERROR - not using language entry - intended. trigger_error('Unable to remove files within ' . $this->cache_dir . '. Please check directory permissions.', E_USER_ERROR); diff --git a/phpBB/includes/acm/acm_memory.php b/phpBB/includes/acm/acm_memory.php index efbfd4dd62..2936ea0bae 100644 --- a/phpBB/includes/acm/acm_memory.php +++ b/phpBB/includes/acm/acm_memory.php @@ -407,7 +407,13 @@ class acm_memory */ function remove_file($filename, $check = false) { - if ($check && !@is_writable($this->cache_dir)) + if (!function_exists('phpbb_is_writable')) + { + global $phpbb_root_path, $phpEx; + include($phpbb_root_path . 'includes/functions.' . $phpEx); + } + + if ($check && !phpbb_is_writable($this->cache_dir)) { // E_USER_ERROR - not using language entry - intended. trigger_error('Unable to remove files within ' . $this->cache_dir . '. Please check directory permissions.', E_USER_ERROR); diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php index 980558c830..fc5f44e14f 100644 --- a/phpBB/includes/acp/acp_attachments.php +++ b/phpBB/includes/acp/acp_attachments.php @@ -1222,7 +1222,7 @@ class acp_attachments return; } - if (!is_writable($phpbb_root_path . $upload_dir)) + if (!phpbb_is_writable($phpbb_root_path . $upload_dir)) { $error[] = sprintf($user->lang['NO_WRITE_UPLOAD'], $upload_dir); return; diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index 927e72010e..a5e80e1f6d 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -319,6 +319,7 @@ class acp_board 'load_online_guests' => array('lang' => 'YES_ONLINE_GUESTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'load_onlinetrack' => array('lang' => 'YES_ONLINE_TRACK', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'load_birthdays' => array('lang' => 'YES_BIRTHDAYS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'load_unreads_search' => array('lang' => 'YES_UNREAD_SEARCH', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_moderators' => array('lang' => 'YES_MODERATORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_jumpbox' => array('lang' => 'YES_JUMPBOX', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_user_activity' => array('lang' => 'LOAD_USER_ACTIVITY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), diff --git a/phpBB/includes/acp/acp_forums.php b/phpBB/includes/acp/acp_forums.php index f2f1bd80e2..4d9b9f01e0 100644 --- a/phpBB/includes/acp/acp_forums.php +++ b/phpBB/includes/acp/acp_forums.php @@ -1642,6 +1642,9 @@ class acp_forums delete_attachments('topic', $topic_ids, false); + // Delete shadow topics pointing to topics in this forum + delete_topic_shadows($forum_id); + // Before we remove anything we make sure we are able to adjust the post counts later. ;) $sql = 'SELECT poster_id FROM ' . POSTS_TABLE . ' diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php index 3df61ff4e2..60512c67b8 100644 --- a/phpBB/includes/acp/acp_groups.php +++ b/phpBB/includes/acp/acp_groups.php @@ -49,7 +49,7 @@ class acp_groups // Clear some vars - $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && @is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false; + $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false; $group_row = array(); // Grab basic data for group, if group_id is set and exists diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php index 3310560c73..2ccc728031 100644 --- a/phpBB/includes/acp/acp_styles.php +++ b/phpBB/includes/acp/acp_styles.php @@ -748,7 +748,7 @@ parse_css_file = {PARSE_CSS_FILE} $additional = ''; // If the template is stored on the filesystem try to write the file else store it in the database - if (!$safe_mode && !$template_info['template_storedb'] && file_exists($file) && @is_writable($file)) + if (!$safe_mode && !$template_info['template_storedb'] && file_exists($file) && phpbb_is_writable($file)) { if (!($fp = @fopen($file, 'wb'))) { @@ -1155,7 +1155,7 @@ parse_css_file = {PARSE_CSS_FILE} $message = $user->lang['THEME_UPDATED']; // If the theme is stored on the filesystem try to write the file else store it in the database - if (!$safe_mode && !$theme_info['theme_storedb'] && file_exists($file) && @is_writable($file)) + if (!$safe_mode && !$theme_info['theme_storedb'] && file_exists($file) && phpbb_is_writable($file)) { if (!($fp = @fopen($file, 'wb'))) { @@ -2040,23 +2040,18 @@ parse_css_file = {PARSE_CSS_FILE} { case 'tar': $ext = '.tar'; - $mimetype = 'x-tar'; - $compress = 'compress_tar'; break; case 'zip': $ext = '.zip'; - $mimetype = 'zip'; break; case 'tar.gz': $ext = '.tar.gz'; - $mimetype = 'x-gzip'; break; case 'tar.bz2': $ext = '.tar.bz2'; - $mimetype = 'x-bzip2'; break; default: @@ -2246,7 +2241,7 @@ parse_css_file = {PARSE_CSS_FILE} { // a rather elaborate check we have to do here once to avoid trouble later $check = "{$phpbb_root_path}styles/" . $style_row["{$mode}_path"] . (($mode === 'theme') ? '/theme/stylesheet.css' : '/template'); - if (($style_row["{$mode}_storedb"] != $store_db) && !$store_db && ($safe_mode || !@is_writable($check))) + if (($style_row["{$mode}_storedb"] != $store_db) && !$store_db && ($safe_mode || !phpbb_is_writable($check))) { $error[] = $user->lang['EDIT_' . strtoupper($mode) . '_STORED_DB']; $store_db = 1; @@ -2326,7 +2321,7 @@ parse_css_file = {PARSE_CSS_FILE} { $theme_data = $this->db_theme_data($style_row); } - else if (!$store_db && !$safe_mode && @is_writable("{$phpbb_root_path}styles/{$style_row['theme_path']}/theme/stylesheet.css")) + else if (!$store_db && !$safe_mode && phpbb_is_writable("{$phpbb_root_path}styles/{$style_row['theme_path']}/theme/stylesheet.css")) { $store_db = 1; $theme_data = $style_row['theme_data']; @@ -2357,7 +2352,7 @@ parse_css_file = {PARSE_CSS_FILE} } else { - if (!$store_db && !$safe_mode && @is_writable("{$phpbb_root_path}styles/{$style_row['template_path']}/template")) + if (!$store_db && !$safe_mode && phpbb_is_writable("{$phpbb_root_path}styles/{$style_row['template_path']}/template")) { $err = $this->store_in_fs('template', $style_row['template_id']); if ($err) @@ -2531,13 +2526,21 @@ parse_css_file = {PARSE_CSS_FILE} // Match CSS imports $matches = array(); - preg_match_all('/@import url\(["\'](.*)["\']\);/i', $stylesheet, $matches); + preg_match_all('/@import url\((["\'])(.*)\1\);/i', $stylesheet, $matches); + + // remove commented stylesheets (very simple parser, allows only whitespace + // around an @import statement) + preg_match_all('#/\*\s*@import url\((["\'])(.*)\1\);\s\*/#i', $stylesheet, $commented); + $matches[2] = array_diff($matches[2], $commented[2]); if (sizeof($matches)) { foreach ($matches[0] as $idx => $match) { - $stylesheet = str_replace($match, acp_styles::load_css_file($theme_row['theme_path'], $matches[1][$idx]), $stylesheet); + if (isset($matches[2][$idx])) + { + $stylesheet = str_replace($match, acp_styles::load_css_file($theme_row['theme_path'], $matches[2][$idx]), $stylesheet); + } } } @@ -3728,7 +3731,7 @@ parse_css_file = {PARSE_CSS_FILE} $store_db = 0; $error = array(); - if (!$safe_mode && @is_writable("{$phpbb_root_path}styles/{$path}/template")) + if (!$safe_mode && phpbb_is_writable("{$phpbb_root_path}styles/{$path}/template")) { $sql = 'SELECT * FROM ' . STYLES_TEMPLATE_DATA_TABLE . " diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index 1f10893781..6be0760be0 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -319,10 +319,7 @@ class acp_users $server_url = generate_board_url(); - $user_actkey = gen_rand_string(10); - $key_len = 54 - (strlen($server_url)); - $key_len = ($key_len > 6) ? $key_len : 6; - $user_actkey = substr($user_actkey, 0, $key_len); + $user_actkey = gen_rand_string(mt_rand(6, 10)); $email_template = ($user_row['user_type'] == USER_NORMAL) ? 'user_reactivate_account' : 'user_resend_inactive'; if ($user_row['user_type'] == USER_NORMAL) @@ -1701,7 +1698,7 @@ class acp_users include($phpbb_root_path . 'includes/functions_display.' . $phpEx); include($phpbb_root_path . 'includes/functions_user.' . $phpEx); - $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && @is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false; + $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false; if ($submit) { diff --git a/phpBB/includes/cache.php b/phpBB/includes/cache.php index 6b1e078ca4..b50fab4ca2 100644 --- a/phpBB/includes/cache.php +++ b/phpBB/includes/cache.php @@ -88,7 +88,14 @@ class cache extends acm { if ($unicode) { - $censors['match'][] = '#(?<![\p{Nd}\p{L}_])(' . str_replace('\*', '[\p{Nd}\p{L}_]*?', preg_quote($row['word'], '#')) . ')(?![\p{Nd}\p{L}_])#iu'; + // Unescape the asterisk to simplify further conversions + $row['word'] = str_replace('\*', '*', preg_quote($row['word'], '#')); + + // Replace the asterisk inside the pattern, at the start and at the end of it with regexes + $row['word'] = preg_replace(array('#(?<=[\p{Nd}\p{L}_])\*(?=[\p{Nd}\p{L}_])#iu', '#^\*#', '#\*$#'), array('([\x20]*?|[\p{Nd}\p{L}_-]*?)', '[\p{Nd}\p{L}_-]*?', '[\p{Nd}\p{L}_-]*?'), $row['word']); + + // Generate the final substitution + $censors['match'][] = '#(?<![\p{Nd}\p{L}_-])(' . $row['word'] . ')(?![\p{Nd}\p{L}_-])#iu'; } else { diff --git a/phpBB/includes/captcha/plugins/captcha_abstract.php b/phpBB/includes/captcha/plugins/captcha_abstract.php index e7b8742b05..21cacd730c 100644 --- a/phpBB/includes/captcha/plugins/captcha_abstract.php +++ b/phpBB/includes/captcha/plugins/captcha_abstract.php @@ -59,7 +59,7 @@ class phpbb_default_captcha { global $user; - $this->code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); + $this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); $this->seed = hexdec(substr(unique_id(), 4, 10)); // compute $seed % 0x7fffffff @@ -235,7 +235,7 @@ class phpbb_default_captcha { global $db, $user; - $this->code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); + $this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); $this->confirm_id = md5(unique_id($user->ip)); $this->seed = hexdec(substr(unique_id(), 4, 10)); $this->solved = 0; @@ -259,7 +259,7 @@ class phpbb_default_captcha { global $db, $user; - $this->code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); + $this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); $this->seed = hexdec(substr(unique_id(), 4, 10)); $this->solved = 0; // compute $seed % 0x7fffffff @@ -281,7 +281,7 @@ class phpbb_default_captcha { global $db, $user; - $this->code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); + $this->code = gen_rand_string_friendly(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); $this->seed = hexdec(substr(unique_id(), 4, 10)); $this->solved = 0; // compute $seed % 0x7fffffff diff --git a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php index 0f0bfc4156..ea171dbe2c 100644 --- a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php @@ -314,10 +314,7 @@ class phpbb_recaptcha extends phpbb_default_captcha } else { - if ($answers[1] === 'incorrect-captcha-sol') - { - return $user->lang['RECAPTCHA_INCORRECT']; - } + return $user->lang['RECAPTCHA_INCORRECT']; } } diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index 819ef69c96..f4b181c6ad 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -611,7 +611,7 @@ class phpbb_db_tools * drop_columns: Removing/Dropping columns * add_primary_keys: adding primary keys * add_unique_index: adding an unique index - * add_index: adding an index + * add_index: adding an index (can be column:index_size if you need to provide size) * * The values are in this format: * {TABLE NAME} => array( @@ -1804,6 +1804,12 @@ class phpbb_db_tools { $statements = array(); + // remove index length unless MySQL4 + if ('mysql_40' != $this->sql_layer) + { + $column = preg_replace('#:.*$#', '', $column); + } + switch ($this->sql_layer) { case 'firebird': @@ -1814,6 +1820,16 @@ class phpbb_db_tools break; case 'mysql_40': + // add index size to definition as required by MySQL4 + foreach ($column as $i => $col) + { + if (false !== strpos($col, ':')) + { + list($col, $index_size) = explode(':', $col); + $column[$i] = "$col($index_size)"; + } + } + // no break case 'mysql_41': $statements[] = 'CREATE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; break; diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index 44d5722e4f..44d5722e4f 100755..100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index bc3d721de5..9aec98dce2 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -195,10 +195,27 @@ function set_config_count($config_name, $increment, $is_dynamic = false) /** * Generates an alphanumeric random string of given length +* +* @return string */ function gen_rand_string($num_chars = 8) { + // [a, z] + [0, 9] = 36 + return substr(strtoupper(base_convert(unique_id(), 16, 36)), 0, $num_chars); +} + +/** +* Generates a user-friendly alphanumeric random string of given length +* We remove 0 and O so users cannot confuse those in passwords etc. +* +* @return string +*/ +function gen_rand_string_friendly($num_chars = 8) +{ $rand_str = unique_id(); + + // Remove Z and Y from the base_convert(), replace 0 with Z and O with Y + // [a, z] + [0, 9] - {z, y} = [a, z] + [0, 9] - {0, o} = 34 $rand_str = str_replace(array('0', 'O'), array('Z', 'Y'), strtoupper(base_convert($rand_str, 16, 34))); return substr($rand_str, 0, $num_chars); @@ -701,7 +718,7 @@ function phpbb_chmod($filename, $perms = CHMOD_READ) clearstatcache(); - if (is_readable($filename) && is_writable($filename)) + if (is_readable($filename) && phpbb_is_writable($filename)) { break; } @@ -711,7 +728,7 @@ function phpbb_chmod($filename, $perms = CHMOD_READ) clearstatcache(); - if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || is_writable($filename))) + if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || phpbb_is_writable($filename))) { break; } @@ -721,7 +738,7 @@ function phpbb_chmod($filename, $perms = CHMOD_READ) clearstatcache(); - if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || is_writable($filename))) + if ((!($perms & CHMOD_READ) || is_readable($filename)) && (!($perms & CHMOD_WRITE) || phpbb_is_writable($filename))) { break; } @@ -2519,6 +2536,11 @@ function build_url($strip_vars = false) $key = $arguments[0]; unset($arguments[0]); + if ($key === '') + { + continue; + } + $query[$key] = implode('=', $arguments); } @@ -3440,26 +3462,110 @@ function short_ipv6($ip, $length) /** * Wrapper for php's checkdnsrr function. * -* The windows failover is from the php manual -* Please make sure to check the return value for === true and === false, since NULL could -* be returned too. +* @param string $host Fully-Qualified Domain Name +* @param string $type Resource record type to lookup +* Supported types are: MX (default), A, AAAA, NS, TXT, CNAME +* Other types may work or may not work +* +* @return mixed true if entry found, +* false if entry not found, +* null if this function is not supported by this environment * -* @return true if entry found, false if not, NULL if this function is not supported by this environment +* Since null can also be returned, you probably want to compare the result +* with === true or === false, +* +* @author bantu */ -function phpbb_checkdnsrr($host, $type = '') +function phpbb_checkdnsrr($host, $type = 'MX') { - $type = (!$type) ? 'MX' : $type; + // The dot indicates to search the DNS root (helps those having DNS prefixes on the same domain) + if (substr($host, -1) == '.') + { + $host_fqdn = $host; + $host = substr($host, 0, -1); + } + else + { + $host_fqdn = $host . '.'; + } + // $host has format some.host.example.com + // $host_fqdn has format some.host.example.com. + + // If we're looking for an A record we can use gethostbyname() + if ($type == 'A' && function_exists('gethostbyname')) + { + return (@gethostbyname($host_fqdn) == $host_fqdn) ? false : true; + } + + // checkdnsrr() is available on Windows since PHP 5.3, + // but until 5.3.3 it only works for MX records + // See: http://bugs.php.net/bug.php?id=51844 - // Call checkdnsrr() if available. This is also the case on Windows with PHP 5.3 or later. - if (function_exists('checkdnsrr')) + // Call checkdnsrr() if + // we're looking for an MX record or + // we're not on Windows or + // we're running a PHP version where #51844 has been fixed + + // checkdnsrr() supports AAAA since 5.0.0 + // checkdnsrr() supports TXT since 5.2.4 + if ( + ($type == 'MX' || DIRECTORY_SEPARATOR != '\\' || version_compare(PHP_VERSION, '5.3.3', '>=')) && + ($type != 'AAAA' || version_compare(PHP_VERSION, '5.0.0', '>=')) && + ($type != 'TXT' || version_compare(PHP_VERSION, '5.2.4', '>=')) && + function_exists('checkdnsrr') + ) { - // The dot indicates to search the DNS root (helps those having DNS prefixes on the same domain) - return checkdnsrr($host . '.', $type); + return checkdnsrr($host_fqdn, $type); } - else if (DIRECTORY_SEPARATOR == '\\' && function_exists('exec')) + + // dns_get_record() is available since PHP 5; since PHP 5.3 also on Windows, + // but on Windows it does not work reliable for AAAA records before PHP 5.3.1 + + // Call dns_get_record() if + // we're not looking for an AAAA record or + // we're not on Windows or + // we're running a PHP version where AAAA lookups work reliable + if ( + ($type != 'AAAA' || DIRECTORY_SEPARATOR != '\\' || version_compare(PHP_VERSION, '5.3.1', '>=')) && + function_exists('dns_get_record') + ) { - // @exec('nslookup -retry=1 -timout=1 -type=' . escapeshellarg($type) . ' ' . escapeshellarg($host), $output); - @exec('nslookup -type=' . escapeshellarg($type) . ' ' . escapeshellarg($host) . '.', $output); + // dns_get_record() expects an integer as second parameter + // We have to convert the string $type to the corresponding integer constant. + $type_constant = 'DNS_' . $type; + $type_param = (defined($type_constant)) ? constant($type_constant) : DNS_ANY; + + // dns_get_record() might throw E_WARNING and return false for records that do not exist + $resultset = @dns_get_record($host_fqdn, $type_param); + + if (empty($resultset) || !is_array($resultset)) + { + return false; + } + else if ($type_param == DNS_ANY) + { + // $resultset is a non-empty array + return true; + } + + foreach ($resultset as $result) + { + if ( + isset($result['host']) && $result['host'] == $host && + isset($result['type']) && $result['type'] == $type + ) + { + return true; + } + } + + return false; + } + + // If we're on Windows we can still try to call nslookup via exec() as a last resort + if (DIRECTORY_SEPARATOR == '\\' && function_exists('exec')) + { + @exec('nslookup -type=' . escapeshellarg($type) . ' ' . escapeshellarg($host_fqdn), $output); // If output is empty, the nslookup failed if (empty($output)) @@ -3469,15 +3575,66 @@ function phpbb_checkdnsrr($host, $type = '') foreach ($output as $line) { - if (!trim($line)) + $line = trim($line); + + if (empty($line)) { continue; } - // Valid records begin with host name: - if (strpos($line, $host) === 0) + // Squash tabs and multiple whitespaces to a single whitespace. + $line = preg_replace('/\s+/', ' ', $line); + + switch ($type) { - return true; + case 'MX': + if (stripos($line, "$host MX") === 0) + { + return true; + } + break; + + case 'NS': + if (stripos($line, "$host nameserver") === 0) + { + return true; + } + break; + + case 'TXT': + if (stripos($line, "$host text") === 0) + { + return true; + } + break; + + case 'CNAME': + if (stripos($line, "$host canonical name") === 0) + { + return true; + } + + default: + case 'A': + case 'AAAA': + if (!empty($host_matches)) + { + // Second line + if (stripos($line, "Address: ") === 0) + { + return true; + } + else + { + $host_matches = false; + } + } + else if (stripos($line, "Name: $host") === 0) + { + // First line + $host_matches = true; + } + break; } } @@ -3596,7 +3753,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) } // Do not send 200 OK, but service unavailable on errors - header('HTTP/1.1 503 Service Unavailable'); + send_status_line(503, 'Service Unavailable'); garbage_collection(); @@ -4066,7 +4223,8 @@ function phpbb_http_login($param) } else if ($auth_result['status'] == LOGIN_ERROR_ATTEMPTS) { - header('HTTP/1.0 401 Unauthorized'); + send_status_line(401, 'Unauthorized'); + trigger_error('NOT_AUTHORISED'); } } @@ -4078,7 +4236,7 @@ function phpbb_http_login($param) $param['auth_message'] = preg_replace('/[\x80-\xFF]/', '?', $param['auth_message']); header('WWW-Authenticate: Basic realm="' . $param['auth_message'] . '"'); - header('HTTP/1.0 401 Unauthorized'); + send_status_line(401, 'Unauthorized'); trigger_error('NOT_AUTHORISED'); } @@ -4308,6 +4466,8 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'S_ENABLE_FEEDS_TOPICS_ACTIVE' => ($config['feed_topics_active']) ? true : false, 'S_ENABLE_FEEDS_NEWS' => ($s_feed_news) ? true : false, + 'S_LOAD_UNREADS' => ($config['load_unreads_search']) ? true : false, + 'T_THEME_PATH' => "{$web_path}styles/" . $user->theme['theme_path'] . '/theme', 'T_TEMPLATE_PATH' => "{$web_path}styles/" . $user->theme['template_path'] . '/template', 'T_SUPER_TEMPLATE_PATH' => (isset($user->theme['template_inherit_path']) && $user->theme['template_inherit_path']) ? "{$web_path}styles/" . $user->theme['template_inherit_path'] . '/template' : "{$web_path}styles/" . $user->theme['template_path'] . '/template', diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index 89892feb30..3178d35c34 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -1125,53 +1125,65 @@ function delete_attachments($mode, $ids, $resync = true) } /** -* Remove topic shadows +* Deletes shadow topics pointing to a specified forum. +* +* @param int $forum_id The forum id +* @param string $sql_more Additional WHERE statement, e.g. t.topic_time < (time() - 1234) +* @param bool $auto_sync Will call sync() if this is true +* +* @return array Array with affected forums +* +* @author bantu */ -function delete_topic_shadows($max_age, $forum_id = '', $auto_sync = true) +function delete_topic_shadows($forum_id, $sql_more = '', $auto_sync = true) { - $where = (is_array($forum_id)) ? 'AND ' . $db->sql_in_set('t.forum_id', array_map('intval', $forum_id)) : (($forum_id) ? 'AND t.forum_id = ' . (int) $forum_id : ''); + global $db; - switch ($db->sql_layer) + if (!$forum_id) { - case 'mysql4': - case 'mysqli': - $sql = 'DELETE t.* - FROM ' . TOPICS_TABLE . ' t, ' . TOPICS_TABLE . ' t2 - WHERE t.topic_moved_id = t2.topic_id - AND t.topic_time < ' . (time() - $max_age) - . $where; - $db->sql_query($sql); - break; + // Nothing to do. + return; + } - default: - $sql = 'SELECT t.topic_id - FROM ' . TOPICS_TABLE . ' t, ' . TOPICS_TABLE . ' t2 - WHERE t.topic_moved_id = t2.topic_id - AND t.topic_time < ' . (time() - $max_age) - . $where; - $result = $db->sql_query($sql); + // Set of affected forums we have to resync + $sync_forum_ids = array(); - $topic_ids = array(); - while ($row = $db->sql_fetchrow($result)) - { - $topic_ids[] = $row['topic_id']; - } - $db->sql_freeresult($result); + // Amount of topics we select and delete at once. + $batch_size = 500; - if (sizeof($topic_ids)) - { - $sql = 'DELETE FROM ' . TOPICS_TABLE . ' - WHERE ' . $db->sql_in_set('topic_id', $topic_ids); - $db->sql_query($sql); - } - break; + do + { + $sql = 'SELECT t2.forum_id, t2.topic_id + FROM ' . TOPICS_TABLE . ' t2, ' . TOPICS_TABLE . ' t + WHERE t2.topic_moved_id = t.topic_id + AND t.forum_id = ' . (int) $forum_id . ' + ' . (($sql_more) ? 'AND ' . $sql_more : ''); + $result = $db->sql_query_limit($sql, $batch_size); + + $topic_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $topic_ids[] = (int) $row['topic_id']; + + $sync_forum_ids[(int) $row['forum_id']] = (int) $row['forum_id']; + } + $db->sql_freeresult($result); + + if (!empty($topic_ids)) + { + $sql = 'DELETE FROM ' . TOPICS_TABLE . ' + WHERE ' . $db->sql_in_set('topic_id', $topic_ids); + $db->sql_query($sql); + } } + while (sizeof($topic_ids) == $batch_size); if ($auto_sync) { - $where_type = ($forum_id) ? 'forum_id' : ''; - sync('forum', $where_type, $forum_id, true, true); + sync('forum', 'forum_id', $sync_forum_ids, true, true); } + + return $sync_forum_ids; } /** diff --git a/phpBB/includes/functions_compress.php b/phpBB/includes/functions_compress.php index f422eaa8c1..455debd939 100644 --- a/phpBB/includes/functions_compress.php +++ b/phpBB/includes/functions_compress.php @@ -53,13 +53,18 @@ class compress $filelist = filelist("$phpbb_root_path$src", '', '*'); krsort($filelist); + /** + * Commented out, as adding the folders produces corrupted archives if ($src_path) { $this->data($src_path, '', true, stat("$phpbb_root_path$src")); } + */ foreach ($filelist as $path => $file_ary) { + /** + * Commented out, as adding the folders produces corrupted archives if ($path) { // Same as for src_path @@ -68,6 +73,7 @@ class compress $this->data("$src_path$path", '', true, stat("$phpbb_root_path$src$path")); } + */ foreach ($file_ary as $file) { diff --git a/phpBB/includes/functions_convert.php b/phpBB/includes/functions_convert.php index c035fd3739..9e26043b39 100644 --- a/phpBB/includes/functions_convert.php +++ b/phpBB/includes/functions_convert.php @@ -2306,7 +2306,7 @@ function copy_file($src, $trg, $overwrite = false, $die_on_failure = true, $sour } } - if (!is_writable($path)) + if (!phpbb_is_writable($path)) { @chmod($path, 0777); } @@ -2341,7 +2341,7 @@ function copy_dir($src, $trg, $copy_subdirs = true, $overwrite = false, $die_on_ @chmod($trg_path, 0777); } - if (!@is_writable($trg_path)) + if (!phpbb_is_writable($trg_path)) { $bad_dirs[] = path($config['script_path']) . $trg; } @@ -2408,7 +2408,7 @@ function copy_dir($src, $trg, $copy_subdirs = true, $overwrite = false, $die_on_ @chmod($trg_path . $dir, 0777); } - if (!@is_writable($trg_path . $dir)) + if (!phpbb_is_writable($trg_path . $dir)) { $bad_dirs[] = $trg . $dir; $bad_dirs[] = $trg_path . $dir; diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index f6f90575d4..6fd87db663 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -2537,7 +2537,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u if ($mode == 'post' || $mode == 'reply' || $mode == 'quote') { // Mark this topic as posted to - markread('post', $data['forum_id'], $data['topic_id'], $data['post_time']); + markread('post', $data['forum_id'], $data['topic_id']); } // Mark this topic as read @@ -2583,7 +2583,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u } // Send Notifications - if ($mode != 'edit' && $mode != 'delete' && $post_approval) + if (($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $post_approval) { user_notification($mode, $subject, $data['topic_title'], $data['forum_name'], $data['forum_id'], $data['topic_id'], $data['post_id']); } diff --git a/phpBB/includes/functions_privmsgs.php b/phpBB/includes/functions_privmsgs.php index c4cbb7ca1e..4c34bc92ca 100644 --- a/phpBB/includes/functions_privmsgs.php +++ b/phpBB/includes/functions_privmsgs.php @@ -1380,6 +1380,9 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true) } } + // First of all make sure the subject are having the correct length. + $subject = truncate_string($subject); + $db->sql_transaction('begin'); $sql = ''; diff --git a/phpBB/includes/functions_profile_fields.php b/phpBB/includes/functions_profile_fields.php index fa1cc98e10..3937cf9c21 100644 --- a/phpBB/includes/functions_profile_fields.php +++ b/phpBB/includes/functions_profile_fields.php @@ -543,8 +543,9 @@ class custom_profile else if ($day && $month && $year) { global $user; - // d/m/y 00:00 GMT isn't necessarily on the same d/m/y in the user's timezone, so add the timezone seconds - return $user->format_date(gmmktime(0, 0, 0, $month, $day, $year) + $user->timezone + $user->dst, $user->lang['DATE_FORMAT'], true); + // Date should display as the same date for every user regardless of timezone, so remove offset + // to compensate for the offset added by user::format_date() + return $user->format_date(gmmktime(0, 0, 0, $month, $day, $year) - ($user->timezone + $user->dst), $user->lang['DATE_FORMAT'], true); } return $value; diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index 51fed45ebd..7f09cc1640 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -58,8 +58,9 @@ class filespec $this->filename = $upload_ary['tmp_name']; $this->filesize = $upload_ary['size']; - $name = trim(utf8_htmlspecialchars(utf8_basename($upload_ary['name']))); - $this->realname = $this->uploadname = (STRIP) ? stripslashes($name) : $name; + $name = (STRIP) ? stripslashes($upload_ary['name']) : $upload_ary['name']; + $name = trim(utf8_htmlspecialchars(utf8_basename($name))); + $this->realname = $this->uploadname = $name; $this->mimetype = $upload_ary['type']; // Opera adds the name to the mime type diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php index 0b26f28864..f2c80705ba 100644 --- a/phpBB/includes/functions_user.php +++ b/phpBB/includes/functions_user.php @@ -766,7 +766,8 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas if (sizeof($ban_other) == 3 && ((int)$ban_other[0] < 9999) && (strlen($ban_other[0]) == 4) && (strlen($ban_other[1]) == 2) && (strlen($ban_other[2]) == 2)) { - $ban_end = max($current_time, gmmktime(0, 0, 0, (int)$ban_other[1], (int)$ban_other[2], (int)$ban_other[0])); + $time_offset = (isset($user->timezone) && isset($user->dst)) ? (int) $user->timezone + (int) $user->dst : 0; + $ban_end = max($current_time, gmmktime(0, 0, 0, (int)$ban_other[1], (int)$ban_other[2], (int)$ban_other[0]) - $time_offset); } else { @@ -1229,22 +1230,39 @@ function user_unban($mode, $ban) } /** -* Whois facility +* Internet Protocol Address Whois +* RFC3912: WHOIS Protocol Specification * -* @link http://tools.ietf.org/html/rfc3912 RFC3912: WHOIS Protocol Specification +* @param string $ip Ip address, either IPv4 or IPv6. +* +* @return string Empty string if not a valid ip address. +* Otherwise make_clickable()'ed whois result. */ function user_ipwhois($ip) { - $ipwhois = ''; + if (empty($ip)) + { + return ''; + } - // Check IP - // Only supporting IPv4 at the moment... - if (empty($ip) || !preg_match(get_preg_expression('ipv4'), $ip)) + if (preg_match(get_preg_expression('ipv4'), $ip)) + { + // IPv4 address + $whois_host = 'whois.arin.net.'; + } + else if (preg_match(get_preg_expression('ipv6'), $ip)) + { + // IPv6 address + $whois_host = 'whois.sixxs.net.'; + } + else { return ''; } - if (($fsk = @fsockopen('whois.arin.net', 43))) + $ipwhois = ''; + + if (($fsk = @fsockopen($whois_host, 43))) { // CRLF as per RFC3912 fputs($fsk, "$ip\r\n"); @@ -1257,7 +1275,7 @@ function user_ipwhois($ip) $match = array(); - // Test for referrals from ARIN to other whois databases, roll on rwhois + // Test for referrals from $whois_host to other whois databases, roll on rwhois if (preg_match('#ReferralServer: whois://(.+)#im', $ipwhois, $match)) { if (strpos($match[1], ':') !== false) @@ -1285,7 +1303,7 @@ function user_ipwhois($ip) @fclose($fsk); } - // Use the result from ARIN if we don't get any result here + // Use the result from $whois_host if we don't get any result here $ipwhois = (empty($buffer)) ? $ipwhois : $buffer; } @@ -2326,7 +2344,7 @@ function avatar_process_user(&$error, $custom_userdata = false, $can_upload = nu // Can we upload? if (is_null($can_upload)) { - $can_upload = ($config['allow_avatar_upload'] && file_exists($phpbb_root_path . $config['avatar_path']) && @is_writable($phpbb_root_path . $config['avatar_path']) && $change_avatar && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false; + $can_upload = ($config['allow_avatar_upload'] && file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $change_avatar && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false; } if ((!empty($_FILES['uploadfile']['name']) || $data['uploadurl']) && $can_upload) diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index 80c3559649..d5551f5114 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -1048,6 +1048,35 @@ function mcp_fork_topic($topic_ids) $total_posts = 0; $new_topic_id_list = array(); + if ($topic_data['enable_indexing']) + { + // Select the search method and do some additional checks to ensure it can actually be utilised + $search_type = basename($config['search_type']); + + if (!file_exists($phpbb_root_path . 'includes/search/' . $search_type . '.' . $phpEx)) + { + trigger_error('NO_SUCH_SEARCH_MODULE'); + } + + if (!class_exists($search_type)) + { + include("{$phpbb_root_path}includes/search/$search_type.$phpEx"); + } + + $error = false; + $search = new $search_type($error); + $search_mode = 'post'; + + if ($error) + { + trigger_error($error); + } + } + else + { + $search_type = false; + } + foreach ($topic_data as $topic_id => $topic_row) { $sql_ary = array( @@ -1158,6 +1187,12 @@ function mcp_fork_topic($topic_ids) // Copy whether the topic is dotted markread('post', $to_forum_id, $new_topic_id, 0, $row['poster_id']); + if ($search_type) + { + $search->index($search_mode, $sql_ary['post_id'], $sql_ary['post_text'], $sql_ary['post_subject'], $sql_ary['poster_id'], ($topic_row['topic_type'] == POST_GLOBAL) ? 0 : $to_forum_id); + $search_mode = 'reply'; // After one we index replies + } + // Copy Attachments if ($row['post_attachment']) { diff --git a/phpBB/includes/mcp/mcp_queue.php b/phpBB/includes/mcp/mcp_queue.php index e43881fab2..c419da5574 100644 --- a/phpBB/includes/mcp/mcp_queue.php +++ b/phpBB/includes/mcp/mcp_queue.php @@ -428,7 +428,7 @@ class mcp_queue 'POST_ID' => $row['post_id'], 'FORUM_NAME' => (!$global_topic) ? $forum_names[$row['forum_id']] : $user->lang['GLOBAL_ANNOUNCEMENT'], - 'POST_SUBJECT' => $row['post_subject'], + 'POST_SUBJECT' => ($row['post_subject'] != '') ? $row['post_subject'] : $user->lang['NO_SUBJECT'], 'TOPIC_TITLE' => $row['topic_title'], 'POST_TIME' => $user->format_date($row['post_time'])) ); diff --git a/phpBB/includes/search/fulltext_native.php b/phpBB/includes/search/fulltext_native.php index c89e92711e..727e3aaffb 100644 --- a/phpBB/includes/search/fulltext_native.php +++ b/phpBB/includes/search/fulltext_native.php @@ -83,7 +83,9 @@ class fulltext_native extends search_backend { global $db, $user, $config; - $keywords = trim($this->cleanup($keywords, '+-|()*')); + $tokens = '+-|()*'; + + $keywords = trim($this->cleanup($keywords, $tokens)); // allow word|word|word without brackets if ((strpos($keywords, ' ') === false) && (strpos($keywords, '|') !== false) && (strpos($keywords, '(') === false)) @@ -114,6 +116,15 @@ class fulltext_native extends search_backend case ' ': $keywords[$i] = '|'; break; + case '*': + if ($i === 0 || ($keywords[$i - 1] !== '*' && strcspn($keywords[$i - 1], $tokens) === 0)) + { + if ($i === $n - 1 || ($keywords[$i + 1] !== '*' && strcspn($keywords[$i + 1], $tokens) === 0)) + { + $keywords = substr($keywords, 0, $i) . substr($keywords, $i + 1); + } + } + break; } } else diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index e157053e61..5f5b39fe27 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -285,6 +285,17 @@ class session break; } + // Quick check for IPv4-mapped address in IPv6 + if (stripos($ip, '::ffff:') === 0) + { + $ipv4 = substr($ip, 7); + + if (preg_match(get_preg_expression('ipv4'), $ipv4)) + { + $ip = $ipv4; + } + } + // Use the last in chain $this->ip = $ip; } @@ -748,7 +759,7 @@ class session if ((int) $row['sessions'] > (int) $config['active_sessions']) { - header('HTTP/1.1 503 Service Unavailable'); + send_status_line(503, 'Service Unavailable'); trigger_error('BOARD_UNAVAILABLE'); } } @@ -1821,7 +1832,7 @@ class user extends session { if ($this->data['is_bot']) { - header('HTTP/1.1 503 Service Unavailable'); + send_status_line(503, 'Service Unavailable'); } $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE'; @@ -1831,7 +1842,7 @@ class user extends session // Is load exceeded? if ($config['limit_load'] && $this->load !== false) { - if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN')) + if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN') && !defined('IN_ADMIN')) { // Set board disabled to true to let the admins/mods get the proper notification $config['board_disable'] = '1'; @@ -1840,7 +1851,7 @@ class user extends session { if ($this->data['is_bot']) { - header('HTTP/1.1 503 Service Unavailable'); + send_status_line(503, 'Service Unavailable'); } trigger_error('BOARD_UNAVAILABLE'); } diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php index 423d9b718a..1c055a4823 100644 --- a/phpBB/includes/ucp/ucp_groups.php +++ b/phpBB/includes/ucp/ucp_groups.php @@ -490,7 +490,7 @@ class ucp_groups $avatar_select = basename(request_var('avatar_select', '')); $category = basename(request_var('category', '')); - $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && @is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false; + $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false; // Did we submit? if ($update) diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php index 26968e1382..16700c490c 100644 --- a/phpBB/includes/ucp/ucp_pm_viewmessage.php +++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php @@ -309,7 +309,7 @@ function get_user_information($user_id, $user_row) get_user_rank($user_row['user_rank'], $user_row['user_posts'], $user_row['rank_title'], $user_row['rank_image'], $user_row['rank_image_src']); - if (!empty($user_row['user_allow_viewemail']) || $auth->acl_get('a_email')) + if ((!empty($user_row['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_email')) { $user_row['email'] = ($config['board_email_form'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&u=$user_id") : ((($config['board_hide_emails'] && !$auth->acl_get('a_email')) || empty($user_row['user_email'])) ? '' : 'mailto:' . $user_row['user_email']); } diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index 363a4803b6..c099e3b3fa 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -141,10 +141,7 @@ class ucp_profile $server_url = generate_board_url(); - $user_actkey = gen_rand_string(10); - $key_len = 54 - (strlen($server_url)); - $key_len = ($key_len > 6) ? $key_len : 6; - $user_actkey = substr($user_actkey, 0, $key_len); + $user_actkey = gen_rand_string(mt_rand(6, 10)); $messenger = new messenger(false); @@ -564,7 +561,7 @@ class ucp_profile $avatar_select = basename(request_var('avatar_select', '')); $category = basename(request_var('category', '')); - $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && @is_writable($phpbb_root_path . $config['avatar_path']) && $auth->acl_get('u_chgavatar') && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false; + $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $auth->acl_get('u_chgavatar') && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false; add_form_key('ucp_avatar'); diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index 9656a4a3af..7fd99da55a 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -286,11 +286,7 @@ class ucp_register $config['require_activation'] == USER_ACTIVATION_SELF || $config['require_activation'] == USER_ACTIVATION_ADMIN) && $config['email_enable']) { - $user_actkey = gen_rand_string(10); - $key_len = 54 - (strlen($server_url)); - $key_len = ($key_len < 6) ? 6 : $key_len; - $user_actkey = substr($user_actkey, 0, $key_len); - + $user_actkey = gen_rand_string(mt_rand(6, 10)); $user_type = USER_INACTIVE; $user_inactive_reason = INACTIVE_REGISTER; $user_inactive_time = time(); diff --git a/phpBB/includes/ucp/ucp_remind.php b/phpBB/includes/ucp/ucp_remind.php index f9b792de20..cb89ad99be 100644 --- a/phpBB/includes/ucp/ucp_remind.php +++ b/phpBB/includes/ucp/ucp_remind.php @@ -79,10 +79,10 @@ class ucp_remind // Make password at least 8 characters long, make it longer if admin wants to. // gen_rand_string() however has a limit of 12 or 13. - $user_password = gen_rand_string(max(8, rand((int) $config['min_pass_chars'], (int) $config['max_pass_chars']))); + $user_password = gen_rand_string_friendly(max(8, mt_rand((int) $config['min_pass_chars'], (int) $config['max_pass_chars']))); // For the activation key a random length between 6 and 10 will do. - $user_actkey = gen_rand_string(rand(6, 10)); + $user_actkey = gen_rand_string(mt_rand(6, 10)); $sql = 'UPDATE ' . USERS_TABLE . " SET user_newpasswd = '" . $db->sql_escape(phpbb_hash($user_password)) . "', user_actkey = '" . $db->sql_escape($user_actkey) . "' diff --git a/phpBB/install/convertors/functions_phpbb20.php b/phpBB/install/convertors/functions_phpbb20.php index b80c7673e3..78224dd5da 100644 --- a/phpBB/install/convertors/functions_phpbb20.php +++ b/phpBB/install/convertors/functions_phpbb20.php @@ -1239,9 +1239,9 @@ function phpbb_prepare_message($message) // Already the new user id ;) $user_id = $convert->row['poster_id']; + $message = str_replace('<br />', "\n", $message); $message = str_replace('<', '<', $message); $message = str_replace('>', '>', $message); - $message = str_replace('<br />', "\n", $message); // make the post UTF-8 $message = phpbb_set_encoding($message); diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 83bbbf4577..ca4ef817be 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -119,6 +119,7 @@ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false); unset($dbpasswd); $user->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : ''; +$user->ip = (stripos($user->ip, '::ffff:') === 0) ? substr($user->ip, 7) : $user->ip; $sql = "SELECT config_value FROM " . CONFIG_TABLE . " @@ -880,7 +881,7 @@ function database_update_info() 'pm_id' => array('pm_id'), ), POSTS_TABLE => array( - 'post_username' => array('post_username'), + 'post_username' => array('post_username:255'), ), ), ), @@ -1749,6 +1750,55 @@ function change_database_data(&$no_updates, $version) _sql($sql, $errored, $error_ary); // end Bing Bot addition + // Delete shadow topics pointing to not existing topics + $batch_size = 500; + + // Set of affected forums we have to resync + $sync_forum_ids = array(); + + do + { + $sql_array = array( + 'SELECT' => 't1.topic_id, t1.forum_id', + 'FROM' => array( + TOPICS_TABLE => 't1', + ), + 'LEFT_JOIN' => array( + array( + 'FROM' => array(TOPICS_TABLE => 't2'), + 'ON' => 't1.topic_moved_id = t2.topic_id', + ), + ), + 'WHERE' => 't1.topic_moved_id <> 0 + AND t2.topic_id IS NULL', + ); + $sql = $db->sql_build_query('SELECT', $sql_array); + $result = $db->sql_query_limit($sql, $batch_size); + + $topic_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $topic_ids[] = (int) $row['topic_id']; + + $sync_forum_ids[(int) $row['forum_id']] = (int) $row['forum_id']; + } + $db->sql_freeresult($result); + + if (!empty($topic_ids)) + { + $sql = 'DELETE FROM ' . TOPICS_TABLE . ' + WHERE ' . $db->sql_in_set('topic_id', $topic_ids); + $db->sql_query($sql); + } + } + while (sizeof($topic_ids) == $batch_size); + + // Sync the forums we have deleted shadow topics from. + sync('forum', 'forum_id', $sync_forum_ids, true, true); + + // Unread posts search load switch + set_config('load_unreads_search', '1'); + $no_updates = false; break; } @@ -2095,7 +2145,7 @@ class updater_db_tools * drop_columns: Removing/Dropping columns * add_primary_keys: adding primary keys * add_unique_index: adding an unique index - * add_index: adding an index + * add_index: adding an index (can be column:index_size if you need to provide size) * * The values are in this format: * {TABLE NAME} => array( @@ -3474,6 +3524,12 @@ class updater_db_tools { $statements = array(); + // remove index length unless MySQL4 + if ('mysql_40' != $this->sql_layer) + { + $column = preg_replace('#:.*$#', '', $column); + } + switch ($this->sql_layer) { case 'firebird': @@ -3484,6 +3540,16 @@ class updater_db_tools break; case 'mysql_40': + // add index size to definition as required by MySQL4 + foreach ($column as $i => $col) + { + if (false !== strpos($col, ':')) + { + list($col, $index_size) = explode(':', $col); + $column[$i] = "$col($index_size)"; + } + } + // no break case 'mysql_41': $statements[] = 'CREATE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')'; break; diff --git a/phpBB/install/install_convert.php b/phpBB/install/install_convert.php index 8c3ffd61a8..814b50cf68 100644 --- a/phpBB/install/install_convert.php +++ b/phpBB/install/install_convert.php @@ -835,7 +835,7 @@ class install_convert extends module $this->p_master->error($user->lang['DEV_NO_TEST_FILE'], __LINE__, __FILE__); } - if (!$local_path || !@is_writable($phpbb_root_path . $local_path)) + if (!$local_path || !phpbb_is_writable($phpbb_root_path . $local_path)) { if (!$local_path) { diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php index 4c22db07b2..2dd58584f4 100644 --- a/phpBB/install/install_install.php +++ b/phpBB/install/install_install.php @@ -486,7 +486,7 @@ class install_install extends module $write = $exists = true; if (file_exists($phpbb_root_path . $dir)) { - if (!@is_writable($phpbb_root_path . $dir)) + if (!phpbb_is_writable($phpbb_root_path . $dir)) { $write = false; } @@ -906,7 +906,7 @@ class install_install extends module $config_data .= '?' . '>'; // Done this to prevent highlighting editors getting confused! // 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) && is_writable($phpbb_root_path . 'config.' . $phpEx)) || is_writable($phpbb_root_path)) + if ((file_exists($phpbb_root_path . 'config.' . $phpEx) && phpbb_is_writable($phpbb_root_path . 'config.' . $phpEx)) || phpbb_is_writable($phpbb_root_path)) { // Assume it will work ... if nothing goes wrong below $written = true; @@ -1236,6 +1236,7 @@ class install_install extends module $current_time = time(); $user_ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : ''; + $user_ip = (stripos($user_ip, '::ffff:') === 0) ? substr($user_ip, 7) : $user_ip; if ($data['script_path'] !== '/') { diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index e815615eef..a25b68ba39 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -168,6 +168,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_online_time', INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_onlinetrack', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_search', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_tplcompile', '0'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_unreads_search', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_user_activity', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_attachments', '3'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_attachments_pm', '1'); diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php index 8b12a926b0..77deba6e19 100644 --- a/phpBB/language/en/acp/board.php +++ b/phpBB/language/en/acp/board.php @@ -177,8 +177,8 @@ $lang = array_merge($lang, array( 'MIN_CHAR_LIMIT_EXPLAIN' => 'The minimum number of characters the user need to enter within a post/private message.', 'POSTING' => 'Posting', 'POSTS_PER_PAGE' => 'Posts per page', - 'QUOTE_DEPTH_LIMIT' => 'Maximum nested quotes per post', - 'QUOTE_DEPTH_LIMIT_EXPLAIN' => 'Maximum number of nested quotes in a post. Set to 0 for unlimited depth.', + 'QUOTE_DEPTH_LIMIT' => 'Maximum nesting depth for quotes', + 'QUOTE_DEPTH_LIMIT_EXPLAIN' => 'Maximum quote nesting depth in a post. Set to 0 for unlimited depth.', 'SMILIES_LIMIT' => 'Maximum smilies per post', 'SMILIES_LIMIT_EXPLAIN' => 'Maximum number of smilies in a post. Set to 0 for unlimited smilies.', 'SMILIES_PER_PAGE' => 'Smilies per page', @@ -375,6 +375,7 @@ $lang = array_merge($lang, array( 'YES_POST_MARKING_EXPLAIN' => 'Indicates whether user has posted to a topic.', 'YES_READ_MARKING' => 'Enable server-side topic marking', 'YES_READ_MARKING_EXPLAIN' => 'Stores read/unread status information in the database rather than a cookie.', + 'YES_UNREAD_SEARCH' => 'Enable search for unread posts', )); // Auth settings diff --git a/phpBB/language/en/search.php b/phpBB/language/en/search.php index be92391a4e..d93fe6b56a 100644 --- a/phpBB/language/en/search.php +++ b/phpBB/language/en/search.php @@ -62,6 +62,7 @@ $lang = array_merge($lang, array( 'NO_SEARCH' => 'Sorry but you are not permitted to use the search system.', 'NO_SEARCH_RESULTS' => 'No suitable matches were found.', 'NO_SEARCH_TIME' => 'Sorry but you cannot use search at this time. Please try again in a few minutes.', + 'NO_SEARCH_UNREADS' => 'Sorry but searching for unread posts has been disabled on this board.', 'WORD_IN_NO_POST' => 'No posts were found because the word <strong>%s</strong> is not contained in any post.', 'WORDS_IN_NO_POST' => 'No posts were found because the words <strong>%s</strong> are not contained in any post.', diff --git a/phpBB/memberlist.php b/phpBB/memberlist.php index b46230b10a..2fa2d11ee1 100644 --- a/phpBB/memberlist.php +++ b/phpBB/memberlist.php @@ -1607,7 +1607,7 @@ function show_profile($data, $user_notes_enabled = false, $warn_user_enabled = f $rank_title = $rank_img = $rank_img_src = ''; get_user_rank($data['user_rank'], (($user_id == ANONYMOUS) ? false : $data['user_posts']), $rank_title, $rank_img, $rank_img_src); - if (!empty($data['user_allow_viewemail']) || $auth->acl_get('a_user')) + if ((!empty($data['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_user')) { $email = ($config['board_email_form'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=email&u=' . $user_id) : (($config['board_hide_emails'] && !$auth->acl_get('a_user')) ? '' : 'mailto:' . $data['user_email']); } diff --git a/phpBB/posting.php b/phpBB/posting.php index df063ef391..f775699cee 100644 --- a/phpBB/posting.php +++ b/phpBB/posting.php @@ -402,6 +402,19 @@ if ($post_data['poll_start']) $db->sql_freeresult($result); } +if ($mode == 'edit') +{ + $original_poll_data = array( + 'poll_title' => $post_data['poll_title'], + 'poll_length' => $post_data['poll_length'], + 'poll_max_options' => $post_data['poll_max_options'], + 'poll_option_text' => implode("\n", $post_data['poll_options']), + 'poll_start' => $post_data['poll_start'], + 'poll_last_vote' => $post_data['poll_last_vote'], + 'poll_vote_change' => $post_data['poll_vote_change'], + ); +} + $orig_poll_options_size = sizeof($post_data['poll_options']); $message_parser = new parse_message(); @@ -912,6 +925,22 @@ if ($submit || $preview || $refresh) $message_parser->warn_msg[] = $user->lang['NO_DELETE_POLL_OPTIONS']; }*/ } + else if (!$auth->acl_get('f_poll', $forum_id) && ($mode == 'edit') && ($post_id == $post_data['topic_first_post_id']) && ($original_poll_data['poll_title'] != '')) + { + // We have a poll but the editing user is not permitted to create/edit it. + // So we just keep the original poll-data. + $poll = array_merge($original_poll_data, array( + 'enable_bbcode' => $post_data['enable_bbcode'], + 'enable_urls' => $post_data['enable_urls'], + 'enable_smilies' => $post_data['enable_smilies'], + 'img_status' => $img_status, + )); + + $message_parser->parse_poll($poll); + + $post_data['poll_options'] = (isset($poll['poll_options'])) ? $poll['poll_options'] : ''; + $post_data['poll_title'] = (isset($poll['poll_title'])) ? $poll['poll_title'] : ''; + } else { $poll = array(); @@ -1271,7 +1300,7 @@ $attachment_data = $message_parser->attachment_data; $filename_data = $message_parser->filename_data; $post_data['post_text'] = $message_parser->message; -if (sizeof($post_data['poll_options']) && $post_data['poll_title']) +if (sizeof($post_data['poll_options']) || !empty($post_data['poll_title'])) { $message_parser->message = $post_data['poll_title']; $message_parser->bbcode_uid = $post_data['bbcode_uid']; diff --git a/phpBB/search.php b/phpBB/search.php index 1e1e42d01f..2a13e20477 100644 --- a/phpBB/search.php +++ b/phpBB/search.php @@ -61,10 +61,18 @@ if ($search_id == 'egosearch') } } -// Search for unread posts needs user to be logged in if topics tracking for guests is disabled -if ($search_id == 'unreadposts' && !$config['load_anon_lastread'] && !$user->data['is_registered']) +// Search for unread posts needs to be allowed and user to be logged in if topics tracking for guests is disabled +if ($search_id == 'unreadposts') { - login_box('', $user->lang['LOGIN_EXPLAIN_UNREADSEARCH']); + if (!$config['load_unreads_search']) + { + $template->assign_var('S_NO_SEARCH', true); + trigger_error('NO_SEARCH_UNREADS'); + } + else if (!$config['load_anon_lastread'] && !$user->data['is_registered']) + { + login_box('', $user->lang['LOGIN_EXPLAIN_UNREADSEARCH']); + } } // Is user able to search? Has search been disabled? @@ -81,9 +89,10 @@ if ($user->load && $config['limit_search_load'] && ($user->load > doubleval($con trigger_error('NO_SEARCH_TIME'); } -// Check flood limit ... if applicable +// It is applicable if the configuration setting is non-zero, and the user cannot +// ignore the flood setting, and the search is a keyword search. $interval = ($user->data['user_id'] == ANONYMOUS) ? $config['search_anonymous_interval'] : $config['search_interval']; -if ($interval && !$auth->acl_get('u_ignoreflood')) +if ($interval && !in_array($search_id, array('unreadposts', 'unanswered', 'active_topics', 'egosearch')) && !$auth->acl_get('u_ignoreflood')) { if ($user->data['user_last_search'] > time() - $interval) { @@ -891,7 +900,7 @@ if ($keywords || $author || $author_id || $search_id || $submit) 'S_TOPIC_GLOBAL' => (!$forum_id) ? true : false, 'S_TOPIC_TYPE' => $row['topic_type'], - 'S_USER_POSTED' => (!empty($row['mark_type'])) ? true : false, + 'S_USER_POSTED' => (!empty($row['topic_posted'])) ? true : false, 'S_UNREAD_TOPIC' => $unread_topic, 'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && $auth->acl_get('m_report', $forum_id)) ? true : false, diff --git a/phpBB/styles/prosilver/template/index_body.html b/phpBB/styles/prosilver/template/index_body.html index 17790eb78a..af2077141c 100644 --- a/phpBB/styles/prosilver/template/index_body.html +++ b/phpBB/styles/prosilver/template/index_body.html @@ -6,7 +6,7 @@ <!-- IF S_DISPLAY_SEARCH or (S_USER_LOGGED_IN and not S_IS_BOT) --> <ul class="linklist"> <!-- IF S_DISPLAY_SEARCH --> - <li><a href="{U_SEARCH_UNANSWERED}">{L_SEARCH_UNANSWERED}</a><!-- IF S_USER_LOGGED_IN --> • <a href="{U_SEARCH_UNREAD}">{L_SEARCH_UNREAD}</a> • <a href="{U_SEARCH_NEW}">{L_SEARCH_NEW}</a><!-- ENDIF --> • <a href="{U_SEARCH_ACTIVE_TOPICS}">{L_SEARCH_ACTIVE_TOPICS}</a></li> + <li><a href="{U_SEARCH_UNANSWERED}">{L_SEARCH_UNANSWERED}</a><!-- IF S_USER_LOGGED_IN --><!-- IF S_LOAD_UNREADS --> • <a href="{U_SEARCH_UNREAD}">{L_SEARCH_UNREAD}</a><!-- ENDIF --> • <a href="{U_SEARCH_NEW}">{L_SEARCH_NEW}</a><!-- ENDIF --> • <a href="{U_SEARCH_ACTIVE_TOPICS}">{L_SEARCH_ACTIVE_TOPICS}</a></li> <!-- ENDIF --> <!-- IF not S_IS_BOT and U_MARK_FORUMS --><li class="rightside"><a href="{U_MARK_FORUMS}" accesskey="m">{L_MARK_FORUMS_READ}</a></li><!-- ENDIF --> </ul> diff --git a/phpBB/styles/prosilver/template/login_body.html b/phpBB/styles/prosilver/template/login_body.html index fe111aaa45..e52ccd6434 100644 --- a/phpBB/styles/prosilver/template/login_body.html +++ b/phpBB/styles/prosilver/template/login_body.html @@ -32,11 +32,11 @@ </dl> <!-- ENDIF --> + {S_LOGIN_REDIRECT} <dl> <dt> </dt> <dd>{S_HIDDEN_FIELDS}<input type="submit" name="login" tabindex="6" value="{L_LOGIN}" class="button1" /></dd> </dl> - {S_LOGIN_REDIRECT} </fieldset> </div> <span class="corners-bottom"><span></span></span></div> diff --git a/phpBB/styles/prosilver/theme/bidi.css b/phpBB/styles/prosilver/theme/bidi.css index 109312ac1b..f441784d85 100644 --- a/phpBB/styles/prosilver/theme/bidi.css +++ b/phpBB/styles/prosilver/theme/bidi.css @@ -236,6 +236,7 @@ } .rtl a.top2 { + background-position: 100% 50%; padding-left: 0; padding-right: 15px; } diff --git a/phpBB/styles/prosilver/theme/print.css b/phpBB/styles/prosilver/theme/print.css index 6dfb5c4726..68600b030b 100644 --- a/phpBB/styles/prosilver/theme/print.css +++ b/phpBB/styles/prosilver/theme/print.css @@ -140,3 +140,5 @@ div.spacer { clear: both; } /* Accessibility tweaks: Mozilla.org */ .skip_link { display: none; } + +dl.codebox dt { display: none; }
\ No newline at end of file diff --git a/phpBB/styles/subsilver2/template/login_body.html b/phpBB/styles/subsilver2/template/login_body.html index 51f7068b5f..503de9e69e 100644 --- a/phpBB/styles/subsilver2/template/login_body.html +++ b/phpBB/styles/subsilver2/template/login_body.html @@ -72,12 +72,12 @@ <!-- INCLUDE {CAPTCHA_TEMPLATE} --> <!-- ENDIF --> +{S_LOGIN_REDIRECT} <tr> <td class="cat" <!-- IF not S_ADMIN_AUTH or S_CONFIRM_CODE -->colspan="2"<!-- ENDIF --> align="center">{S_HIDDEN_FIELDS}<input type="submit" name="login" class="btnmain" value="{L_LOGIN}" tabindex="5" /></td> </tr> </table> {S_FORM_TOKEN} -{S_LOGIN_REDIRECT} </form> <br clear="all" /> diff --git a/phpBB/styles/subsilver2/template/overall_header.html b/phpBB/styles/subsilver2/template/overall_header.html index 963f5160dd..37691d4f1c 100644 --- a/phpBB/styles/subsilver2/template/overall_header.html +++ b/phpBB/styles/subsilver2/template/overall_header.html @@ -202,7 +202,7 @@ function marklist(id, name, state) <p class="searchbar"> <span style="float: {S_CONTENT_FLOW_BEGIN};"><a href="{U_SEARCH_UNANSWERED}">{L_SEARCH_UNANSWERED}</a> | <a href="{U_SEARCH_ACTIVE_TOPICS}">{L_SEARCH_ACTIVE_TOPICS}</a></span> <!-- IF S_USER_LOGGED_IN --> - <span style="float: {S_CONTENT_FLOW_END};"><a href="{U_SEARCH_UNREAD}">{L_SEARCH_UNREAD}</a> | <a href="{U_SEARCH_NEW}">{L_SEARCH_NEW}</a> | <a href="{U_SEARCH_SELF}">{L_SEARCH_SELF}</a></span> + <span style="float: {S_CONTENT_FLOW_END};"><!-- IF S_LOAD_UNREADS --><a href="{U_SEARCH_UNREAD}">{L_SEARCH_UNREAD}</a> | <!-- ENDIF --><a href="{U_SEARCH_NEW}">{L_SEARCH_NEW}</a> | <a href="{U_SEARCH_SELF}">{L_SEARCH_SELF}</a></span> <!-- ENDIF --> </p> <!-- ENDIF --> diff --git a/phpBB/ucp.php b/phpBB/ucp.php index 994fe064a1..f5a2ec9648 100644 --- a/phpBB/ucp.php +++ b/phpBB/ucp.php @@ -22,7 +22,7 @@ require($phpbb_root_path . 'includes/functions_module.' . $phpEx); $id = request_var('i', ''); $mode = request_var('mode', ''); -if ($mode == 'login' || $mode == 'logout' || $mode == 'confirm') +if (in_array($mode, array('login', 'logout', 'confirm', 'sendpassword', 'activate'))) { define('IN_LOGIN', true); } diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php index 8926d5a40b..498088c5c8 100644 --- a/phpBB/viewtopic.php +++ b/phpBB/viewtopic.php @@ -1146,7 +1146,7 @@ while ($row = $db->sql_fetchrow($result)) get_user_rank($row['user_rank'], $row['user_posts'], $user_cache[$poster_id]['rank_title'], $user_cache[$poster_id]['rank_image'], $user_cache[$poster_id]['rank_image_src']); - if (!empty($row['user_allow_viewemail']) || $auth->acl_get('a_email')) + if ((!empty($row['user_allow_viewemail']) && $auth->acl_get('u_sendemail')) || $auth->acl_get('a_email')) { $user_cache[$poster_id]['email'] = ($config['board_email_form'] && $config['email_enable']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=email&u=$poster_id") : (($config['board_hide_emails'] && !$auth->acl_get('a_email')) ? '' : 'mailto:' . $row['user_email']); } diff --git a/tests/all_tests.php b/tests/all_tests.php index 7894d688ee..bae7725ee7 100644 --- a/tests/all_tests.php +++ b/tests/all_tests.php @@ -24,6 +24,8 @@ require_once 'template/all_tests.php'; require_once 'text_processing/all_tests.php'; require_once 'dbal/all_tests.php'; require_once 'regex/all_tests.php'; +require_once 'network/all_tests.php'; +require_once 'random/all_tests.php'; // exclude the test directory from code coverage reports PHPUnit_Util_Filter::addDirectoryToFilter('./'); @@ -46,6 +48,8 @@ class phpbb_all_tests $suite->addTest(phpbb_text_processing_all_tests::suite()); $suite->addTest(phpbb_dbal_all_tests::suite()); $suite->addTest(phpbb_regex_all_tests::suite()); + $suite->addTest(phpbb_network_all_tests::suite()); + $suite->addTest(phpbb_random_all_tests::suite()); return $suite; } diff --git a/tests/dbal/dbal.php b/tests/dbal/dbal.php index 1cce891ca9..663323ad61 100644 --- a/tests/dbal/dbal.php +++ b/tests/dbal/dbal.php @@ -244,8 +244,9 @@ class phpbb_dbal_test extends phpbb_database_test_case array('username_clean' => 'bertie'))), // These here would throw errors and therefor $result should be false. - array('user_id', array(), false, false, false, true), - array('user_id', array(), true, false, false, true), + // Removing for now because SQLite accepts empty IN() syntax + /*array('user_id', array(), false, false, false, true), + array('user_id', array(), true, false, false, true),*/ ); } diff --git a/tests/network/all_tests.php b/tests/network/all_tests.php new file mode 100644 index 0000000000..b500647f81 --- /dev/null +++ b/tests/network/all_tests.php @@ -0,0 +1,40 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2010 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +if (!defined('PHPUnit_MAIN_METHOD')) +{ + define('PHPUnit_MAIN_METHOD', 'phpbb_network_all_tests::main'); +} + +require_once 'test_framework/framework.php'; +require_once 'PHPUnit/TextUI/TestRunner.php'; + +require_once 'network/checkdnsrr.php'; + +class phpbb_network_all_tests +{ + public static function main() + { + PHPUnit_TextUI_TestRunner::run(self::suite()); + } + + public static function suite() + { + $suite = new PHPUnit_Framework_TestSuite('phpBB Network Functions'); + + $suite->addTestSuite('phpbb_network_checkdnsrr_test'); + + return $suite; + } +} + +if (PHPUnit_MAIN_METHOD == 'phpbb_network_all_tests::main') +{ + phpbb_network_all_tests::main(); +} diff --git a/tests/network/checkdnsrr.php b/tests/network/checkdnsrr.php new file mode 100644 index 0000000000..57fe2761cc --- /dev/null +++ b/tests/network/checkdnsrr.php @@ -0,0 +1,63 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2010 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +require_once 'test_framework/framework.php'; +require_once '../phpBB/includes/functions.php'; + +class phpbb_network_checkdnsrr_test extends phpbb_test_case +{ + public function data_provider() + { + return array( + // Existing MX record + array('phpbb.com', 'MX', true), + + // Non-existing MX record + array('does-not-exist.phpbb.com', 'MX', false), + + // Existing A record + array('www.phpbb.com', 'A', true), + + // Non-existing A record + array('does-not-exist.phpbb.com', 'A', false), + + // Existing AAAA record + array('www.six.heise.de', 'AAAA', true), + + // Non-existing AAAA record + array('does-not-exist.phpbb.com', 'AAAA', false), + + // Existing CNAME record + array('news.cnet.com', 'CNAME', true), + + // Non-existing CNAME record + array('does-not-exist.phpbb.com', 'CNAME', false), + + // Existing NS record + array('phpbb.com', 'NS', true), + + // Non-existing NS record + array('does-not-exist', 'NS', false), + + // Existing TXT record + array('phpbb.com', 'TXT', true), + + // Non-existing TXT record + array('does-not-exist', 'TXT', false), + ); + } + + /** + * @dataProvider data_provider + */ + public function test_checkdnsrr($host, $type, $expected) + { + $this->assertEquals($expected, phpbb_checkdnsrr($host, $type)); + } +} diff --git a/tests/random/all_tests.php b/tests/random/all_tests.php new file mode 100644 index 0000000000..c6ffe78024 --- /dev/null +++ b/tests/random/all_tests.php @@ -0,0 +1,40 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2010 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +if (!defined('PHPUnit_MAIN_METHOD')) +{ + define('PHPUnit_MAIN_METHOD', 'phpbb_random_all_tests::main'); +} + +require_once 'test_framework/framework.php'; +require_once 'PHPUnit/TextUI/TestRunner.php'; + +require_once 'random/gen_rand_string.php'; + +class phpbb_random_all_tests +{ + public static function main() + { + PHPUnit_TextUI_TestRunner::run(self::suite()); + } + + public static function suite() + { + $suite = new PHPUnit_Framework_TestSuite('phpBB Random Functions'); + + $suite->addTestSuite('phpbb_random_gen_rand_string_test'); + + return $suite; + } +} + +if (PHPUnit_MAIN_METHOD == 'phpbb_random_all_tests::main') +{ + phpbb_random_all_tests::main(); +} diff --git a/tests/random/gen_rand_string.php b/tests/random/gen_rand_string.php new file mode 100644 index 0000000000..cd58d14ed3 --- /dev/null +++ b/tests/random/gen_rand_string.php @@ -0,0 +1,63 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2010 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +require_once 'test_framework/framework.php'; +require_once '../phpBB/includes/functions.php'; + +class phpbb_random_gen_rand_string_test extends phpbb_test_case +{ + const TEST_COUNT = 100; + const MIN_STRING_LENGTH = 1; + const MAX_STRING_LENGTH = 15; + + public function setUp() + { + global $config; + + if (!is_array($config)) + { + $config = array(); + } + + $config['rand_seed'] = ''; + $config['rand_seed_last_update'] = time() + 600; + } + + public function test_gen_rand_string() + { + for ($tests = 0; $tests <= self::TEST_COUNT; ++$tests) + { + for ($num_chars = self::MIN_STRING_LENGTH; $num_chars <= self::MAX_STRING_LENGTH; ++$num_chars) + { + $random_string = gen_rand_string($num_chars); + $random_string_length = strlen($random_string); + + $this->assertTrue($random_string_length >= self::MIN_STRING_LENGTH); + $this->assertTrue($random_string_length <= $num_chars); + $this->assertRegExp('#^[A-Z0-9]+$#', $random_string); + } + } + } + + public function test_gen_rand_string_friendly() + { + for ($tests = 0; $tests <= self::TEST_COUNT; ++$tests) + { + for ($num_chars = self::MIN_STRING_LENGTH; $num_chars <= self::MAX_STRING_LENGTH; ++$num_chars) + { + $random_string = gen_rand_string_friendly($num_chars); + $random_string_length = strlen($random_string); + + $this->assertTrue($random_string_length >= self::MIN_STRING_LENGTH); + $this->assertTrue($random_string_length <= $num_chars); + $this->assertRegExp('#^[A-NP-Z1-9]+$#', $random_string); + } + } + } +} diff --git a/tests/test_framework/phpbb_database_test_case.php b/tests/test_framework/phpbb_database_test_case.php index d558874c6f..f6bf420ebc 100644 --- a/tests/test_framework/phpbb_database_test_case.php +++ b/tests/test_framework/phpbb_database_test_case.php @@ -19,7 +19,7 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test } } - function get_dbms_data($dbms) + public function get_dbms_data($dbms) { $available_dbms = array( 'firebird' => array( @@ -65,7 +65,7 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test 'sqlite' => array( 'SCHEMA' => 'sqlite', 'DELIM' => ';', - 'PDO' => 'sqlite', + 'PDO' => 'sqlite2', ), ); @@ -79,10 +79,13 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test } } - function split_sql_file($sql, $delimiter) + // NOTE: This function is not the same as split_sql_file from functions_install + public function split_sql_file($sql, $dbms) { + $dbms_data = $this->get_dbms_data($dbms); + $sql = str_replace("\r" , '', $sql); - $data = preg_split('/' . preg_quote($delimiter, '/') . '$/m', $sql); + $data = preg_split('/' . preg_quote($dbms_data['DELIM'], '/') . '$/m', $sql); $data = array_map('trim', $data); @@ -94,6 +97,15 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test unset($data[key($data)]); } + if ($dbms == 'sqlite') + { + // trim # off query to satisfy sqlite + foreach ($data as $i => $query) + { + $data[$i] = preg_replace('/^#.*$/m', "\n", $query); + } + } + return $data; } @@ -108,21 +120,42 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test if ($already_connected) { - $pdo = new PDO($dbms_data['PDO'] . ':host=' . $database_config['dbhost'] . ';dbname=' . $database_config['dbname'], $database_config['dbuser'], $database_config['dbpasswd']); + if ($database_config['dbms'] == 'sqlite') + { + $pdo = new PDO($dbms_data['PDO'] . ':' . $database_config['dbhost']); + } + else + { + $pdo = new PDO($dbms_data['PDO'] . ':host=' . $database_config['dbhost'] . ';dbname=' . $database_config['dbname'], $database_config['dbuser'], $database_config['dbpasswd']); + } } else { - $pdo = new PDO($dbms_data['PDO'] . ':host=' . $database_config['dbhost'] . ';', $database_config['dbuser'], $database_config['dbpasswd']); - - try + if ($database_config['dbms'] == 'sqlite') { - $pdo->exec('DROP DATABASE ' . $database_config['dbname']); + // delete existing database + if (file_exists($database_config['dbhost'])) + { + unlink($database_config['dbhost']); + } + + $pdo = new PDO($dbms_data['PDO'] . ':' . $database_config['dbhost']); } - catch (PDOException $e){} // ignore non existent db + else + { + $pdo = new PDO($dbms_data['PDO'] . ':host=' . $database_config['dbhost'] . ';', $database_config['dbuser'], $database_config['dbpasswd']);try + { + $pdo->exec('DROP DATABASE ' . $database_config['dbname']); + } + catch (PDOException $e){} // ignore non existent db - $pdo->exec('CREATE DATABASE ' . $database_config['dbname']); + $pdo->exec('CREATE DATABASE ' . $database_config['dbname']); + + $pdo = new PDO($dbms_data['PDO'] . ':host=' . $database_config['dbhost'] . ';dbname=' . $database_config['dbname'], $database_config['dbuser'], $database_config['dbpasswd']); + } - $pdo = new PDO($dbms_data['PDO'] . ':host=' . $database_config['dbhost'] . ';dbname=' . $database_config['dbname'], $database_config['dbuser'], $database_config['dbpasswd']); + // good for debug + // $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); if ($database_config['dbms'] == 'mysql') { @@ -141,7 +174,7 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test unset($row, $sth); } - $sql_query = $this->split_sql_file(file_get_contents("../phpBB/install/schemas/{$dbms_data['SCHEMA']}_schema.sql"), $dbms_data['DELIM']); + $sql_query = $this->split_sql_file(file_get_contents("../phpBB/install/schemas/{$dbms_data['SCHEMA']}_schema.sql"), $database_config['dbms']); foreach ($sql_query as $sql) { diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index 0c5932e1ad..7c026e496e 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -22,7 +22,32 @@ class phpbb_test_case_helpers { static $show_error = true; - if (!file_exists('test_config.php')) + if (file_exists('test_config.php')) + { + include('test_config.php'); + + return array( + 'dbms' => $dbms, + 'dbhost' => $dbhost, + 'dbport' => $dbport, + 'dbname' => $dbname, + 'dbuser' => $dbuser, + 'dbpasswd' => $dbpasswd, + ); + } + else if (extension_loaded('sqlite') && version_compare(PHPUnit_Runner_Version::id(), '3.4.15', '>=')) + { + // Silently use sqlite + return array( + 'dbms' => 'sqlite', + 'dbhost' => 'phpbb_unit_tests.sqlite2', // filename + 'dbport' => '', + 'dbname' => '', + 'dbuser' => '', + 'dbpasswd' => '', + ); + } + else { if ($show_error) { @@ -46,16 +71,6 @@ class phpbb_test_case_helpers NOTE: The database is dropped and recreated with the phpbb-db-schema! Do NOT specify a database with important data.", E_USER_ERROR); } - include('test_config.php'); - - return array( - 'dbms' => $dbms, - 'dbhost' => $dbhost, - 'dbport' => $dbport, - 'dbname' => $dbname, - 'dbuser' => $dbuser, - 'dbpasswd' => $dbpasswd, - ); } public function new_dbal() |