diff options
Diffstat (limited to 'phpBB')
-rw-r--r-- | phpBB/download/file.php | 4 | ||||
-rw-r--r-- | phpBB/includes/acp/acp_database.php | 54 | ||||
-rw-r--r-- | phpBB/includes/acp/acp_groups.php | 9 | ||||
-rw-r--r-- | phpBB/includes/db/mssqlnative.php | 20 | ||||
-rw-r--r-- | phpBB/includes/functions_download.php | 168 | ||||
-rw-r--r-- | phpBB/includes/functions_messenger.php | 87 | ||||
-rw-r--r-- | phpBB/includes/search/fulltext_mysql.php | 8 | ||||
-rw-r--r-- | phpBB/language/en/acp/search.php | 2 | ||||
-rw-r--r-- | phpBB/language/en/captcha_recaptcha.php | 2 | ||||
-rw-r--r-- | phpBB/language/en/common.php | 6 | ||||
-rw-r--r-- | phpBB/styles/prosilver/template/captcha_recaptcha.html | 1 | ||||
-rw-r--r-- | phpBB/styles/subsilver2/template/captcha_recaptcha.html | 1 |
12 files changed, 312 insertions, 50 deletions
diff --git a/phpBB/download/file.php b/phpBB/download/file.php index 891352f00c..68a4afe03c 100644 --- a/phpBB/download/file.php +++ b/phpBB/download/file.php @@ -246,7 +246,7 @@ if (!download_allowed()) $download_mode = (int) $extensions[$attachment['extension']]['download_mode']; // Fetching filename here to prevent sniffing of filename -$sql = 'SELECT attach_id, is_orphan, in_message, post_msg_id, extension, physical_filename, real_filename, mimetype, filetime +$sql = 'SELECT attach_id, is_orphan, in_message, post_msg_id, extension, physical_filename, real_filename, mimetype, filesize, filetime FROM ' . ATTACHMENTS_TABLE . " WHERE attach_id = $download_id"; $result = $db->sql_query_limit($sql, 1); @@ -275,7 +275,7 @@ if ($thumbnail) { $attachment['physical_filename'] = 'thumb_' . $attachment['physical_filename']; } -else if (($display_cat == ATTACHMENT_CATEGORY_NONE/* || $display_cat == ATTACHMENT_CATEGORY_IMAGE*/) && !$attachment['is_orphan']) +else if (($display_cat == ATTACHMENT_CATEGORY_NONE/* || $display_cat == ATTACHMENT_CATEGORY_IMAGE*/) && !$attachment['is_orphan'] && !phpbb_http_byte_range($attachment['filesize'])) { // Update download count $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php index 0582d6204e..193dd001c0 100644 --- a/phpBB/includes/acp/acp_database.php +++ b/phpBB/includes/acp/acp_database.php @@ -1619,41 +1619,48 @@ class mssql_extractor extends base_extractor function write_data_mssqlnative($table_name) { global $db; - $ary_type = $ary_name = $meta_array = array(); + $ary_type = $ary_name = array(); $ident_set = false; $sql_data = ''; // Grab all of the data from current table. $sql = "SELECT * FROM $table_name"; + $db->mssqlnative_set_query_options(array('Scrollable' => SQLSRV_CURSOR_STATIC)); $result = $db->sql_query($sql); - $retrieved_data = $db->mssqlnative_num_rows($result); + $retrieved_data = $db->mssqlnative_num_rows($result); - $meta_array = sqlsrv_field_metadata($result); - $i_num_fields = sqlsrv_num_fields($result); - + if (!$retrieved_data) + { + $db->sql_freeresult($result); + return; + } + + $sql = "SELECT * FROM $table_name"; + $result_fields = $db->sql_query_limit($sql, 1); + + $row = new result_mssqlnative($result_fields); + $i_num_fields = $row->num_fields(); + for ($i = 0; $i < $i_num_fields; $i++) { - $info = $db->mssqlnative_fieldInfo($table_name, $meta_array[$i]['Name']); - $ary_type[$i] = $info->type(); - $ary_name[$i] = $info->name(); + $ary_type[$i] = $row->field_type($i); + $ary_name[$i] = $row->field_name($i); } + $db->sql_freeresult($result_fields); + + $sql = "SELECT 1 as has_identity + FROM INFORMATION_SCHEMA.COLUMNS + WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1"; + $result2 = $db->sql_query($sql); + $row2 = $db->sql_fetchrow($result2); - if ($retrieved_data) + if (!empty($row2['has_identity'])) { - $sql = "SELECT 1 as has_identity - FROM INFORMATION_SCHEMA.COLUMNS - WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1"; - $result2 = $db->sql_query($sql); - $row2 = $db->sql_fetchrow($result2); - - if (!empty($row2['has_identity'])) - { - $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n"; - $ident_set = true; - } - $db->sql_freeresult($result2); + $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n"; + $ident_set = true; } + $db->sql_freeresult($result2); while ($row = $db->sql_fetchrow($result)) { @@ -1664,7 +1671,8 @@ class mssql_extractor extends base_extractor { $str_val = $row[$ary_name[$i]]; - if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i])) + // defaults to type number - better quote just to be safe, so check for is_int too + if (is_int($ary_type[$i]) || preg_match('#char|text|bool|varbinary#i', $ary_type[$i])) { $str_quote = ''; $str_empty = "''"; @@ -1705,7 +1713,7 @@ class mssql_extractor extends base_extractor } $db->sql_freeresult($result); - if ($retrieved_data && $ident_set) + if ($ident_set) { $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n"; } diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php index 60512c67b8..486616c33d 100644 --- a/phpBB/includes/acp/acp_groups.php +++ b/phpBB/includes/acp/acp_groups.php @@ -394,6 +394,15 @@ class acp_groups } } + // Validate the length of "Maximum number of allowed recipients per private message" setting. + // We use 16777215 as a maximum because it matches MySQL unsigned mediumint maximum value + // which is the lowest amongst DBMSes supported by phpBB3 + if ($max_recipients_error = validate_data($submit_ary, array('max_recipients' => array('num', false, 0, 16777215)))) + { + // Replace "error" string with its real, localised form + $error = array_merge($error, array_map(array(&$user, 'lang'), $max_recipients_error)); + } + if (!sizeof($error)) { // Only set the rank, colour, etc. if it's changed or if we're adding a new diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php index 44d5722e4f..d6ac3b3acc 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/mssqlnative.php @@ -51,7 +51,6 @@ class result_mssqlnative } $this->m_row_count = count($this->m_rows); - sqlsrv_free_stmt($queryresult); } private function array_to_obj($array, &$obj) @@ -199,6 +198,7 @@ class dbal_mssqlnative extends dbal { var $m_insert_id = NULL; var $last_query_text = ''; + var $query_options = array(); /** * Connect to server @@ -308,10 +308,12 @@ class dbal_mssqlnative extends dbal if ($this->query_result === false) { - if (($this->query_result = @sqlsrv_query($this->db_connect_id, $query)) === false) + if (($this->query_result = @sqlsrv_query($this->db_connect_id, $query, array(), $this->query_options)) === false) { $this->sql_error($query); } + // reset options for next query + $this->query_options = array(); if (defined('DEBUG_EXTRA')) { @@ -598,20 +600,28 @@ class dbal_mssqlnative extends dbal * Utility method used to retrieve number of rows * Emulates mysql_num_rows * Used in acp_database.php -> write_data_mssqlnative() + * Requires a static or keyset cursor to be definde via + * mssqlnative_set_query_options() */ function mssqlnative_num_rows($res) { if ($res !== false) { - $row = new result_mssqlnative($res); - $num_rows = $row->num_rows(); - return $num_rows; + return sqlsrv_num_rows($res); } else { return false; } } + + /** + * Allows setting mssqlnative specific query options passed to sqlsrv_query as 4th parameter. + */ + function mssqlnative_set_query_options($options) + { + $this->query_options = $options; + } } ?>
\ No newline at end of file diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php index 87bf7a91a6..94d851e383 100644 --- a/phpBB/includes/functions_download.php +++ b/phpBB/includes/functions_download.php @@ -157,6 +157,16 @@ function send_file_to_browser($attachment, $upload_dir, $category) trigger_error('UNABLE_TO_DELIVER_FILE'); } + // Make sure the database record for the filesize is correct + if ($size > 0 && $size != $attachment['filesize']) + { + // Update database record + $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' + SET filesize = ' . (int) $size . ' + WHERE attach_id = ' . (int) $attachment['attach_id']; + $db->sql_query($sql); + } + // Now the tricky part... let's dance header('Pragma: public'); @@ -226,6 +236,16 @@ function send_file_to_browser($attachment, $upload_dir, $category) if ($fp !== false) { + // Deliver file partially if requested + if ($range = phpbb_http_byte_range($size)) + { + fseek($fp, $range['byte_pos_start']); + + send_status_line(206, 'Partial Content'); + header('Content-Range: bytes ' . $range['byte_pos_start'] . '-' . $range['byte_pos_end'] . '/' . $range['bytes_total']); + header('Content-Length: ' . $range['bytes_requested']); + } + while (!feof($fp)) { echo fread($fp, 8192); @@ -407,3 +427,151 @@ function file_gc() $db->sql_close(); exit; } + +/** +* HTTP range support (RFC 2616 Section 14.35) +* +* Allows browsers to request partial file content +* in case a download has been interrupted. +* +* @param int $filesize the size of the file in bytes we are about to deliver +* +* @return mixed false if the whole file has to be delivered +* associative array on success +*/ +function phpbb_http_byte_range($filesize) +{ + // Only call find_range_request() once. + static $request_array; + + if (!$filesize) + { + return false; + } + + if (!isset($request_array)) + { + $request_array = phpbb_find_range_request(); + } + + return (empty($request_array)) ? false : phpbb_parse_range_request($request_array, $filesize); +} + +/** +* Searches for HTTP range request in super globals. +* +* @return mixed false if no request found +* array of strings containing the requested ranges otherwise +* e.g. array(0 => '0-0', 1 => '123-125') +*/ +function phpbb_find_range_request() +{ + $globals = array( + array('_SERVER', 'HTTP_RANGE'), + array('_ENV', 'HTTP_RANGE'), + ); + + foreach ($globals as $array) + { + $global = $array[0]; + $key = $array[1]; + + // Make sure range request starts with "bytes=" + if (isset($GLOBALS[$global][$key]) && strpos($GLOBALS[$global][$key], 'bytes=') === 0) + { + // Strip leading 'bytes=' + // Multiple ranges can be separated by a comma + return explode(',', substr($GLOBALS[$global][$key], 6)); + } + } + + return false; +} + +/** +* Analyses a range request array. +* +* A range request can contain multiple ranges, +* we however only handle the first request and +* only support requests from a given byte to the end of the file. +* +* @param array $request_array array of strings containing the requested ranges +* @param int $filesize the full size of the file in bytes that has been requested +* +* @return mixed false if the whole file has to be delivered +* associative array on success +* byte_pos_start the first byte position, can be passed to fseek() +* byte_pos_end the last byte position +* bytes_requested the number of bytes requested +* bytes_total the full size of the file +*/ +function phpbb_parse_range_request($request_array, $filesize) +{ + // Go through all ranges + foreach ($request_array as $range_string) + { + $range = explode('-', trim($range_string)); + + // "-" is invalid, "0-0" however is valid and means the very first byte. + if (sizeof($range) != 2 || $range[0] === '' && $range[1] === '') + { + continue; + } + + if ($range[0] === '') + { + // Return last $range[1] bytes. + + if (!$range[1]) + { + continue; + } + + if ($range[1] >= $filesize) + { + return false; + } + + $first_byte_pos = $filesize - (int) $range[1]; + $last_byte_pos = $filesize - 1; + } + else + { + // Return bytes from $range[0] to $range[1] + + $first_byte_pos = (int) $range[0]; + $last_byte_pos = (int) $range[1]; + + if ($last_byte_pos && $last_byte_pos < $first_byte_pos) + { + // The requested range contains 0 bytes. + continue; + } + + if ($first_byte_pos >= $filesize) + { + // Requested range not satisfiable + return false; + } + + // Adjust last-byte-pos if it is absent or greater than the content. + if ($range[1] === '' || $last_byte_pos >= $filesize) + { + $last_byte_pos = $filesize - 1; + } + } + + // We currently do not support range requests that end before the end of the file + if ($last_byte_pos != $filesize - 1) + { + continue; + } + + return array( + 'byte_pos_start' => $first_byte_pos, + 'byte_pos_end' => $last_byte_pos, + 'bytes_requested' => $last_byte_pos - $first_byte_pos + 1, + 'bytes_total' => $filesize, + ); + } +} diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index bb0d88ec1b..b5c87094c0 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -632,6 +632,64 @@ class queue } /** + * Obtains exclusive lock on queue cache file. + * Returns resource representing the lock + */ + function lock() + { + // For systems that can't have two processes opening + // one file for writing simultaneously + if (file_exists($this->cache_file . '.lock')) + { + $mode = 'rb'; + } + else + { + $mode = 'wb'; + } + + $lock_fp = @fopen($this->cache_file . '.lock', $mode); + + if ($mode == 'wb') + { + if (!$lock_fp) + { + // Two processes may attempt to create lock file at the same time. + // Have the losing process try opening the lock file again for reading + // on the assumption that the winning process created it + $mode = 'rb'; + $lock_fp = @fopen($this->cache_file . '.lock', $mode); + } + else + { + // Only need to set mode when the lock file is written + @chmod($this->cache_file . '.lock', 0666); + } + } + + if ($lock_fp) + { + @flock($lock_fp, LOCK_EX); + } + + return $lock_fp; + } + + /** + * Releases lock on queue cache file, using resource obtained from lock() + */ + function unlock($lock_fp) + { + // lock() will return null if opening lock file, and thus locking, failed. + // Accept null values here so that client code does not need to check them + if ($lock_fp) + { + @flock($lock_fp, LOCK_UN); + fclose($lock_fp); + } + } + + /** * Process queue * Using lock file */ @@ -639,24 +697,16 @@ class queue { global $db, $config, $phpEx, $phpbb_root_path, $user; - set_config('last_queue_run', time(), true); + $lock_fp = $this->lock(); - // Delete stale lock file - if (file_exists($this->cache_file . '.lock') && !file_exists($this->cache_file)) - { - @unlink($this->cache_file . '.lock'); - return; - } + set_config('last_queue_run', time(), true); - if (!file_exists($this->cache_file) || (file_exists($this->cache_file . '.lock') && filemtime($this->cache_file) > time() - $config['queue_interval'])) + if (!file_exists($this->cache_file) || filemtime($this->cache_file) > time() - $config['queue_interval']) { + $this->unlock($lock_fp); return; } - $fp = @fopen($this->cache_file . '.lock', 'wb'); - fclose($fp); - @chmod($this->cache_file . '.lock', 0777); - include($this->cache_file); foreach ($this->queue_data as $object => $data_ary) @@ -720,6 +770,7 @@ class queue break; default: + $this->unlock($lock_fp); return; } @@ -745,8 +796,6 @@ class queue if (!$result) { - @unlink($this->cache_file . '.lock'); - messenger::error('EMAIL', $err_msg); continue 2; } @@ -790,16 +839,14 @@ class queue { if ($fp = @fopen($this->cache_file, 'wb')) { - @flock($fp, LOCK_EX); fwrite($fp, "<?php\nif (!defined('IN_PHPBB')) exit;\n\$this->queue_data = unserialize(" . var_export(serialize($this->queue_data), true) . ");\n\n?>"); - @flock($fp, LOCK_UN); fclose($fp); phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE); } } - @unlink($this->cache_file . '.lock'); + $this->unlock($lock_fp); } /** @@ -812,6 +859,8 @@ class queue return; } + $lock_fp = $this->lock(); + if (file_exists($this->cache_file)) { include($this->cache_file); @@ -831,13 +880,13 @@ class queue if ($fp = @fopen($this->cache_file, 'w')) { - @flock($fp, LOCK_EX); fwrite($fp, "<?php\nif (!defined('IN_PHPBB')) exit;\n\$this->queue_data = unserialize(" . var_export(serialize($this->data), true) . ");\n\n?>"); - @flock($fp, LOCK_UN); fclose($fp); phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE); } + + $this->unlock($lock_fp); } } diff --git a/phpBB/includes/search/fulltext_mysql.php b/phpBB/includes/search/fulltext_mysql.php index 0be3a10e5f..29cdd8ee9a 100644 --- a/phpBB/includes/search/fulltext_mysql.php +++ b/phpBB/includes/search/fulltext_mysql.php @@ -919,6 +919,14 @@ class fulltext_mysql extends search_backend <dt><label>' . $user->lang['FULLTEXT_MYSQL_MBSTRING'] . '</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_MBSTRING_EXPLAIN'] . '</span></dt> <dd>' . (($this->mbstring_regex) ? $user->lang['YES'] : $user->lang['NO']). '</dd> </dl> + <dl> + <dt><label>' . $user->lang['MIN_SEARCH_CHARS'] . ':</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_MIN_SEARCH_CHARS_EXPLAIN'] . '</span></dt> + <dd>' . $config['fulltext_mysql_min_word_len'] . '</dd> + </dl> + <dl> + <dt><label>' . $user->lang['MAX_SEARCH_CHARS'] . ':</label><br /><span>' . $user->lang['FULLTEXT_MYSQL_MAX_SEARCH_CHARS_EXPLAIN'] . '</span></dt> + <dd>' . $config['fulltext_mysql_max_word_len'] . '</dd> + </dl> '; // These are fields required in the config table diff --git a/phpBB/language/en/acp/search.php b/phpBB/language/en/acp/search.php index 88eed9d948..a7d687d7c2 100644 --- a/phpBB/language/en/acp/search.php +++ b/phpBB/language/en/acp/search.php @@ -59,6 +59,8 @@ $lang = array_merge($lang, array( 'FULLTEXT_MYSQL_PCRE' => 'Support for non-latin UTF-8 characters using PCRE:', 'FULLTEXT_MYSQL_MBSTRING_EXPLAIN' => 'If PCRE does not have unicode character properties, the search backend will try to use mbstring’s regular expression engine.', 'FULLTEXT_MYSQL_PCRE_EXPLAIN' => 'This search backend requires PCRE unicode character properties, only available in PHP 4.4, 5.1 and above, if you want to search for non-latin characters.', + 'FULLTEXT_MYSQL_MIN_SEARCH_CHARS_EXPLAIN' => 'Words with at least this many characters will be indexed for searching. You or your host can only change this setting by changing the mysql configuration.', + 'FULLTEXT_MYSQL_MAX_SEARCH_CHARS_EXPLAIN' => 'Words with no more than this many characters will be indexed for searching. You or your host can only change this setting by changing the mysql configuration.', 'GENERAL_SEARCH_SETTINGS' => 'General search settings', 'GO_TO_SEARCH_INDEX' => 'Go to search index page', diff --git a/phpBB/language/en/captcha_recaptcha.php b/phpBB/language/en/captcha_recaptcha.php index 897e8a4979..463bfffe0d 100644 --- a/phpBB/language/en/captcha_recaptcha.php +++ b/phpBB/language/en/captcha_recaptcha.php @@ -46,7 +46,7 @@ $lang = array_merge($lang, array( 'RECAPTCHA_PRIVATE' => 'Private reCaptcha key', 'RECAPTCHA_PRIVATE_EXPLAIN' => 'Your private reCaptcha key. Keys can be obtained on <a href="http://recaptcha.net">reCaptcha.net</a>.', - 'RECAPTCHA_EXPLAIN' => 'In an effort to prevent automatic submissions, we require that you enter both of the words displayed below into the text field underneath.', + 'RECAPTCHA_EXPLAIN' => 'In an effort to prevent automatic submissions, we require that you enter both of the words displayed into the text field underneath.', )); ?>
\ No newline at end of file diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index bc38c1563d..e79e5a6de3 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -566,6 +566,9 @@ $lang = array_merge($lang, array( 'TEST_CONNECTION' => 'Test connection', 'THE_TEAM' => 'The team', 'TIME' => 'Time', + + 'TOO_LARGE' => 'The value you entered is too large.', + 'TOO_LARGE_MAX_RECIPIENTS' => 'The value of <strong>Maximum number of allowed recipients per private message</strong> setting you entered is too large.', 'TOO_LONG' => 'The value you entered is too long.', @@ -608,6 +611,9 @@ $lang = array_merge($lang, array( 'TOO_SHORT_EMAIL_CONFIRM' => 'The e-mail address confirmation you entered is too short.', 'TOO_SHORT_WEBSITE' => 'The website address you entered is too short.', 'TOO_SHORT_YIM' => 'The Yahoo! Messenger name you entered is too short.', + + 'TOO_SMALL' => 'The value you entered is too small.', + 'TOO_SMALL_MAX_RECIPIENTS' => 'The value of <strong>Maximum number of allowed recipients per private message</strong> setting you entered is too small.', 'TOPIC' => 'Topic', 'TOPICS' => 'Topics', diff --git a/phpBB/styles/prosilver/template/captcha_recaptcha.html b/phpBB/styles/prosilver/template/captcha_recaptcha.html index 97d2cda28e..51a1615bd5 100644 --- a/phpBB/styles/prosilver/template/captcha_recaptcha.html +++ b/phpBB/styles/prosilver/template/captcha_recaptcha.html @@ -16,6 +16,7 @@ // <![CDATA[ var RecaptchaOptions = { lang : '{LA_RECAPTCHA_LANG}', + theme : 'clean', tabindex : <!-- IF $CAPTCHA_TAB_INDEX -->{$CAPTCHA_TAB_INDEX}<!-- ELSE -->10<!-- ENDIF --> }; // ]]> diff --git a/phpBB/styles/subsilver2/template/captcha_recaptcha.html b/phpBB/styles/subsilver2/template/captcha_recaptcha.html index 3776c77ea4..ec09b28ef5 100644 --- a/phpBB/styles/subsilver2/template/captcha_recaptcha.html +++ b/phpBB/styles/subsilver2/template/captcha_recaptcha.html @@ -9,6 +9,7 @@ // <![CDATA[ var RecaptchaOptions = { lang : '{LA_RECAPTCHA_LANG}', + theme : 'clean', tabindex : <!-- IF $CAPTCHA_TAB_INDEX -->{$CAPTCHA_TAB_INDEX}<!-- ELSE -->10<!-- ENDIF --> }; // ]]> |