diff options
Diffstat (limited to 'phpBB/includes')
108 files changed, 9440 insertions, 9187 deletions
diff --git a/phpBB/includes/acm/acm_file.php b/phpBB/includes/acm/acm_file.php index 175ef0ad81..b6af055399 100644 --- a/phpBB/includes/acm/acm_file.php +++ b/phpBB/includes/acm/acm_file.php @@ -80,6 +80,16 @@ class acm @flock($fp, LOCK_UN); fclose($fp); } + else + { + // Now, this occurred how often? ... phew, just tell the user then... + if (!@is_writeable($this->cache_dir)) + { + trigger_error($this->cache_dir . ' is NOT writeable.', E_USER_ERROR); + } + + trigger_error('Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx, E_USER_ERROR); + } $this->is_modified = false; } @@ -132,7 +142,7 @@ class acm */ function get($var_name) { - if ($var_name{0} == '_') + if ($var_name[0] == '_') { global $phpEx; @@ -155,7 +165,7 @@ class acm */ function put($var_name, $var, $ttl = 31536000) { - if ($var_name{0} == '_') + if ($var_name[0] == '_') { global $phpEx; @@ -176,6 +186,32 @@ class acm } /** + * Purge cache data + */ + function purge() + { + // Purge all phpbb cache files + $dir = opendir($this->cache_dir); + while (($entry = readdir($dir)) !== false) + { + if (strpos($entry, 'sql_') !== 0 && strpos($entry, 'data_') !== 0 && strpos($entry, 'ctpl_') !== 0 && strpos($entry, 'tpl_') !== 0) + { + continue; + } + + @unlink($this->cache_dir . $entry); + } + @closedir($dir); + + unset($this->vars); + unset($this->var_expires); + unset($this->sql_rowset); + unset($this->sql_row_pointer); + + $this->is_modified = false; + } + + /** * Destroy cache data */ function destroy($var_name, $table = '') @@ -213,7 +249,7 @@ class acm return; } - if ($var_name{0} == '_') + if ($var_name[0] == '_') { @unlink($this->cache_dir . 'data' . $var_name . ".$phpEx"); } @@ -233,7 +269,7 @@ class acm */ function _exists($var_name) { - if ($var_name{0} == '_') + if ($var_name[0] == '_') { global $phpEx; return file_exists($this->cache_dir . 'data' . $var_name . ".$phpEx"); @@ -345,7 +381,7 @@ class acm } $db->sql_freeresult($query_result); - fwrite($fp, "<?php\n\n/*\n$query\n*/\n\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n\n\$this->sql_rowset[\$query_id] = array(" . implode(',', $lines) . ') ?>'); + fwrite($fp, "<?php\n\n/*\n" . str_replace('*/', '*\/', $query) . "\n*/\n\n\$expired = (time() > " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n\n\$this->sql_rowset[\$query_id] = array(" . implode(',', $lines) . ') ?>'); @flock($fp, LOCK_UN); fclose($fp); @@ -375,14 +411,6 @@ class acm } /** - * Fetch the number of rows from cache (database) - */ - function sql_numrows($query_id) - { - return sizeof($this->sql_rowset[$query_id]); - } - - /** * Fetch a field from the current row of a cached database result (database) */ function sql_fetchfield($query_id, $field) @@ -398,7 +426,7 @@ class acm /** * Seek a specific row in an a cached database result (database) */ - function sql_rowseek($query_id, $rownum) + function sql_rowseek($rownum, $query_id) { if ($rownum >= sizeof($this->sql_rowset[$query_id])) { diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php index 1089a06152..59694b294e 100644 --- a/phpBB/includes/acp/acp_attachments.php +++ b/phpBB/includes/acp/acp_attachments.php @@ -46,7 +46,8 @@ class acp_attachments break; default: - trigger_error('NO_MODE'); + trigger_error('NO_MODE', E_USER_ERROR); + break; } $this->tpl_name = 'acp_attachments'; @@ -86,31 +87,42 @@ class acp_attachments 'img_max_width' => false, 'img_max_height' => false, 'img_link_width' => false, 'img_link_height' => false, 'legend1' => 'ACP_ATTACHMENT_SETTINGS', - 'allow_attachments' => array('lang' => 'ALLOW_ATTACHMENTS', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'type' => 'radio:yes_no', 'explain' => false), - 'upload_path' => array('lang' => 'UPLOAD_DIR', 'type' => 'text:25:100', 'explain' => true), - 'display_order' => array('lang' => 'DISPLAY_ORDER', 'type' => 'custom', 'method' => 'display_order', 'explain' => true), - 'attachment_quota' => array('lang' => 'ATTACH_QUOTA', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), - 'max_filesize' => array('lang' => 'ATTACH_MAX_FILESIZE', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), - 'max_filesize_pm' => array('lang' => 'ATTACH_MAX_PM_FILESIZE','type' => 'custom', 'method' => 'max_filesize', 'explain' => true), - 'max_attachments' => array('lang' => 'MAX_ATTACHMENTS', 'type' => 'text:3:3', 'explain' => false), - 'max_attachments_pm' => array('lang' => 'MAX_ATTACHMENTS_PM', 'type' => 'text:3:3', 'explain' => false), - 'secure_downloads' => array('lang' => 'SECURE_DOWNLOADS', 'type' => 'radio:yes_no', 'explain' => true), - 'secure_allow_deny' => array('lang' => 'SECURE_ALLOW_DENY', 'type' => 'custom', 'method' => 'select_allow_deny', 'explain' => true), - 'secure_allow_empty_referer' => array('lang' => 'SECURE_EMPTY_REFERRER', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_attachments' => array('lang' => 'ALLOW_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'upload_path' => array('lang' => 'UPLOAD_DIR', 'validate' => 'wpath', 'type' => 'text:25:100', 'explain' => true), + 'display_order' => array('lang' => 'DISPLAY_ORDER', 'validate' => 'bool', 'type' => 'custom', 'method' => 'display_order', 'explain' => true), + 'attachment_quota' => array('lang' => 'ATTACH_QUOTA', 'validate' => 'int', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), + 'max_filesize' => array('lang' => 'ATTACH_MAX_FILESIZE', 'validate' => 'int', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), + 'max_filesize_pm' => array('lang' => 'ATTACH_MAX_PM_FILESIZE','validate' => 'int', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true), + 'max_attachments' => array('lang' => 'MAX_ATTACHMENTS', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => false), + 'max_attachments_pm' => array('lang' => 'MAX_ATTACHMENTS_PM', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => false), + 'secure_downloads' => array('lang' => 'SECURE_DOWNLOADS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'secure_allow_deny' => array('lang' => 'SECURE_ALLOW_DENY', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_allow_deny', 'explain' => true), + 'secure_allow_empty_referer' => array('lang' => 'SECURE_EMPTY_REFERRER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend2' => $l_legend_cat_images, - 'img_display_inlined' => array('lang' => 'DISPLAY_INLINED', 'type' => 'radio:yes_no', 'explain' => true), - 'img_create_thumbnail' => array('lang' => 'CREATE_THUMBNAIL', 'type' => 'radio:yes_no', 'explain' => true), - 'img_min_thumb_filesize' => array('lang' => 'MIN_THUMB_FILESIZE', 'type' => 'text:7:15', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), - 'img_imagick' => array('lang' => 'IMAGICK_PATH', 'type' => 'text:20:200', 'explain' => true, 'append' => ' <span>[ <a href="' . $this->u_action . '&action=imgmagick">' . $user->lang['SEARCH_IMAGICK'] . '</a> ]</span>'), - 'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'type' => 'dimension:3:4', 'explain' => true), - 'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'type' => 'dimension:3:4', 'explain' => true), + 'img_display_inlined' => array('lang' => 'DISPLAY_INLINED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'img_create_thumbnail' => array('lang' => 'CREATE_THUMBNAIL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int', 'type' => 'text:7:15', 'explain' => true, 'append' => ' px'), + 'img_min_thumb_filesize' => array('lang' => 'MIN_THUMB_FILESIZE', 'validate' => 'int', 'type' => 'text:7:15', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), + 'img_imagick' => array('lang' => 'IMAGICK_PATH', 'validate' => 'string', 'type' => 'text:20:200', 'explain' => true, 'append' => ' <span>[ <a href="' . $this->u_action . '&action=imgmagick">' . $user->lang['SEARCH_IMAGICK'] . '</a> ]</span>'), + 'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true), + 'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true), ) ); $this->new_config = $config; $cfg_array = (isset($_REQUEST['config'])) ? request_var('config', array('' => '')) : $this->new_config; + $error = array(); + + // We validate the complete config if whished + validate_config_vars($display_vars['vars'], $cfg_array, $error); + + // Do not write values if there is an error + if (sizeof($error)) + { + $submit = false; + } // We go through the display_vars to make sure no one is trying to set variables he/she is not allowed to... foreach ($display_vars['vars'] as $config_name => $null) @@ -197,7 +209,9 @@ class acp_attachments $template->assign_vars(array( 'S_SECURE_DOWNLOADS' => $this->new_config['secure_downloads'], 'S_DEFINED_IPS' => ($defined_ips != '') ? true : false, + 'S_WARNING' => (sizeof($error)) ? true : false, + 'WARNING_MSG' => implode('<br />', $error), 'DEFINED_IPS' => $defined_ips, 'L_SECURE_TITLE' => $user->lang['DEFINE_' . $allow_deny . '_IPS'], @@ -403,12 +417,12 @@ class acp_attachments if ($action != 'add' && $action != 'edit') { - trigger_error('WRONG_MODE'); + trigger_error('NO_MODE', E_USER_ERROR); } if (!$group_id && $action == 'edit') { - trigger_error('NO_EXT_GROUP_SPECIFIED'); + trigger_error($user->lang['NO_EXT_GROUP_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); } if ($group_id) @@ -437,7 +451,7 @@ class acp_attachments { $sql = 'SELECT group_id FROM ' . EXTENSION_GROUPS_TABLE . " - WHERE LOWER(group_name) = '" . $db->sql_escape(strtolower($new_group_name)) . "'"; + WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($new_group_name)) . "'"; $result = $db->sql_query($sql); if ($db->sql_fetchrow($result)) @@ -521,15 +535,16 @@ class acp_attachments } $cat_lang = array( - ATTACHMENT_CATEGORY_NONE => $user->lang['NO_FILE_CAT'], - ATTACHMENT_CATEGORY_IMAGE => $user->lang['CAT_IMAGES'], - ATTACHMENT_CATEGORY_WM => $user->lang['CAT_WM_FILES'], - ATTACHMENT_CATEGORY_RM => $user->lang['CAT_RM_FILES'] + ATTACHMENT_CATEGORY_NONE => $user->lang['NO_FILE_CAT'], + ATTACHMENT_CATEGORY_IMAGE => $user->lang['CAT_IMAGES'], + ATTACHMENT_CATEGORY_WM => $user->lang['CAT_WM_FILES'], + ATTACHMENT_CATEGORY_RM => $user->lang['CAT_RM_FILES'], + ATTACHMENT_CATEGORY_FLASH => $user->lang['CAT_FLASH_FILES'], + ATTACHMENT_CATEGORY_QUICKTIME => $user->lang['CAT_QUICKTIME_FILES'], ); $group_id = request_var('g', 0); $action = (isset($_POST['add'])) ? 'add' : $action; -// $action = (($action == 'add' || $action == 'edit') && $submit && !sizeof($error)) ? 'show' : $action; switch ($action) { @@ -578,7 +593,7 @@ class acp_attachments if (!$group_id) { - trigger_error($user->lang['NO_EXTENSION_GROUP'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_EXT_GROUP_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT * @@ -770,7 +785,7 @@ class acp_attachments if (!$group_id) { - trigger_error($user->lang['NO_EXTENSION_GROUP'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_EXT_GROUP_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'UPDATE ' . EXTENSION_GROUPS_TABLE . ' @@ -823,24 +838,45 @@ class acp_attachments $add_files = (isset($_POST['add'])) ? array_keys(request_var('add', array('' => 0))) : array(); $post_ids = request_var('post_id', array('' => 0)); - foreach ($delete_files as $delete) + if (sizeof($delete_files)) { - phpbb_unlink($delete); - phpbb_unlink($delete, 'thumbnail'); + $sql = 'SELECT * + FROM ' . ATTACHMENTS_TABLE . ' + WHERE ' . $db->sql_in_set('attach_id', $delete_files) . ' + AND is_orphan = 1'; + $result = $db->sql_query($sql); + + $delete_files = array(); + while ($row = $db->sql_fetchrow($result)) + { + phpbb_unlink($row['physical_filename']); + + if ($row['thumbnail']) + { + phpbb_unlink($row['physical_filename'], 'thumbnail'); + } + + $delete_files[$row['attach_id']] = $row['real_filename']; + } + $db->sql_freeresult($result); } if (sizeof($delete_files)) { + $sql = 'DELETE FROM ' . ATTACHMENTS_TABLE . ' + WHERE ' . $db->sql_in_set('attach_id', array_keys($delete_files)); + $db->sql_query($sql); + add_log('admin', 'LOG_ATTACH_ORPHAN_DEL', implode(', ', $delete_files)); $notify[] = sprintf($user->lang['LOG_ATTACH_ORPHAN_DEL'], implode(', ', $delete_files)); } $upload_list = array(); - foreach ($add_files as $file) + foreach ($add_files as $attach_id) { - if (!in_array($file, $delete_files) && $post_ids[$file]) + if (!in_array($attach_id, array_keys($delete_files)) && !empty($post_ids[$attach_id])) { - $upload_list[$post_ids[$file]] = $file; + $upload_list[$attach_id] = $post_ids[$attach_id]; } } unset($add_files); @@ -849,13 +885,10 @@ class acp_attachments { $template->assign_var('S_UPLOADING_FILES', true); - include_once($phpbb_root_path . 'includes/message_parser.' . $phpEx); - $message_parser = new parse_message(); - $sql = 'SELECT forum_id, forum_name FROM ' . FORUMS_TABLE; $result = $db->sql_query($sql); - + $forum_names = array(); while ($row = $db->sql_fetchrow($result)) { @@ -863,30 +896,67 @@ class acp_attachments } $db->sql_freeresult($result); - $sql = 'SELECT forum_id, topic_id, post_id + $sql = 'SELECT forum_id, topic_id, post_id, poster_id FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('post_id', array_keys($upload_list)); + WHERE ' . $db->sql_in_set('post_id', $upload_list); + $result = $db->sql_query($sql); + + $post_info = array(); + while ($row = $db->sql_fetchrow($result)) + { + $post_info[$row['post_id']] = $row; + } + $db->sql_freeresult($result); + + // Select those attachments we want to change... + $sql = 'SELECT * + FROM ' . ATTACHMENTS_TABLE . ' + WHERE ' . $db->sql_in_set('attach_id', array_keys($upload_list)) . ' + AND is_orphan = 1'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { - $return = true; + $post_row = $post_info[$upload_list[$row['attach_id']]]; - if ($auth->acl_get('f_attach', $row['forum_id'])) + $template->assign_block_vars('upload', array( + 'FILE_INFO' => sprintf($user->lang['UPLOADING_FILE_TO'], $row['real_filename'], $post_row['post_id']), + 'S_DENIED' => (!$auth->acl_get('f_attach', $post_row['forum_id'])) ? true : false, + 'L_DENIED' => (!$auth->acl_get('f_attach', $post_row['forum_id'])) ? sprintf($user->lang['UPLOAD_DENIED_FORUM'], $forum_names[$row['forum_id']]) : '') + ); + + if (!$auth->acl_get('f_attach', $post_row['forum_id'])) { - $return = $this->upload_file($row['post_id'], $row['topic_id'], $row['forum_id'], $config['upload_path'], $upload_list[$row['post_id']]); + continue; } - $template->assign_block_vars('upload', array( - 'FILE_INFO' => sprintf($user->lang['UPLOADING_FILE_TO'], $upload_list[$row['post_id']], $row['post_id']), - 'S_DENIED' => (!$auth->acl_get('f_attach', $row['forum_id'])) ? true : false, - 'L_DENIED' => (!$auth->acl_get('f_attach', $row['forum_id'])) ? sprintf($user->lang['UPLOAD_DENIED_FORUM'], $forum_names[$row['forum_id']]) : '', - 'ERROR_MSG' => ($return === true) ? false : $return) + // Adjust attachment entry + $sql_ary = array( + 'in_message' => 0, + 'is_orphan' => 0, + 'poster_id' => $post_row['poster_id'], + 'post_msg_id' => $post_row['post_id'], + 'topic_id' => $post_row['topic_id'], ); + + $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE attach_id = ' . $row['attach_id']; + $db->sql_query($sql); + + $sql = 'UPDATE ' . POSTS_TABLE . ' + SET post_attachment = 1 + WHERE post_id = ' . $post_row['post_id']; + $db->sql_query($sql); + + $sql = 'UPDATE ' . TOPICS_TABLE . ' + SET topic_attachment = 1 + WHERE topic_id = ' . $post_row['topic_id']; + $db->sql_query($sql); + + add_log('admin', 'LOG_ATTACH_FILEUPLOAD', $post_row['post_id'], $row['real_filename']); } $db->sql_freeresult($result); - - unset($message_parser); } } @@ -894,43 +964,31 @@ class acp_attachments 'S_ORPHAN' => true) ); - $attach_filelist = array(); - - $dir = @opendir($phpbb_root_path . $config['upload_path']); - while (($file = @readdir($dir)) !== false) - { - if (is_file($phpbb_root_path . $config['upload_path'] . '/' . $file) && filesize($phpbb_root_path . $config['upload_path'] . '/' . $file) && $file{0} != '.' && $file != 'index.htm' && !preg_match('#^thumb\_#', $file)) - { - $attach_filelist[$file] = $file; - } - } - @closedir($dir); - - $sql = 'SELECT physical_filename - FROM ' . ATTACHMENTS_TABLE; + // Just get the files with is_orphan set and older than 3 hours + $sql = 'SELECT * + FROM ' . ATTACHMENTS_TABLE . ' + WHERE is_orphan = 1 + AND filetime < ' . (time() - 3*60*60) . ' + ORDER BY filetime DESC'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { - unset($attach_filelist[$row['physical_filename']]); - } - $db->sql_freeresult($result); - - $i = 0; - foreach ($attach_filelist as $file) - { - $filesize = @filesize($phpbb_root_path . $config['upload_path'] . '/' . $file); - $size_lang = ($filesize >= 1048576) ? $user->lang['MB'] : ( ($filesize >= 1024) ? $user->lang['KB'] : $user->lang['BYTES'] ); - $filesize = ($filesize >= 1048576) ? round((round($filesize / 1048576 * 100) / 100), 2) : (($filesize >= 1024) ? round((round($filesize / 1024 * 100) / 100), 2) : $filesize); + $size_lang = ($row['filesize'] >= 1048576) ? $user->lang['MB'] : (($row['filesize'] >= 1024) ? $user->lang['KB'] : $user->lang['BYTES']); + $row['filesize'] = ($row['filesize'] >= 1048576) ? round((round($row['filesize'] / 1048576 * 100) / 100), 2) : (($row['filesize'] >= 1024) ? round((round($row['filesize'] / 1024 * 100) / 100), 2) : $row['filesize']); $template->assign_block_vars('orphan', array( - 'FILESIZE' => $filesize . ' ' . $size_lang, - 'U_FILE' => $phpbb_root_path . $config['upload_path'] . '/' . $file, - 'FILE' => $file, - 'POST_IDS' => (!empty($post_ids[$file])) ? $post_ids[$file] : '') + 'FILESIZE' => $row['filesize'] . ' ' . $size_lang, + 'FILETIME' => $user->format_date($row['filetime']), + 'REAL_FILENAME' => basename($row['real_filename']), + 'PHYSICAL_FILENAME' => basename($row['physical_filename']), + 'ATTACH_ID' => $row['attach_id'], + 'POST_IDS' => (!empty($post_ids[$row['attach_id']])) ? $post_ids[$row['attach_id']] : '', + 'U_FILE' => append_sid($phpbb_root_path . 'download.' . $phpEx, 'id=' . $row['attach_id'])) ); } - + $db->sql_freeresult($result); + break; } @@ -959,10 +1017,12 @@ class acp_attachments global $db, $user; $types = array( - ATTACHMENT_CATEGORY_NONE => $user->lang['NO_FILE_CAT'], - ATTACHMENT_CATEGORY_IMAGE => $user->lang['CAT_IMAGES'], - ATTACHMENT_CATEGORY_WM => $user->lang['CAT_WM_FILES'], - ATTACHMENT_CATEGORY_RM => $user->lang['CAT_RM_FILES'] + ATTACHMENT_CATEGORY_NONE => $user->lang['NO_FILE_CAT'], + ATTACHMENT_CATEGORY_IMAGE => $user->lang['CAT_IMAGES'], + ATTACHMENT_CATEGORY_WM => $user->lang['CAT_WM_FILES'], + ATTACHMENT_CATEGORY_RM => $user->lang['CAT_RM_FILES'], + ATTACHMENT_CATEGORY_FLASH => $user->lang['CAT_FLASH_FILES'], + ATTACHMENT_CATEGORY_QUICKTIME => $user->lang['CAT_QUICKTIME_FILES'], ); if ($group_id) @@ -1079,70 +1139,6 @@ class acp_attachments return $group_select; } - /** - * Upload already uploaded file... huh? are you kidding? - */ - function upload_file($post_id, $topic_id, $forum_id, $upload_dir, $filename) - { - global $message_parser, $db, $user, $phpbb_root_path; - - $message_parser->attachment_data = array(); - - $message_parser->filename_data['filecomment'] = ''; - $message_parser->filename_data['filename'] = $phpbb_root_path . $upload_dir . '/' . basename($filename); - - $filedata = upload_attachment('local', $forum_id, true, $phpbb_root_path . $upload_dir . '/' . basename($filename)); - - if ($filedata['post_attach'] && !sizeof($filedata['error'])) - { - $message_parser->attachment_data = array( - 'post_msg_id' => $post_id, - 'poster_id' => $user->data['user_id'], - 'topic_id' => $topic_id, - 'in_message' => 0, - 'physical_filename' => $filedata['physical_filename'], - 'real_filename' => $filedata['real_filename'], - 'attach_comment' => $message_parser->filename_data['filecomment'], - 'extension' => $filedata['extension'], - 'mimetype' => $filedata['mimetype'], - 'filesize' => $filedata['filesize'], - 'filetime' => $filedata['filetime'], - 'thumbnail' => $filedata['thumbnail'] - ); - - $message_parser->filename_data['filecomment'] = ''; - $filedata['post_attach'] = false; - - // Submit Attachment - $attach_sql = $message_parser->attachment_data; - - $db->sql_transaction('begin'); - - $sql = 'INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $attach_sql); - $db->sql_query($sql); - - $sql = 'UPDATE ' . POSTS_TABLE . " - SET post_attachment = 1 - WHERE post_id = $post_id"; - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_attachment = 1 - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - - $db->sql_transaction('commit'); - - add_log('admin', 'LOG_ATTACH_FILEUPLOAD', $post_id, $filename); - - return true; - } - else if (sizeof($filedata['error'])) - { - return sprintf($user->lang['ADMIN_UPLOAD_ERROR'], implode('<br />', $filedata['error'])); - } - } - /** * Search Imagick */ @@ -1369,7 +1365,7 @@ class acp_attachments add_log('admin', $log_entry, $ip_list_log); } - trigger_error($user->lang['SECURE_DOWNLOAD_UPDATE_SUCCESS']); + trigger_error($user->lang['SECURE_DOWNLOAD_UPDATE_SUCCESS'] . adm_back_link($this->u_action)); } else if (isset($_POST['unsecuresubmit'])) { @@ -1398,7 +1394,7 @@ class acp_attachments add_log('admin', 'LOG_DOWNLOAD_REMOVE_IP', $l_unip_list); } - trigger_error($user->lang['SECURE_DOWNLOAD_UPDATE_SUCCESS']); + trigger_error($user->lang['SECURE_DOWNLOAD_UPDATE_SUCCESS'] . adm_back_link($this->u_action)); } } diff --git a/phpBB/includes/acp/acp_ban.php b/phpBB/includes/acp/acp_ban.php index 420deb975f..a4e860b7bc 100644 --- a/phpBB/includes/acp/acp_ban.php +++ b/phpBB/includes/acp/acp_ban.php @@ -189,7 +189,7 @@ class acp_ban $template->assign_block_vars('ban_reason', array( 'BAN_ID' => $ban_id, 'REASON' => $reason, - 'A_REASON' => addslashes(html_entity_decode($reason))) + 'A_REASON' => addslashes(htmlspecialchars_decode($reason))) ); } } @@ -201,7 +201,7 @@ class acp_ban $template->assign_block_vars('ban_give_reason', array( 'BAN_ID' => $ban_id, 'REASON' => $reason, - 'A_REASON' => addslashes(html_entity_decode($reason))) + 'A_REASON' => addslashes(htmlspecialchars_decode($reason))) ); } } diff --git a/phpBB/includes/acp/acp_bbcodes.php b/phpBB/includes/acp/acp_bbcodes.php index cdfe8e42eb..e4ea02ad4d 100644 --- a/phpBB/includes/acp/acp_bbcodes.php +++ b/phpBB/includes/acp/acp_bbcodes.php @@ -47,13 +47,13 @@ class acp_bbcodes if (!$row) { - trigger_error('BBCODE_NOT_EXIST'); + trigger_error($user->lang['BBCODE_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); } $bbcode_match = $row['bbcode_match']; $bbcode_tpl = htmlspecialchars($row['bbcode_tpl']); $display_on_posting = $row['display_on_posting']; - $bbcode_helpline = html_entity_decode($row['bbcode_helpline']); + $bbcode_helpline = $row['bbcode_helpline']; break; case 'modify': @@ -66,7 +66,7 @@ class acp_bbcodes if (!$row) { - trigger_error('BBCODE_NOT_EXIST'); + trigger_error($user->lang['BBCODE_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); } // No break here @@ -75,8 +75,8 @@ class acp_bbcodes $display_on_posting = request_var('display_on_posting', 0); $bbcode_match = request_var('bbcode_match', ''); - $bbcode_tpl = html_entity_decode(request_var('bbcode_tpl', '')); - $bbcode_helpline = htmlspecialchars(request_var('bbcode_helpline', '')); + $bbcode_tpl = htmlspecialchars_decode(request_var('bbcode_tpl', '')); + $bbcode_helpline = request_var('bbcode_helpline', ''); break; } @@ -127,9 +127,11 @@ class acp_bbcodes $info = $db->sql_fetchrow($result); $db->sql_freeresult($result); - if ($info['test'] === '1' || in_array(strtolower($data['bbcode_tag']), $hard_coded)) + // Grab the end, interrogate the last closing tag + preg_match('#\[/([^[]*)]$#', $bbcode_match, $regs); + if ($info['test'] === '1' || in_array(strtolower($data['bbcode_tag']), $hard_coded) || in_array(strtolower($regs[1]), $hard_coded)) { - trigger_error('BBCODE_INVALID_TAG_NAME'); + trigger_error($user->lang['BBCODE_INVALID_TAG_NAME'] . adm_back_link($this->u_action), E_USER_WARNING); } } @@ -170,12 +172,13 @@ class acp_bbcodes if ($bbcode_id > 1511) { - trigger_error('TOO_MANY_BBCODES'); + trigger_error($user->lang['TOO_MANY_BBCODES'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql_ary['bbcode_id'] = (int) $bbcode_id; $db->sql_query('INSERT INTO ' . BBCODES_TABLE . $db->sql_build_array('INSERT', $sql_ary)); + $cache->destroy('sql', BBCODES_TABLE); $lang = 'BBCODE_ADDED'; $log_action = 'LOG_BBCODE_ADD'; @@ -186,6 +189,7 @@ class acp_bbcodes SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE bbcode_id = ' . $bbcode_id; $db->sql_query($sql); + $cache->destroy('sql', BBCODES_TABLE); $lang = 'BBCODE_EDITED'; $log_action = 'LOG_BBCODE_EDIT'; @@ -208,8 +212,21 @@ class acp_bbcodes if ($row) { - $db->sql_query('DELETE FROM ' . BBCODES_TABLE . " WHERE bbcode_id = $bbcode_id"); - add_log('admin', 'LOG_BBCODE_DELETE', $row['bbcode_tag']); + if (confirm_box(true)) + { + $db->sql_query('DELETE FROM ' . BBCODES_TABLE . " WHERE bbcode_id = $bbcode_id"); + $cache->destroy('sql', BBCODES_TABLE); + add_log('admin', 'LOG_BBCODE_DELETE', $row['bbcode_tag']); + } + else + { + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( + 'bbcode' => $bbcode_id, + 'i' => $id, + 'mode' => $mode, + 'action' => $action)) + ); + } } break; @@ -290,7 +307,7 @@ class acp_bbcodes if (preg_match_all('/(?<!\\\\)\$([0-9]+)/', $replace, $repad)) { $repad = $pad + sizeof(array_unique($repad[0])); - $replace = preg_replace('/(?<!\\\\)\$([0-9]+)/e', "'\$' . (\$1 + \$pad)", $replace); + $replace = preg_replace('/(?<!\\\\)\$([0-9]+)/e', "'\${' . (\$1 + \$pad) . '}'", $replace); $pad = $repad; } @@ -320,7 +337,7 @@ class acp_bbcodes $fp_replace = str_replace($token, $replace, $fp_replace); $sp_match = str_replace(preg_quote($token, '!'), '(.*?)', $sp_match); - $sp_replace = str_replace($token, '$' . ($n + 1), $sp_replace); + $sp_replace = str_replace($token, '${' . ($n + 1) . '}', $sp_replace); } $fp_match = '!' . $fp_match . '!' . $modifiers; diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index 49e4b1eb1c..84cc8ddd1c 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -27,6 +27,7 @@ class acp_board $action = request_var('action', ''); $submit = (isset($_POST['submit'])) ? true : false; + // Validation types are: string, int, bool, rpath (relative), rwpath (realtive, writeable), path (relative path, but able to escape the root), wpath (writeable) switch ($mode) { case 'settings': @@ -34,19 +35,19 @@ class acp_board 'title' => 'ACP_BOARD_SETTINGS', 'vars' => array( 'legend1' => 'ACP_BOARD_SETTINGS', - 'sitename' => array('lang' => 'SITE_NAME', 'type' => 'text:40:255', 'explain' => false), - 'site_desc' => array('lang' => 'SITE_DESC', 'type' => 'text:40:255', 'explain' => false), - 'board_disable' => array('lang' => 'DISABLE_BOARD', 'type' => 'custom', 'method' => 'board_disable', 'explain' => true), + 'sitename' => array('lang' => 'SITE_NAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false), + 'site_desc' => array('lang' => 'SITE_DESC', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false), + 'board_disable' => array('lang' => 'DISABLE_BOARD', 'validate' => 'bool', 'type' => 'custom', 'method' => 'board_disable', 'explain' => true), 'board_disable_msg' => false, - 'default_lang' => array('lang' => 'DEFAULT_LANGUAGE', 'type' => 'select', 'function' => 'language_select', 'params' => array('{CONFIG_VALUE}'), 'explain' => false), - 'default_dateformat' => array('lang' => 'DEFAULT_DATE_FORMAT', 'type' => 'custom', 'method' => 'dateformat_select', 'explain' => true), - 'board_timezone' => array('lang' => 'SYSTEM_TIMEZONE', 'type' => 'select', 'function' => 'tz_select', 'params' => array('{CONFIG_VALUE}', 1), 'explain' => false), - 'board_dst' => array('lang' => 'SYSTEM_DST', 'type' => 'radio:yes_no', 'explain' => false), - 'default_style' => array('lang' => 'DEFAULT_STYLE', 'type' => 'select', 'function' => 'style_select', 'params' => array('{CONFIG_VALUE}', 1), 'explain' => false), - 'override_user_style' => array('lang' => 'OVERRIDE_STYLE', 'type' => 'radio:yes_no', 'explain' => true), + 'default_lang' => array('lang' => 'DEFAULT_LANGUAGE', 'validate' => 'string', 'type' => 'select', 'function' => 'language_select', 'params' => array('{CONFIG_VALUE}'), 'explain' => false), + 'default_dateformat' => array('lang' => 'DEFAULT_DATE_FORMAT', 'validate' => 'string', 'type' => 'custom', 'method' => 'dateformat_select', 'explain' => true), + 'board_timezone' => array('lang' => 'SYSTEM_TIMEZONE', 'validate' => 'string', 'type' => 'select', 'function' => 'tz_select', 'params' => array('{CONFIG_VALUE}', 1), 'explain' => false), + 'board_dst' => array('lang' => 'SYSTEM_DST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'default_style' => array('lang' => 'DEFAULT_STYLE', 'validate' => 'int', 'type' => 'select', 'function' => 'style_select', 'params' => array('{CONFIG_VALUE}', 1), 'explain' => false), + 'override_user_style' => array('lang' => 'OVERRIDE_STYLE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend2' => 'WARNINGS', - 'warnings_expire_days' => array('lang' => 'WARNINGS_EXPIRE', 'type' => 'text:3:4', 'explain' => true), + 'warnings_expire_days' => array('lang' => 'WARNINGS_EXPIRE', 'validate' => 'int', 'type' => 'text:3:4', 'explain' => true), ) ); break; @@ -56,29 +57,25 @@ class acp_board 'title' => 'ACP_BOARD_FEATURES', 'vars' => array( 'legend1' => 'ACP_BOARD_FEATURES', - 'allow_privmsg' => array('lang' => 'BOARD_PM', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_topic_notify' => array('lang' => 'ALLOW_TOPIC_NOTIFY', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_forum_notify' => array('lang' => 'ALLOW_FORUM_NOTIFY', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_attachments' => array('lang' => 'ALLOW_ATTACHMENTS', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_bbcode' => array('lang' => 'ALLOW_BBCODE', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_smilies' => array('lang' => 'ALLOW_SMILIES', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig' => array('lang' => 'ALLOW_SIG', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_bbcode' => array('lang' => 'ALLOW_SIG_BBCODE', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_img' => array('lang' => 'ALLOW_SIG_IMG', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_flash' => array('lang' => 'ALLOW_SIG_FLASH', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_smilies' => array('lang' => 'ALLOW_SIG_SMILIES', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_nocensors' => array('lang' => 'ALLOW_NO_CENSORS', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_bookmarks' => array('lang' => 'ALLOW_BOOKMARKS', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_privmsg' => array('lang' => 'BOARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_topic_notify' => array('lang' => 'ALLOW_TOPIC_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_forum_notify' => array('lang' => 'ALLOW_FORUM_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_attachments' => array('lang' => 'ALLOW_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_bbcode' => array('lang' => 'ALLOW_BBCODE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_smilies' => array('lang' => 'ALLOW_SMILIES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_sig' => array('lang' => 'ALLOW_SIG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_nocensors' => array('lang' => 'ALLOW_NO_CENSORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_bookmarks' => array('lang' => 'ALLOW_BOOKMARKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend2' => 'ACP_LOAD_SETTINGS', - 'load_birthdays' => array('lang' => 'YES_BIRTHDAYS', 'type' => 'radio:yes_no', 'explain' => false), - 'load_moderators' => array('lang' => 'YES_MODERATORS', 'type' => 'radio:yes_no', 'explain' => false), - 'load_jumpbox' => array('lang' => 'YES_JUMPBOX', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'type' => 'radio:yes_no', 'explain' => false), + 'load_birthdays' => array('lang' => 'YES_BIRTHDAYS', '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_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), ) ); break; @@ -90,14 +87,14 @@ class acp_board 'legend1' => 'ACP_AVATAR_SETTINGS', 'avatar_min_height' => false, 'avatar_min_width' => false, 'avatar_max_height' => false, 'avatar_max_width' => false, - 'allow_avatar_local' => array('lang' => 'ALLOW_LOCAL', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_avatar_remote' => array('lang' => 'ALLOW_REMOTE', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_avatar_upload' => array('lang' => 'ALLOW_UPLOAD', 'type' => 'radio:yes_no', 'explain' => false), - 'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'type' => 'text:4:10', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), - 'avatar_min' => array('lang' => 'MIN_AVATAR_SIZE', 'type' => 'dimension:3:4', 'explain' => true), - 'avatar_max' => array('lang' => 'MAX_AVATAR_SIZE', 'type' => 'dimension:3:4', 'explain' => true), - 'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'type' => 'text:20:255', 'explain' => true), - 'avatar_gallery_path' => array('lang' => 'AVATAR_GALLERY_PATH', 'type' => 'text:20:255', 'explain' => true) + 'allow_avatar_local' => array('lang' => 'ALLOW_LOCAL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_avatar_remote' => array('lang' => 'ALLOW_REMOTE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_avatar_upload' => array('lang' => 'ALLOW_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'validate' => 'int', 'type' => 'text:4:10', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), + 'avatar_min' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true), + 'avatar_max' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true), + 'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'validate' => 'rwpath', 'type' => 'text:20:255', 'explain' => true), + 'avatar_gallery_path' => array('lang' => 'AVATAR_GALLERY_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true) ) ); break; @@ -108,23 +105,23 @@ class acp_board 'lang' => 'ucp', 'vars' => array( 'legend1' => 'GENERAL_SETTINGS', - 'allow_privmsg' => array('lang' => 'BOARD_PM', 'type' => 'radio:yes_no', 'explain' => true), - 'pm_max_boxes' => array('lang' => 'BOXES_MAX', 'type' => 'text:4:4', 'explain' => true), - 'pm_max_msgs' => array('lang' => 'BOXES_LIMIT', 'type' => 'text:4:4', 'explain' => true), - 'full_folder_action' => array('lang' => 'FULL_FOLDER_ACTION', 'type' => 'select', 'method' => 'full_folder_select', 'explain' => true), - 'pm_edit_time' => array('lang' => 'PM_EDIT_TIME', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), + 'allow_privmsg' => array('lang' => 'BOARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'pm_max_boxes' => array('lang' => 'BOXES_MAX', 'validate' => 'int', 'type' => 'text:4:4', 'explain' => true), + 'pm_max_msgs' => array('lang' => 'BOXES_LIMIT', 'validate' => 'int', 'type' => 'text:4:4', 'explain' => true), + 'full_folder_action' => array('lang' => 'FULL_FOLDER_ACTION', 'validate' => 'int', 'type' => 'select', 'method' => 'full_folder_select', 'explain' => true), + 'pm_edit_time' => array('lang' => 'PM_EDIT_TIME', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), 'legend2' => 'GENERAL_OPTIONS', - 'allow_mass_pm' => array('lang' => 'ALLOW_MASS_PM', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_bbcode_pm' => array('lang' => 'ALLOW_BBCODE_PM', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_smilies_pm' => array('lang' => 'ALLOW_SMILIES_PM', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_pm' => array('lang' => 'ALLOW_SIG_PM', 'type' => 'radio:yes_no', 'explain' => false), - 'print_pm' => array('lang' => 'ALLOW_PRINT_PM', 'type' => 'radio:yes_no', 'explain' => false), - 'forward_pm' => array('lang' => 'ALLOW_FORWARD_PM', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_img_pm' => array('lang' => 'ALLOW_IMG_PM', 'type' => 'radio:yes_no', 'explain' => false), - 'auth_flash_pm' => array('lang' => 'ALLOW_FLASH_PM', 'type' => 'radio:yes_no', 'explain' => false), - 'enable_pm_icons' => array('lang' => 'ENABLE_PM_ICONS', 'type' => 'radio:yes_no', 'explain' => false) + 'allow_mass_pm' => array('lang' => 'ALLOW_MASS_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'auth_bbcode_pm' => array('lang' => 'ALLOW_BBCODE_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'auth_smilies_pm' => array('lang' => 'ALLOW_SMILIES_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_sig_pm' => array('lang' => 'ALLOW_SIG_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'print_pm' => array('lang' => 'ALLOW_PRINT_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'forward_pm' => array('lang' => 'ALLOW_FORWARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'auth_img_pm' => array('lang' => 'ALLOW_IMG_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'auth_flash_pm' => array('lang' => 'ALLOW_FLASH_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'enable_pm_icons' => array('lang' => 'ENABLE_PM_ICONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false) ) ); break; @@ -134,31 +131,32 @@ class acp_board 'title' => 'ACP_POST_SETTINGS', 'vars' => array( 'legend1' => 'GENERAL_OPTIONS', - 'allow_topic_notify' => array('lang' => 'ALLOW_TOPIC_NOTIFY', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_forum_notify' => array('lang' => 'ALLOW_FORUM_NOTIFY', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_bbcode' => array('lang' => 'ALLOW_BBCODE', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_smilies' => array('lang' => 'ALLOW_SMILIES', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_nocensors' => array('lang' => 'ALLOW_NO_CENSORS', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_bookmarks' => array('lang' => 'ALLOW_BOOKMARKS', 'type' => 'radio:yes_no', 'explain' => true), - 'enable_post_confirm' => array('lang' => 'VISUAL_CONFIRM_POST', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_topic_notify' => array('lang' => 'ALLOW_TOPIC_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_forum_notify' => array('lang' => 'ALLOW_FORUM_NOTIFY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_bbcode' => array('lang' => 'ALLOW_BBCODE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_smilies' => array('lang' => 'ALLOW_SMILIES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_post_links' => array('lang' => 'ALLOW_POST_LINKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_nocensors' => array('lang' => 'ALLOW_NO_CENSORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_bookmarks' => array('lang' => 'ALLOW_BOOKMARKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'enable_post_confirm' => array('lang' => 'VISUAL_CONFIRM_POST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend2' => 'POSTING', 'bump_type' => false, - 'edit_time' => array('lang' => 'EDIT_TIME', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), - 'display_last_edited' => array('lang' => 'DISPLAY_LAST_EDITED', 'type' => 'radio:yes_no', 'explain' => true), - 'flood_interval' => array('lang' => 'FLOOD_INTERVAL', 'type' => 'text:3:4', 'explain' => true), - 'bump_interval' => array('lang' => 'BUMP_INTERVAL', 'type' => 'custom', 'method' => 'bump_interval', 'explain' => true), - 'topics_per_page' => array('lang' => 'TOPICS_PER_PAGE', 'type' => 'text:3:4', 'explain' => false), - 'posts_per_page' => array('lang' => 'POSTS_PER_PAGE', 'type' => 'text:3:4', 'explain' => false), - 'hot_threshold' => array('lang' => 'HOT_THRESHOLD', 'type' => 'text:3:4', 'explain' => false), - 'max_poll_options' => array('lang' => 'MAX_POLL_OPTIONS', 'type' => 'text:4:4', 'explain' => false), - 'max_post_chars' => array('lang' => 'CHAR_LIMIT', 'type' => 'text:4:6', 'explain' => true), - 'max_post_smilies' => array('lang' => 'SMILIES_LIMIT', 'type' => 'text:4:4', 'explain' => true), - 'max_post_urls' => array('lang' => 'MAX_POST_URLS', 'type' => 'text:5:4', 'explain' => true), - 'max_post_font_size' => array('lang' => 'MAX_POST_FONT_SIZE', 'type' => 'text:5:4', 'explain' => true), - 'max_quote_depth' => array('lang' => 'QUOTE_DEPTH_LIMIT', 'type' => 'text:4:4', 'explain' => true), - 'max_post_img_width' => array('lang' => 'MAX_POST_IMG_WIDTH', 'type' => 'text:5:4', 'explain' => true), - 'max_post_img_height' => array('lang' => 'MAX_POST_IMG_HEIGHT', 'type' => 'text:5:4', 'explain' => true), + 'edit_time' => array('lang' => 'EDIT_TIME', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), + 'display_last_edited' => array('lang' => 'DISPLAY_LAST_EDITED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'flood_interval' => array('lang' => 'FLOOD_INTERVAL', 'validate' => 'int', 'type' => 'text:3:4', 'explain' => true), + 'bump_interval' => array('lang' => 'BUMP_INTERVAL', 'validate' => 'int', 'type' => 'custom', 'method' => 'bump_interval', 'explain' => true), + 'topics_per_page' => array('lang' => 'TOPICS_PER_PAGE', 'validate' => 'int', 'type' => 'text:3:4', 'explain' => false), + 'posts_per_page' => array('lang' => 'POSTS_PER_PAGE', 'validate' => 'int', 'type' => 'text:3:4', 'explain' => false), + 'hot_threshold' => array('lang' => 'HOT_THRESHOLD', 'validate' => 'int', 'type' => 'text:3:4', 'explain' => false), + 'max_poll_options' => array('lang' => 'MAX_POLL_OPTIONS', 'validate' => 'int', 'type' => 'text:4:4', 'explain' => false), + 'max_post_chars' => array('lang' => 'CHAR_LIMIT', 'validate' => 'int', 'type' => 'text:4:6', 'explain' => true), + 'max_post_smilies' => array('lang' => 'SMILIES_LIMIT', 'validate' => 'int', 'type' => 'text:4:4', 'explain' => true), + 'max_post_urls' => array('lang' => 'MAX_POST_URLS', 'validate' => 'int', 'type' => 'text:5:4', 'explain' => true), + 'max_post_font_size' => array('lang' => 'MAX_POST_FONT_SIZE', 'validate' => 'int', 'type' => 'text:5:4', 'explain' => true), + 'max_quote_depth' => array('lang' => 'QUOTE_DEPTH_LIMIT', 'validate' => 'int', 'type' => 'text:4:4', 'explain' => true), + 'max_post_img_width' => array('lang' => 'MAX_POST_IMG_WIDTH', 'validate' => 'int', 'type' => 'text:5:4', 'explain' => true), + 'max_post_img_height' => array('lang' => 'MAX_POST_IMG_HEIGHT', 'validate' => 'int', 'type' => 'text:5:4', 'explain' => true), ) ); break; @@ -168,19 +166,20 @@ class acp_board 'title' => 'ACP_SIGNATURE_SETTINGS', 'vars' => array( 'legend1' => 'GENERAL_OPTIONS', - 'allow_sig' => array('lang' => 'ALLOW_SIG', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_bbcode' => array('lang' => 'ALLOW_SIG_BBCODE', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_img' => array('lang' => 'ALLOW_SIG_IMG', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_flash' => array('lang' => 'ALLOW_SIG_FLASH', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_sig_smilies' => array('lang' => 'ALLOW_SIG_SMILIES', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_sig' => array('lang' => 'ALLOW_SIG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_sig_bbcode' => array('lang' => 'ALLOW_SIG_BBCODE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_sig_img' => array('lang' => 'ALLOW_SIG_IMG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_sig_flash' => array('lang' => 'ALLOW_SIG_FLASH', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_sig_smilies' => array('lang' => 'ALLOW_SIG_SMILIES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_sig_links' => array('lang' => 'ALLOW_SIG_LINKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend2' => 'GENERAL_SETTINGS', - 'max_sig_chars' => array('lang' => 'MAX_SIG_LENGTH', 'type' => 'text:5:4', 'explain' => true), - 'max_sig_urls' => array('lang' => 'MAX_SIG_URLS', 'type' => 'text:5:4', 'explain' => true), - 'max_sig_font_size' => array('lang' => 'MAX_SIG_FONT_SIZE', 'type' => 'text:5:4', 'explain' => true), - 'max_sig_smilies' => array('lang' => 'MAX_SIG_SMILIES', 'type' => 'text:5:4', 'explain' => true), - 'max_sig_img_width' => array('lang' => 'MAX_SIG_IMG_WIDTH', 'type' => 'text:5:4', 'explain' => true), - 'max_sig_img_height' => array('lang' => 'MAX_SIG_IMG_HEIGHT', 'type' => 'text:5:4', 'explain' => true), + 'max_sig_chars' => array('lang' => 'MAX_SIG_LENGTH', 'validate' => 'int', 'type' => 'text:5:4', 'explain' => true), + 'max_sig_urls' => array('lang' => 'MAX_SIG_URLS', 'validate' => 'int', 'type' => 'text:5:4', 'explain' => true), + 'max_sig_font_size' => array('lang' => 'MAX_SIG_FONT_SIZE', 'validate' => 'int', 'type' => 'text:5:4', 'explain' => true), + 'max_sig_smilies' => array('lang' => 'MAX_SIG_SMILIES', 'validate' => 'int', 'type' => 'text:5:4', 'explain' => true), + 'max_sig_img_width' => array('lang' => 'MAX_SIG_IMG_WIDTH', 'validate' => 'int', 'type' => 'text:5:4', 'explain' => true), + 'max_sig_img_height' => array('lang' => 'MAX_SIG_IMG_HEIGHT', 'validate' => 'int', 'type' => 'text:5:4', 'explain' => true), ) ); break; @@ -193,24 +192,24 @@ class acp_board 'max_name_chars' => false, 'max_pass_chars' => false, - 'require_activation' => array('lang' => 'ACC_ACTIVATION', 'type' => 'custom', 'method' => 'select_acc_activation', 'explain' => true), - 'min_name_chars' => array('lang' => 'USERNAME_LENGTH', 'type' => 'custom', 'method' => 'username_length', 'explain' => true), - 'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'type' => 'custom', 'method' => 'password_length', 'explain' => true), - 'allow_name_chars' => array('lang' => 'USERNAME_CHARS', 'type' => 'select', 'method' => 'select_username_chars', 'explain' => true), - 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), - 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'type' => 'text:3:3', 'explain' => true), + 'require_activation' => array('lang' => 'ACC_ACTIVATION', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_acc_activation', 'explain' => true), + 'min_name_chars' => array('lang' => 'USERNAME_LENGTH', 'validate' => 'int', 'type' => 'custom', 'method' => 'username_length', 'explain' => true), + 'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int', 'type' => 'custom', 'method' => 'password_length', 'explain' => true), + 'allow_name_chars' => array('lang' => 'USERNAME_CHARS', 'validate' => 'string', 'type' => 'select', 'method' => 'select_username_chars', 'explain' => true), + 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), + 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => true), 'legend2' => 'GENERAL_OPTIONS', - 'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'type' => 'radio:yes_no', 'explain' => false), - 'allow_emailreuse' => array('lang' => 'ALLOW_EMAIL_REUSE', 'type' => 'radio:yes_no', 'explain' => true), - 'enable_confirm' => array('lang' => 'VISUAL_CONFIRM_REG', 'type' => 'radio:yes_no', 'explain' => true), - 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'type' => 'text:3:3', 'explain' => true), - 'max_reg_attempts' => array('lang' => 'REG_LIMIT', 'type' => 'text:4:4', 'explain' => true), + 'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_emailreuse' => array('lang' => 'ALLOW_EMAIL_REUSE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'enable_confirm' => array('lang' => 'VISUAL_CONFIRM_REG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => true), + 'max_reg_attempts' => array('lang' => 'REG_LIMIT', 'validate' => 'int', 'type' => 'text:4:4', 'explain' => true), 'legend3' => 'COPPA', - 'coppa_enable' => array('lang' => 'ENABLE_COPPA', 'type' => 'radio:yes_no', 'explain' => true), - 'coppa_mail' => array('lang' => 'COPPA_MAIL', 'type' => 'textarea:5:40', 'explain' => true), - 'coppa_fax' => array('lang' => 'COPPA_FAX', 'type' => 'text:25:100', 'explain' => false), + 'coppa_enable' => array('lang' => 'ENABLE_COPPA', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'coppa_mail' => array('lang' => 'COPPA_MAIL', 'validate' => 'string', 'type' => 'textarea:5:40', 'explain' => true), + 'coppa_fax' => array('lang' => 'COPPA_FAX', 'validate' => 'string', 'type' => 'text:25:100', 'explain' => false), ) ); break; @@ -220,10 +219,10 @@ class acp_board 'title' => 'ACP_COOKIE_SETTINGS', 'vars' => array( 'legend1' => 'ACP_COOKIE_SETTINGS', - 'cookie_domain' => array('lang' => 'COOKIE_DOMAIN', 'type' => 'text::255', 'explain' => false), - 'cookie_name' => array('lang' => 'COOKIE_NAME', 'type' => 'text::16', 'explain' => false), - 'cookie_path' => array('lang' => 'COOKIE_PATH', 'type' => 'text::255', 'explain' => false), - 'cookie_secure' => array('lang' => 'COOKIE_SECURE', 'type' => 'radio:disabled_enabled', 'explain' => true) + 'cookie_domain' => array('lang' => 'COOKIE_DOMAIN', 'validate' => 'string', 'type' => 'text::255', 'explain' => false), + 'cookie_name' => array('lang' => 'COOKIE_NAME', 'validate' => 'string', 'type' => 'text::16', 'explain' => false), + 'cookie_path' => array('lang' => 'COOKIE_PATH', 'validate' => 'string', 'type' => 'text::255', 'explain' => false), + 'cookie_secure' => array('lang' => 'COOKIE_SECURE', 'validate' => 'bool', 'type' => 'radio:disabled_enabled', 'explain' => true) ) ); break; @@ -233,28 +232,28 @@ class acp_board 'title' => 'ACP_LOAD_SETTINGS', 'vars' => array( 'legend1' => 'GENERAL_SETTINGS', - 'limit_load' => array('lang' => 'LIMIT_LOAD', 'type' => 'text:4:4', 'explain' => true), - 'session_length' => array('lang' => 'SESSION_LENGTH', 'type' => 'text:5:5', 'explain' => true), - 'active_sessions' => array('lang' => 'LIMIT_SESSIONS', 'type' => 'text:4:4', 'explain' => true), - 'load_online_time' => array('lang' => 'ONLINE_LENGTH', 'type' => 'text:4:3', 'explain' => true), + 'limit_load' => array('lang' => 'LIMIT_LOAD', 'validate' => 'int', 'type' => 'text:4:4', 'explain' => true), + 'session_length' => array('lang' => 'SESSION_LENGTH', 'validate' => 'int', 'type' => 'text:5:5', 'explain' => true), + 'active_sessions' => array('lang' => 'LIMIT_SESSIONS', 'validate' => 'int', 'type' => 'text:4:4', 'explain' => true), + 'load_online_time' => array('lang' => 'ONLINE_LENGTH', 'validate' => 'int', 'type' => 'text:4:3', 'explain' => true), 'legend2' => 'GENERAL_OPTIONS', - 'load_db_track' => array('lang' => 'YES_POST_MARKING', 'type' => 'radio:yes_no', 'explain' => true), - 'load_db_lastread' => array('lang' => 'YES_READ_MARKING', 'type' => 'radio:yes_no', 'explain' => true), - 'load_anon_lastread' => array('lang' => 'YES_ANON_READ_MARKING', 'type' => 'radio:yes_no', 'explain' => true), - 'load_online' => array('lang' => 'YES_ONLINE', 'type' => 'radio:yes_no', 'explain' => true), - 'load_online_guests' => array('lang' => 'YES_ONLINE_GUESTS', 'type' => 'radio:yes_no', 'explain' => true), - 'load_onlinetrack' => array('lang' => 'YES_ONLINE_TRACK', 'type' => 'radio:yes_no', 'explain' => true), - 'load_birthdays' => array('lang' => 'YES_BIRTHDAYS', 'type' => 'radio:yes_no', 'explain' => false), - 'load_moderators' => array('lang' => 'YES_MODERATORS', 'type' => 'radio:yes_no', 'explain' => false), - 'load_jumpbox' => array('lang' => 'YES_JUMPBOX', 'type' => 'radio:yes_no', 'explain' => false), - 'load_user_activity' => array('lang' => 'LOAD_USER_ACTIVITY', 'type' => 'radio:yes_no', 'explain' => true), - 'load_tplcompile' => array('lang' => 'RECOMPILE_TEMPLATES', 'type' => 'radio:yes_no', 'explain' => true), + 'load_db_track' => array('lang' => 'YES_POST_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'load_db_lastread' => array('lang' => 'YES_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'load_anon_lastread' => array('lang' => 'YES_ANON_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'load_online' => array('lang' => 'YES_ONLINE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + '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' => 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), + 'load_tplcompile' => array('lang' => 'RECOMPILE_TEMPLATES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend3' => 'CUSTOM_PROFILE_FIELDS', - 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'type' => 'radio:yes_no', 'explain' => false), - 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'type' => 'radio:yes_no', 'explain' => false), + 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), ) ); break; @@ -264,7 +263,7 @@ class acp_board 'title' => 'ACP_AUTH_SETTINGS', 'vars' => array( 'legend1' => 'ACP_AUTH_SETTINGS', - 'auth_method' => array('lang' => 'AUTH_METHOD', 'type' => 'select', 'method' => 'select_auth_method', 'explain' => false) + 'auth_method' => array('lang' => 'AUTH_METHOD', 'validate' => 'string', 'type' => 'select', 'method' => 'select_auth_method', 'explain' => false) ) ); break; @@ -274,20 +273,20 @@ class acp_board 'title' => 'ACP_SERVER_SETTINGS', 'vars' => array( 'legend1' => 'ACP_SERVER_SETTINGS', - 'send_encoding' => array('lang' => 'SEND_ENCODING', 'type' => 'radio:yes_no', 'explain' => true), - 'gzip_compress' => array('lang' => 'ENABLE_GZIP', 'type' => 'radio:yes_no', 'explain' => false), + 'send_encoding' => array('lang' => 'SEND_ENCODING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'gzip_compress' => array('lang' => 'ENABLE_GZIP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'legend2' => 'PATH_SETTINGS', - 'smilies_path' => array('lang' => 'SMILIES_PATH', 'type' => 'text:20:255', 'explain' => true), - 'icons_path' => array('lang' => 'ICONS_PATH', 'type' => 'text:20:255', 'explain' => true), - 'upload_icons_path' => array('lang' => 'UPLOAD_ICONS_PATH', 'type' => 'text:20:255', 'explain' => true), - 'ranks_path' => array('lang' => 'RANKS_PATH', 'type' => 'text:20:255', 'explain' => true), + 'smilies_path' => array('lang' => 'SMILIES_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), + 'icons_path' => array('lang' => 'ICONS_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), + 'upload_icons_path' => array('lang' => 'UPLOAD_ICONS_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), + 'ranks_path' => array('lang' => 'RANKS_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true), 'legend3' => 'SERVER_URL_SETTINGS', - 'force_server_vars' => array('lang' => 'FORCE_SERVER_VARS', 'type' => 'radio:yes_no', 'explain' => true), - 'server_protocol' => array('lang' => 'SERVER_PROTOCOL', 'type' => 'text:10:10', 'explain' => true), - 'server_name' => array('lang' => 'SERVER_NAME', 'type' => 'text:40:255', 'explain' => true), - 'server_port' => array('lang' => 'SERVER_PORT', 'type' => 'text:5:5', 'explain' => true), + 'force_server_vars' => array('lang' => 'FORCE_SERVER_VARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'server_protocol' => array('lang' => 'SERVER_PROTOCOL', 'validate' => 'string', 'type' => 'text:10:10', 'explain' => true), + 'server_name' => array('lang' => 'SERVER_NAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true), + 'server_port' => array('lang' => 'SERVER_PORT', 'validate' => 'int', 'type' => 'text:5:5', 'explain' => true), ) ); break; @@ -297,14 +296,16 @@ class acp_board 'title' => 'ACP_SECURITY_SETTINGS', 'vars' => array( 'legend1' => 'ACP_SECURITY_SETTINGS', - 'allow_autologin' => array('lang' => 'ALLOW_AUTOLOGIN', 'type' => 'radio:yes_no', 'explain' => true), - 'max_autologin_time' => array('lang' => 'AUTOLOGIN_LENGTH', 'type' => 'text:5:5', 'explain' => true), - 'ip_check' => array('lang' => 'IP_VALID', 'type' => 'custom', 'method' => 'select_ip_check', 'explain' => true), - 'browser_check' => array('lang' => 'BROWSER_VALID', 'type' => 'radio:yes_no', 'explain' => true), - 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), - 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'type' => 'text:3:3', 'explain' => true), - 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'type' => 'text:3:3', 'explain' => true), - 'tpl_allow_php' => array('lang' => 'TPL_ALLOW_PHP', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_autologin' => array('lang' => 'ALLOW_AUTOLOGIN', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'max_autologin_time' => array('lang' => 'AUTOLOGIN_LENGTH', 'validate' => 'int', 'type' => 'text:5:5', 'explain' => true), + 'ip_check' => array('lang' => 'IP_VALID', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_ip_check', 'explain' => true), + 'browser_check' => array('lang' => 'BROWSER_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'check_dnsbl' => array('lang' => 'CHECK_DNSBL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'email_check_mx' => array('lang' => 'EMAIL_CHECK_MX', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), + 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => true), + 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => true), + 'tpl_allow_php' => array('lang' => 'TPL_ALLOW_PHP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), ) ); break; @@ -314,28 +315,29 @@ class acp_board 'title' => 'ACP_EMAIL_SETTINGS', 'vars' => array( 'legend1' => 'GENERAL_SETTINGS', - 'email_enable' => array('lang' => 'ENABLE_EMAIL', 'type' => 'radio:enabled_disabled', 'explain' => true), - 'board_email_form' => array('lang' => 'BOARD_EMAIL_FORM', 'type' => 'radio:enabled_disabled', 'explain' => true), - 'email_function_name' => array('lang' => 'EMAIL_FUNCTION_NAME', 'type' => 'text:20:50', 'explain' => true), - 'email_package_size' => array('lang' => 'EMAIL_PACKAGE_SIZE', 'type' => 'text:5:5', 'explain' => true), - 'board_contact' => array('lang' => 'CONTACT_EMAIL', 'type' => 'text:25:100', 'explain' => true), - 'board_email' => array('lang' => 'ADMIN_EMAIL', 'type' => 'text:25:100', 'explain' => true), - 'board_email_sig' => array('lang' => 'EMAIL_SIG', 'type' => 'textarea:5:30', 'explain' => true), - 'board_hide_emails' => array('lang' => 'BOARD_HIDE_EMAILS', 'type' => 'radio:yes_no', 'explain' => true), + 'email_enable' => array('lang' => 'ENABLE_EMAIL', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), + 'board_email_form' => array('lang' => 'BOARD_EMAIL_FORM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), + 'email_function_name' => array('lang' => 'EMAIL_FUNCTION_NAME', 'validate' => 'string', 'type' => 'text:20:50', 'explain' => true), + 'email_package_size' => array('lang' => 'EMAIL_PACKAGE_SIZE', 'validate' => 'int', 'type' => 'text:5:5', 'explain' => true), + 'board_contact' => array('lang' => 'CONTACT_EMAIL', 'validate' => 'string', 'type' => 'text:25:100', 'explain' => true), + 'board_email' => array('lang' => 'ADMIN_EMAIL', 'validate' => 'string', 'type' => 'text:25:100', 'explain' => true), + 'board_email_sig' => array('lang' => 'EMAIL_SIG', 'validate' => 'string', 'type' => 'textarea:5:30', 'explain' => true), + 'board_hide_emails' => array('lang' => 'BOARD_HIDE_EMAILS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'legend2' => 'SMTP_SETTINGS', - 'smtp_delivery' => array('lang' => 'USE_SMTP', 'type' => 'radio:yes_no', 'explain' => true), - 'smtp_host' => array('lang' => 'SMTP_SERVER', 'type' => 'text:25:50', 'explain' => false), - 'smtp_port' => array('lang' => 'SMTP_PORT', 'type' => 'text:4:5', 'explain' => true), - 'smtp_auth_method' => array('lang' => 'SMTP_AUTH_METHOD', 'type' => 'select', 'method' => 'mail_auth_select', 'explain' => true), - 'smtp_username' => array('lang' => 'SMTP_USERNAME', 'type' => 'text:25:255', 'explain' => true), - 'smtp_password' => array('lang' => 'SMTP_PASSWORD', 'type' => 'password:25:255', 'explain' => true) + 'smtp_delivery' => array('lang' => 'USE_SMTP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'smtp_host' => array('lang' => 'SMTP_SERVER', 'validate' => 'string', 'type' => 'text:25:50', 'explain' => false), + 'smtp_port' => array('lang' => 'SMTP_PORT', 'validate' => 'int', 'type' => 'text:4:5', 'explain' => true), + 'smtp_auth_method' => array('lang' => 'SMTP_AUTH_METHOD', 'validate' => 'string', 'type' => 'select', 'method' => 'mail_auth_select', 'explain' => true), + 'smtp_username' => array('lang' => 'SMTP_USERNAME', 'validate' => 'string', 'type' => 'text:25:255', 'explain' => true), + 'smtp_password' => array('lang' => 'SMTP_PASSWORD', 'validate' => 'string', 'type' => 'password:25:255', 'explain' => true) ) ); break; default: - trigger_error('NO_MODE'); + trigger_error('NO_MODE', E_USER_ERROR); + break; } if (isset($display_vars['lang'])) @@ -345,6 +347,20 @@ class acp_board $this->new_config = $config; $cfg_array = (isset($_REQUEST['config'])) ? request_var('config', array('' => ''), true) : $this->new_config; + if (isset($_REQUEST['config'])) + { + utf8_normalize_nfc(&$cfg_array); + } + $error = array(); + + // We validate the complete config if whished + validate_config_vars($display_vars['vars'], $cfg_array, $error); + + // Do not write values if there is an error + if (sizeof($error)) + { + $submit = false; + } // We go through the display_vars to make sure no one is trying to set variables he/she is not allowed to... foreach ($display_vars['vars'] as $config_name => $null) @@ -448,14 +464,14 @@ class acp_board { set_config($config_name, $config_value); } - trigger_error($error . adm_back_link($this->u_action)); + trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING); } } set_config('auth_method', $cfg_array['auth_method']); } else { - trigger_error('NO_AUTH_PLUGIN'); + trigger_error('NO_AUTH_PLUGIN', E_USER_ERROR); } } } @@ -473,6 +489,10 @@ class acp_board $template->assign_vars(array( 'L_TITLE' => $user->lang[$display_vars['title']], 'L_TITLE_EXPLAIN' => $user->lang[$display_vars['title'] . '_EXPLAIN'], + + 'S_ERROR' => (sizeof($error)) ? true : false, + 'ERROR_MSG' => implode('<br />', $error), + 'U_ACTION' => $this->u_action) ); diff --git a/phpBB/includes/acp/acp_bots.php b/phpBB/includes/acp/acp_bots.php index f24a6b7b12..2dbcc463e9 100644 --- a/phpBB/includes/acp/acp_bots.php +++ b/phpBB/includes/acp/acp_bots.php @@ -142,6 +142,12 @@ class acp_bots } $bot_row['bot_ip'] = str_replace(' ', '', $bot_row['bot_ip']); + // Make sure the admin is not adding a bot with an user agent similar to his one + if ($bot_row['bot_agent'] && substr($user->data['session_browser'], 0, 149) === substr($bot_row['bot_agent'], 0, 149)) + { + $error[] = $user->lang['ERR_BOT_AGENT_MATCHES_UA']; + } + if (!sizeof($error)) { $db->sql_transaction('begin'); @@ -159,7 +165,7 @@ class acp_bots if (!$group_row) { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . "&id=$bot_id&action=$action")); + trigger_error($user->lang['NO_BOT_GROUP'] . adm_back_link($this->u_action . "&id=$bot_id&action=$action"), E_USER_WARNING); } $user_id = user_add(array( @@ -197,7 +203,7 @@ class acp_bots if (!$row) { - trigger_error($user->lang['NO_BOT'] . adm_back_link($this->u_action . "&id=$bot_id&action=$action")); + trigger_error($user->lang['NO_BOT'] . adm_back_link($this->u_action . "&id=$bot_id&action=$action"), E_USER_WARNING); } $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( @@ -237,7 +243,7 @@ class acp_bots if (!$bot_row) { - trigger_error($user->lang['NO_BOT'] . adm_back_link($this->u_action . "&id=$bot_id&action=$action")); + trigger_error($user->lang['NO_BOT'] . adm_back_link($this->u_action . "&id=$bot_id&action=$action"), E_USER_WARNING); } $bot_row['bot_lang'] = $bot_row['user_lang']; diff --git a/phpBB/includes/acp/acp_captcha.php b/phpBB/includes/acp/acp_captcha.php index 3ac354004a..7cef658e93 100644 --- a/phpBB/includes/acp/acp_captcha.php +++ b/phpBB/includes/acp/acp_captcha.php @@ -21,91 +21,37 @@ class acp_captcha $user->add_lang('acp/board'); - $config_vars = array('enable_confirm' => 'REG_ENABLE', - 'enable_post_confirm' => 'POST_ENABLE', - 'policy_overlap' => 'OVERLAP_ENABLE', - 'policy_overlap_noise_pixel' => 'OVERLAP_NOISE_PIXEL', - 'policy_overlap_noise_line' => 'OVERLAP_NOISE_LINE_ENABLE', - 'policy_entropy' => 'ENTROPY_ENABLE', - 'policy_entropy_noise_pixel' => 'ENTROPY_NOISE_PIXEL', - 'policy_entropy_noise_line' => 'ENTROPY_NOISE_LINE_ENABLE', - 'policy_shape' => 'SHAPE_ENABLE', - 'policy_shape_noise_pixel' => 'SHAPE_NOISE_PIXEL', - 'policy_shape_noise_line' => 'SHAPE_NOISE_LINE_ENABLE', - 'policy_3dbitmap' => 'THREEDBITMAP_ENABLE', - 'policy_cells' => 'CELLS_ENABLE', - 'policy_stencil' => 'STENCIL_ENABLE', - 'policy_composite' => 'COMPOSITE_ENABLE' - ); - - $policy_modules = array('policy_entropy', 'policy_3dbitmap', 'policy_overlap', 'policy_shape', 'policy_cells', 'policy_stencil', 'policy_composite'); - - switch ($mode) + $config_vars = array( + 'enable_confirm' => 'REG_ENABLE', + 'enable_post_confirm' => 'POST_ENABLE', + 'captcha_gd' => 'CAPTCHA_GD', + 'captcha_gd_noise' => 'CAPTCHA_GD_NOISE', + ); + + $this->tpl_name = 'acp_captcha'; + $this->page_title = 'ACP_VC_SETTINGS'; + $submit = request_var('submit', ''); + if ($submit) { - case 'visual': - $this->tpl_name = 'acp_captcha'; - $this->page_title = 'ACP_VC_SETTINGS'; - $submit = request_var('submit', ''); - if ($submit) - { - $config_vars = array_keys($config_vars); - foreach ($config_vars as $config_var) - { - set_config($config_var, request_var($config_var, '')); - } - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); - } - else - { - $array = array(); - - foreach ($config_vars as $config_var => $template_var) - { - $array[$template_var] = $config[$config_var]; - } - $template->assign_vars($array); - - - if (@extension_loaded('gd')) - { - $template->assign_var('GD', true); - foreach ($policy_modules as $module_name) - { - $template->assign_var('U_' . strtoupper($module_name), sprintf($user->lang['CAPTCHA_EXPLAIN'], '<a href="' . append_sid("{$phpbb_root_path}adm/index.$phpEx", 'i=captcha&mode=img&policy=' . $module_name) . '" target="_blank">', '</a>')); - } - if (function_exists('imagettfbbox') && function_exists('imagettftext')) - { - $template->assign_var('TTF', true); - } - } - } - break; - - case 'img': - $policy = request_var('policy', ''); - - if (!@extension_loaded('gd')) - { - trigger_error($user->lang['NO_GD']); - } - - if (!($policy === 'policy_entropy' || $policy === 'policy_3dbitmap') && (!function_exists('imagettfbbox') || !function_exists('imagettftext'))) - { - trigger_error($user->lang['NO_TTF']); - } - - if (!in_array($policy, $policy_modules)) - { - trigger_error($user->lang['BAD_POLICY']); - } - - $user->add_lang('ucp'); - - include($phpbb_root_path . 'includes/captcha/captcha_gd.' . $phpEx); - - $captcha = new captcha(); - $captcha->execute(gen_rand_string(), $policy); - break; + $config_vars = array_keys($config_vars); + foreach ($config_vars as $config_var) + { + set_config($config_var, request_var($config_var, '')); + } + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); + } + else + { + $array = array(); + + if (@extension_loaded('gd') && function_exists('imagettfbbox') && function_exists('imagettftext')) + { + $template->assign_var('GD', true); + } + foreach ($config_vars as $config_var => $template_var) + { + $template->assign_var($template_var, $config[$config_var]); + } } } } diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php index 59ccb342fd..cbd654fbcc 100644 --- a/phpBB/includes/acp/acp_database.php +++ b/phpBB/includes/acp/acp_database.php @@ -68,7 +68,9 @@ class acp_database @set_time_limit(1200); - $filename = 'backup_' . time(); + $time = time(); + + $filename = 'backup_' . $time; // We set up the info needed for our on-the-fly creation :D switch ($format) @@ -111,7 +113,7 @@ class acp_database if (!$fp) { - trigger_error('Unable to write temporary file to storage folder'); + trigger_error('Unable to write temporary file to storage folder', E_USER_ERROR); } } @@ -128,10 +130,10 @@ class acp_database $sql_data .= "#\n"; $sql_data .= "# phpBB Backup Script\n"; $sql_data .= "# Dump of tables for $table_prefix\n"; - $sql_data .= "# DATE : " . gmdate("d-m-Y H:i:s", $filename) . " GMT\n"; + $sql_data .= "# DATE : " . gmdate("d-m-Y H:i:s", $time) . " GMT\n"; $sql_data .= "#\n"; - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'sqlite': $sql_data .= "BEGIN TRANSACTION;\n"; @@ -149,12 +151,37 @@ class acp_database break; } + if ($structure && $db->sql_layer == 'firebird') + { + $sql = 'SELECT RDB$FUNCTION_NAME, RDB$DESCRIPTION + FROM RDB$FUNCTIONS + ORDER BY RDB$FUNCTION_NAME'; + $result = $db->sql_query($sql); + + $rows = array(); + while ($row = $db->sql_fetchrow($result)) + { + $sql = 'SELECT F.RDB$FUNCTION_NAME, F.RDB$MODULE_NAME, F.RDB$ENTRYPOINT, F.RDB$RETURN_ARGUMENT, F.RDB$DESCRIPTION, FA.RDB$ARGUMENT_POSITION, FA.RDB$MECHANISM, FA.RDB$FIELD_TYPE, FA.RDB$FIELD_SCALE, FA.RDB$FIELD_LENGTH, FA.RDB$FIELD_SUB_TYPE, C.RDB$BYTES_PER_CHARACTER, C.RDB$CHARACTER_SET_NAME ,FA.RDB$FIELD_PRECISION + FROM RDB$FUNCTIONS F + LEFT JOIN RDB$FUNCTION_ARGUMENTS FA ON F.RDB$FUNCTION_NAME = FA.RDB$FUNCTION_NAME + LEFT JOIN RDB$CHARACTER_SETS C ON FA.RDB$CHARACTER_SET_ID = C.RDB$CHARACTER_SET_ID + WHERE (F.RDB$FUNCTION_NAME = ' . $row['FUNCTION_NAME'] . ') + ORDER BY FA.RDB$ARGUMENT_POSITION'; + $result2 = $db->sql_query($sql); + while ($row2 = $db->sql_fetchrow($result2)) + { + } + $db->sql_freeresult($result2); + } + $db->sql_freeresult($result); + } + foreach ($table as $table_name) { // Get the table structure if ($structure) { - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'mysqli': case 'mysql4': @@ -197,27 +224,12 @@ class acp_database } $sql_data .= $this->get_table_structure($table_name); } - // We might wanna empty out all that junk :D else { - switch (SQL_LAYER) - { - case 'mysqli': - case 'mysql4': - case 'mysql': - case 'mssql': - case 'mssql_odbc': - case 'oracle': - case 'postgres': - case 'firebird': - $sql_data .= 'TRUNCATE TABLE ' . $table_name . ";\n"; - break; - - case 'sqlite': - $sql_data .= 'DELETE FROM ' . $table_name . ";\n"; - break; - } + // We might wanna empty out all that junk :D + $sql_data .= (($db->sql_layer == 'sqlite') ? 'DELETE FROM ' : 'TRUNCATE TABLE ') . $table_name . ";\n"; } + // Now write the data for the first time. :) if ($store == true) { @@ -243,7 +255,7 @@ class acp_database { $sql_data .= "\n"; - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'mysqli': @@ -263,8 +275,8 @@ class acp_database $field_set[$j] = $field[$j]->name; } - $search = array('\\', "'", "\x00", "\x0a", "\x0d", "\x1a"); - $replace = array('\\\\\\\\', "''", '\0', '\n', '\r', '\Z'); + $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"'); + $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"'); $fields = implode(', ', $field_set); $values = array(); $schema_insert = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ('; @@ -336,8 +348,8 @@ class acp_database $field_set[$j] = $field[$j]->name; } - $search = array('\\', "'", "\x00", "\x0a", "\x0d", "\x1a"); - $replace = array('\\\\\\\\', "''", '\0', '\n', '\r', '\Z'); + $search = array("\\", "'", "\x00", "\x0a", "\x0d", "\x1a", '"'); + $replace = array("\\\\", "\\'", '\0', '\n', '\r', '\Z', '\\"'); $fields = implode(', ', $field_set); $schema_insert = 'INSERT INTO ' . $table_name . ' (' . $fields . ') VALUES ('; @@ -406,7 +418,7 @@ class acp_database $column_list = array(); $table_cols = explode(',', trim($matches[1])); - foreach($table_cols as $declaration) + foreach ($table_cols as $declaration) { $entities = preg_split('#\s+#', trim($declaration)); $column_name = preg_replace('/"?([^"]+)"?/', '\1', $entities[0]); @@ -442,7 +454,7 @@ class acp_database { $row_data = "''"; } - else if (strpos($col_types[$row_name], 'text') !== false || strpos($col_types[$row_name], 'char') !== false) + else if (strpos($col_types[$row_name], 'text') !== false || strpos($col_types[$row_name], 'char') !== false || strpos($col_types[$row_name], 'blob') !== false) { $row_data = "'" . $row_data . "'"; } @@ -516,7 +528,7 @@ class acp_database { $str_val = $row[$ary_name[$i]]; - if (preg_match('#char|text|bool#i', $ary_type[$i])) + if (preg_match('#char|text|bool|bytea#i', $ary_type[$i])) { $str_quote = "'"; $str_empty = ''; @@ -637,7 +649,7 @@ class acp_database { $str_val = $row[$ary_name[$i]]; - if (preg_match('#char|text|bool#i', $ary_type[$i])) + if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i])) { $str_quote = "'"; $str_empty = ''; @@ -748,7 +760,7 @@ class acp_database { $str_val = $row[$ary_name[$i]]; - if (preg_match('#char|text|bool#i', $ary_type[$i])) + if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i])) { $str_quote = "'"; $str_empty = ''; @@ -843,7 +855,7 @@ class acp_database { $str_val = $row[strtolower($ary_name[$i])]; - if (preg_match('#char|text|bool#i', $ary_type[$i])) + if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i])) { $str_quote = "'"; $str_empty = ''; @@ -927,7 +939,7 @@ class acp_database { $str_val = $row[$ary_name[$i]]; - if (preg_match('#char|text|bool#i', $ary_type[$i])) + if (preg_match('#char|text|bool|raw#i', $ary_type[$i])) { $str_quote = "'"; $str_empty = ''; @@ -989,7 +1001,7 @@ class acp_database } } - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'sqlite': case 'postgres': @@ -1024,12 +1036,12 @@ class acp_database unset($sql_data); add_log('admin', 'LOG_DB_BACKUP'); - trigger_error($user->lang['BACKUP_SUCCESS']); + trigger_error($user->lang['BACKUP_SUCCESS'] . adm_back_link($this->u_action)); break; default: $tables = array(); - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'sqlite': $sql = "SELECT name @@ -1167,13 +1179,13 @@ class acp_database if (!(file_exists($file_name) && is_readable($file_name))) { - trigger_error($user->lang['BACKUP_INVALID']); + trigger_error($user->lang['BACKUP_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING); } if ($delete) { unlink($file_name); - trigger_error($user->lang['BACKUP_DELETE']); + trigger_error($user->lang['BACKUP_DELETE'] . adm_back_link($this->u_action)); } $data = file_get_contents($file_name); @@ -1220,13 +1232,13 @@ class acp_database remove_remarks($data); // SQLite gets improved performance when you shove all of these disk write queries at once :D - if (SQL_LAYER == 'sqlite') + if ($db->sql_layer == 'sqlite') { $db->sql_query($data); } else { - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'firebird': $delim = ';;'; @@ -1263,7 +1275,7 @@ class acp_database } } add_log('admin', 'LOG_DB_RESTORE'); - trigger_error($user->lang['RESTORE_SUCCESS']); + trigger_error($user->lang['RESTORE_SUCCESS'] . adm_back_link($this->u_action)); break; default: @@ -1324,7 +1336,7 @@ class acp_database $sql_data = ''; - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'mysqli': case 'mysql4': @@ -1370,11 +1382,22 @@ class acp_database { $kname = $row['Key_name']; - if ($kname != 'PRIMARY' && $row['Non_unique'] == 0) + if ($kname != 'PRIMARY') { - $kname = "UNIQUE|$kname"; + if ($row['Index_type'] == 'FULLTEXT') + { + $kname = "FULLTEXT|$kname"; + } + else if ($row['Non_unique'] == 0) + { + $kname = "UNIQUE|$kname"; + } } + if ($row['Sub_part']) + { + $row['Column_name'] .= '(' . $row['Sub_part'] . ')'; + } $index[$kname][] = $row['Column_name']; } $db->sql_freeresult($result); @@ -1391,6 +1414,10 @@ class acp_database { $line .= 'UNIQUE ' . substr($key, 7) . ' (' . implode(', ', $columns) . ')'; } + else if (strpos($key, 'FULLTEXT') === 0) + { + $line .= 'FULLTEXT ' . substr($key, 9) . ' (' . implode(', ', $columns) . ')'; + } else { $line .= "KEY $key (" . implode(', ', $columns) . ')'; diff --git a/phpBB/includes/acp/acp_disallow.php b/phpBB/includes/acp/acp_disallow.php index 1fdc2f8551..adb7270332 100644 --- a/phpBB/includes/acp/acp_disallow.php +++ b/phpBB/includes/acp/acp_disallow.php @@ -37,12 +37,14 @@ class acp_disallow if (!$disallowed_user) { - trigger_error($user->lang['NO_USERNAME_SPECIFIED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_USERNAME_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'INSERT INTO ' . DISALLOW_TABLE . ' ' . $db->sql_build_array('INSERT', array('disallow_username' => $disallowed_user)); $db->sql_query($sql); + $cache->destroy('disallowed_usernames'); + $message = $user->lang['DISALLOW_SUCCESSFUL']; add_log('admin', 'LOG_DISALLOW_ADD', str_replace('%', '*', $disallowed_user)); @@ -54,16 +56,18 @@ class acp_disallow if (!$disallowed_id) { - trigger_error($user->lang['NO_USERNAME_SPECIFIED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_USERNAME_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); } - $sql = 'DELETE FROM ' . DISALLOW_TABLE . " - WHERE disallow_id = $disallowed_id"; + $sql = 'DELETE FROM ' . DISALLOW_TABLE . ' + WHERE disallow_id = ' . $disallowed_id; $db->sql_query($sql); + $cache->destroy('disallowed_usernames'); + add_log('admin', 'LOG_DISALLOW_DELETE'); - trigger_error($user->lang['DISALLOWED_DELETED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['DISALLOWED_DELETED'] . adm_back_link($this->u_action), E_USER_WARNING); } // Grab the current list of disallowed usernames... diff --git a/phpBB/includes/acp/acp_email.php b/phpBB/includes/acp/acp_email.php index c20640bd54..5b79451634 100644 --- a/phpBB/includes/acp/acp_email.php +++ b/phpBB/includes/acp/acp_email.php @@ -28,7 +28,7 @@ class acp_email $submit = (isset($_POST['submit'])) ? true : false; $error = array(); - $usernames = request_var('usernames', ''); + $usernames = request_var('usernames', '', true); $group_id = request_var('g', 0); $subject = request_var('subject', '', true); $message = request_var('message', '', true); @@ -57,7 +57,7 @@ class acp_email { $sql = 'SELECT username, user_email, user_jabber, user_notify_type, user_lang FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('username', explode("\n", $usernames)) . ' + WHERE ' . $db->sql_in_set('username_clean', array_map('utf8_clean_string', explode("\n", $usernames))) . ' AND user_allow_massemail = 1 ORDER BY user_lang, user_notify_type'; // , SUBSTRING(user_email FROM INSTR(user_email, '@')) } @@ -87,7 +87,7 @@ class acp_email if (!$row) { $db->sql_freeresult($result); - trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action), E_USER_WARNING); } $i = $j = 0; @@ -150,15 +150,13 @@ class acp_email $messenger->headers('X-AntiAbuse: Username - ' . $user->data['username']); $messenger->headers('X-AntiAbuse: User IP - ' . $user->ip); - $messenger->subject(html_entity_decode($subject)); + $messenger->subject(htmlspecialchars_decode($subject)); $messenger->replyto($config['board_email']); $messenger->set_mail_priority($priority); $messenger->assign_vars(array( - 'SITENAME' => $config['sitename'], 'CONTACT_EMAIL' => $config['board_contact'], - 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']), - 'MESSAGE' => html_entity_decode($message)) + 'MESSAGE' => htmlspecialchars_decode($message)) ); if (!($messenger->send($used_method))) @@ -185,12 +183,13 @@ class acp_email if (!$errored) { $message = ($use_queue) ? $user->lang['EMAIL_SENT_QUEUE'] : $user->lang['EMAIL_SENT']; + trigger_error($message . adm_back_link($this->u_action)); } else { $message = sprintf($user->lang['EMAIL_SEND_ERROR'], '<a href="' . append_sid("{$phpbb_admin_path}index.$phpEx", 'i=logs&mode=critical') . '">', '</a>'); + trigger_error($message . adm_back_link($this->u_action), E_USER_WARNING); } - trigger_error($message . adm_back_link($this->u_action)); } } @@ -216,6 +215,7 @@ class acp_email 'S_GROUP_OPTIONS' => $select_list, 'USERNAMES' => $usernames, 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=acp_email&field=usernames'), + 'UA_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=acp_email&field=usernames', false), 'SUBJECT' => $subject, 'MESSAGE' => $message, 'S_PRIORITY_OPTIONS' => $s_priority_options) diff --git a/phpBB/includes/acp/acp_forums.php b/phpBB/includes/acp/acp_forums.php index 5964a285e7..7f4dde7211 100644 --- a/phpBB/includes/acp/acp_forums.php +++ b/phpBB/includes/acp/acp_forums.php @@ -36,11 +36,19 @@ class acp_forums // Check additional permissions switch ($action) { + case 'progress_bar': + $start = request_var('start', 0); + $total = request_var('total', 0); + + $this->display_progress_bar($start, $total); + exit; + break; + case 'delete': if (!$auth->acl_get('a_forumdel')) { - trigger_error($user->lang['NO_PERMISSION_FORUM_DELETE'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); + trigger_error($user->lang['NO_PERMISSION_FORUM_DELETE'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } break; @@ -49,7 +57,7 @@ class acp_forums if (!$auth->acl_get('a_forumadd')) { - trigger_error($user->lang['NO_PERMISSION_FORUM_ADD'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); + trigger_error($user->lang['NO_PERMISSION_FORUM_ADD'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } break; @@ -94,23 +102,24 @@ class acp_forums 'forum_type' => request_var('forum_type', FORUM_POST), 'type_action' => request_var('type_action', ''), 'forum_status' => request_var('forum_status', ITEM_UNLOCKED), + 'forum_parents' => '', 'forum_name' => request_var('forum_name', '', true), 'forum_link' => request_var('forum_link', ''), 'forum_link_track' => request_var('forum_link_track', false), 'forum_desc' => request_var('forum_desc', '', true), 'forum_desc_uid' => '', - 'forum_desc_options' => 0, + 'forum_desc_options' => 7, 'forum_desc_bitfield' => '', 'forum_rules' => request_var('forum_rules', '', true), 'forum_rules_uid' => '', - 'forum_rules_options' => 0, + 'forum_rules_options' => 7, 'forum_rules_bitfield' => '', 'forum_rules_link' => request_var('forum_rules_link', ''), 'forum_image' => request_var('forum_image', ''), 'forum_style' => request_var('forum_style', 0), 'display_on_index' => request_var('display_on_index', false), 'forum_topics_per_page' => request_var('topics_per_page', 0), - 'enable_indexing' => request_var('enable_indexing',true), + 'enable_indexing' => request_var('enable_indexing', true), 'enable_icons' => request_var('enable_icons', false), 'enable_prune' => request_var('enable_prune', false), 'enable_post_review' => request_var('enable_post_review', true), @@ -202,34 +211,8 @@ class acp_forums $db->sql_freeresult($result); // Now insert the data - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - if (sizeof($users_sql_ary)) - { - $db->sql_query('INSERT INTO ' . ACL_USERS_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $users_sql_ary)); - } - - if (sizeof($groups_sql_ary)) - { - $db->sql_query('INSERT INTO ' . ACL_GROUPS_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $groups_sql_ary)); - } - break; - - default: - foreach ($users_sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . ACL_USERS_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - - foreach ($groups_sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . ACL_GROUPS_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } + $db->sql_multi_insert(ACL_USERS_TABLE, $users_sql_ary); + $db->sql_multi_insert(ACL_GROUPS_TABLE, $groups_sql_ary); } $auth->acl_clear_prefetch(); @@ -265,7 +248,7 @@ class acp_forums if (!$forum_id) { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); + trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } $sql = 'SELECT * @@ -277,7 +260,7 @@ class acp_forums if (!$row) { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); + trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } $move_forum_name = $this->move_forum_by($row, $action, 1); @@ -293,7 +276,7 @@ class acp_forums case 'sync': if (!$forum_id) { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); + trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } $sql = 'SELECT forum_name, forum_type @@ -305,10 +288,76 @@ class acp_forums if (!$row) { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); + trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); + } + + sync('forum', 'forum_id', $forum_id, false, true); + $cache->destroy('sql', FORUMS_TABLE); + + $url = $this->u_action . "&parent_id={$this->parent_id}&f=$forum_id&action=sync_topic"; + meta_refresh(0, $url); + + $sql = 'SELECT forum_topics_real + FROM ' . FORUMS_TABLE . " + WHERE forum_id = $forum_id"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + $template->assign_vars(array( + 'U_PROGRESS_BAR' => $this->u_action . '&action=progress_bar', + 'UA_PROGRESS_BAR' => str_replace('&', '&', $this->u_action) . '&action=progress_bar', + 'S_CONTINUE_SYNC' => true, + 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], 0, $row['forum_topics_real'])) + ); + +// add_log('admin', 'LOG_FORUM_SYNC', $row['forum_name']); + + return; + + break; + + case 'sync_topic': + + @set_time_limit(0); + + $sql = 'SELECT forum_name, forum_topics_real + FROM ' . FORUMS_TABLE . " + WHERE forum_id = $forum_id"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if ($row['forum_topics_real']) + { + $start = request_var('start', 0); + + $batch_size = 3000; + $end = $start + $batch_size; + + // Sync all topics in batch mode... + sync('topic_approved', 'range', 'topic_id BETWEEN ' . $start . ' AND ' . $end, true, false); + sync('topic', 'range', 'topic_id BETWEEN ' . $start . ' AND ' . $end, true, true); + + if ($end < $row['forum_topics_real']) + { + $start += $batch_size; + + $url = $this->u_action . "&parent_id={$this->parent_id}&f=$forum_id&action=sync_topic&start=$start&total={$row['forum_topics_real']}"; + + meta_refresh(0, $url); + + $template->assign_vars(array( + 'U_PROGRESS_BAR' => $this->u_action . "&action=progress_bar&start=$start&total={$row['forum_topics_real']}", + 'UA_PROGRESS_BAR' => str_replace('&', '&', $this->u_action) . "&action=progress_bar&start=$start&total={$row['forum_topics_real']}", + 'S_CONTINUE_SYNC' => true, + 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $start, $row['forum_topics_real'])) + ); + + return; + } } - sync('forum', 'forum_id', $forum_id); add_log('admin', 'LOG_FORUM_SYNC', $row['forum_name']); $cache->destroy('sql', FORUMS_TABLE); @@ -322,12 +371,12 @@ class acp_forums if ($update) { $forum_data['forum_flags'] = 0; - $forum_data['forum_flags'] += (request_var('forum_link_track', false)) ? 1 : 0; - $forum_data['forum_flags'] += (request_var('prune_old_polls', false)) ? 2 : 0; - $forum_data['forum_flags'] += (request_var('prune_announce', false)) ? 4 : 0; - $forum_data['forum_flags'] += (request_var('prune_sticky', false)) ? 8 : 0; - $forum_data['forum_flags'] += ($forum_data['show_active']) ? 16 : 0; - $forum_data['forum_flags'] += (request_var('enable_post_review', true)) ? 32 : 0; + $forum_data['forum_flags'] += (request_var('forum_link_track', false)) ? FORUM_FLAG_LINK_TRACK : 0; + $forum_data['forum_flags'] += (request_var('prune_old_polls', false)) ? FORUM_FLAG_PRUNE_POLL : 0; + $forum_data['forum_flags'] += (request_var('prune_announce', false)) ? FORUM_FLAG_PRUNE_ANNOUNCE : 0; + $forum_data['forum_flags'] += (request_var('prune_sticky', false)) ? FORUM_FLAG_PRUNE_STICKY : 0; + $forum_data['forum_flags'] += ($forum_data['show_active']) ? FORUM_FLAG_ACTIVE_TOPICS : 0; + $forum_data['forum_flags'] += (request_var('enable_post_review', true)) ? FORUM_FLAG_POST_REVIEW : 0; } // Show form to create/modify a forum @@ -389,7 +438,7 @@ class acp_forums 'prune_days' => 7, 'prune_viewed' => 7, 'prune_freq' => 1, - 'forum_flags' => 0, + 'forum_flags' => FORUM_FLAG_POST_REVIEW, 'forum_password' => '', 'forum_password_confirm'=> '', ); @@ -543,12 +592,12 @@ class acp_forums 'S_TOPIC_ICONS' => ($forum_data['enable_icons']) ? true : false, 'S_DISPLAY_ON_INDEX' => ($forum_data['display_on_index']) ? true : false, 'S_PRUNE_ENABLE' => ($forum_data['enable_prune']) ? true : false, - 'S_FORUM_LINK_TRACK' => ($forum_data['forum_flags'] & 1) ? true : false, - 'S_PRUNE_OLD_POLLS' => ($forum_data['forum_flags'] & 2) ? true : false, - 'S_PRUNE_ANNOUNCE' => ($forum_data['forum_flags'] & 4) ? true : false, - 'S_PRUNE_STICKY' => ($forum_data['forum_flags'] & 8) ? true : false, - 'S_DISPLAY_ACTIVE_TOPICS' => ($forum_data['forum_flags'] & 16) ? true : false, - 'S_ENABLE_POST_REVIEW' => ($forum_data['forum_flags'] & 32) ? true : false, + 'S_FORUM_LINK_TRACK' => ($forum_data['forum_flags'] & FORUM_FLAG_LINK_TRACK) ? true : false, + 'S_PRUNE_OLD_POLLS' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_POLL) ? true : false, + 'S_PRUNE_ANNOUNCE' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_ANNOUNCE) ? true : false, + 'S_PRUNE_STICKY' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_STICKY) ? true : false, + 'S_DISPLAY_ACTIVE_TOPICS' => ($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) ? true : false, + 'S_ENABLE_POST_REVIEW' => ($forum_data['forum_flags'] & FORUM_FLAG_POST_REVIEW) ? true : false, ) ); @@ -560,7 +609,7 @@ class acp_forums if (!$forum_id) { - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); + trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } $forum_data = $this->get_forum_info($forum_id); @@ -634,7 +683,7 @@ class acp_forums // Jumpbox $forum_box = make_forum_select($this->parent_id, false, false, false, false); //make_forum_select($this->parent_id); - if ($action == 'sync') + if ($action == 'sync' || $action == 'sync_topic') { $template->assign_var('S_RESYNCED', true); } @@ -677,6 +726,8 @@ class acp_forums $template->assign_block_vars('forums', array( 'FOLDER_IMAGE' => $folder_image, + 'FORUM_IMAGE' => ($row['forum_image']) ? '<img src="' . $phpbb_root_path . $row['forum_image'] . '" alt="" />' : '', + 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', 'FORUM_NAME' => $row['forum_name'], 'FORUM_DESCRIPTION' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']), 'FORUM_TOPICS' => $row['forum_topics'], @@ -716,7 +767,10 @@ class acp_forums 'NAVIGATION' => $navigation, 'FORUM_BOX' => $forum_box, 'U_SEL_ACTION' => $this->u_action, - 'U_ACTION' => $this->u_action . '&parent_id=' . $this->parent_id) + 'U_ACTION' => $this->u_action . '&parent_id=' . $this->parent_id, + + 'U_PROGRESS_BAR' => $this->u_action . '&action=progress_bar', + 'UA_PROGRESS_BAR' => str_replace('&', '&', $this->u_action) . '&action=progress_bar') ); } @@ -779,12 +833,12 @@ class acp_forums // 16 = show active topics // 32 = enable post review $forum_data['forum_flags'] = 0; - $forum_data['forum_flags'] += ($forum_data['forum_link_track']) ? 1 : 0; - $forum_data['forum_flags'] += ($forum_data['prune_old_polls']) ? 2 : 0; - $forum_data['forum_flags'] += ($forum_data['prune_announce']) ? 4 : 0; - $forum_data['forum_flags'] += ($forum_data['prune_sticky']) ? 8 : 0; - $forum_data['forum_flags'] += ($forum_data['show_active']) ? 16 : 0; - $forum_data['forum_flags'] += ($forum_data['enable_post_review']) ? 32 : 0; + $forum_data['forum_flags'] += ($forum_data['forum_link_track']) ? FORUM_FLAG_LINK_TRACK : 0; + $forum_data['forum_flags'] += ($forum_data['prune_old_polls']) ? FORUM_FLAG_PRUNE_POLL : 0; + $forum_data['forum_flags'] += ($forum_data['prune_announce']) ? FORUM_FLAG_PRUNE_ANNOUNCE : 0; + $forum_data['forum_flags'] += ($forum_data['prune_sticky']) ? FORUM_FLAG_PRUNE_STICKY : 0; + $forum_data['forum_flags'] += ($forum_data['show_active']) ? FORUM_FLAG_ACTIVE_TOPICS : 0; + $forum_data['forum_flags'] += ($forum_data['enable_post_review']) ? FORUM_FLAG_POST_REVIEW : 0; // Unset data that are not database fields $forum_data_sql = $forum_data; @@ -821,7 +875,7 @@ class acp_forums if (!$row) { - trigger_error($user->lang['PARENT_NOT_EXIST'] . adm_back_link($this->u_action . '&' . $this->parent_id)); + trigger_error($user->lang['PARENT_NOT_EXIST'] . adm_back_link($this->u_action . '&' . $this->parent_id), E_USER_WARNING); } $sql = 'UPDATE ' . FORUMS_TABLE . ' @@ -885,7 +939,8 @@ class acp_forums return array($user->lang['NO_FORUM_ACTION']); } - $forum_data_sql['forum_posts'] = $forum_data_sql['forum_topics'] = $forum_data_sql['forum_topics_real'] = 0; + $forum_data_sql['forum_posts'] = $forum_data_sql['forum_topics'] = $forum_data_sql['forum_topics_real'] = $forum_data_sql['forum_last_post_id'] = $forum_data_sql['forum_last_poster_id'] = $forum_data_sql['forum_last_post_time'] = 0; + $forum_data_sql['forum_last_poster_name'] = $forum_data_sql['forum_last_poster_colour'] = ''; } if (sizeof($errors)) @@ -1018,7 +1073,7 @@ class acp_forums { global $db; - $table_ary = array(ACL_GROUPS_TABLE, ACL_USERS_TABLE, LOG_TABLE, POSTS_TABLE, TOPICS_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE); + $table_ary = array(LOG_TABLE, POSTS_TABLE, TOPICS_TABLE, DRAFTS_TABLE, TOPICS_TRACK_TABLE); foreach ($table_ary as $table) { @@ -1121,6 +1176,14 @@ class acp_forums $sql = 'DELETE FROM ' . FORUMS_TABLE . ' WHERE ' . $db->sql_in_set('forum_id', $forum_ids); $db->sql_query($sql); + + $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', $forum_ids); + $db->sql_query($sql); + + $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', $forum_ids); + $db->sql_query($sql); } else if ($action_subforums == 'move') { @@ -1167,6 +1230,14 @@ class acp_forums $sql = 'DELETE FROM ' . FORUMS_TABLE . " WHERE forum_id = $forum_id"; $db->sql_query($sql); + + $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . " + WHERE forum_id = $forum_id"; + $db->sql_query($sql); + + $sql = 'DELETE FROM ' . ACL_USERS_TABLE . " + WHERE forum_id = $forum_id"; + $db->sql_query($sql); } } @@ -1181,6 +1252,14 @@ class acp_forums $sql = 'DELETE FROM ' . FORUMS_TABLE . " WHERE forum_id = $forum_id"; $db->sql_query($sql); + + $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . " + WHERE forum_id = $forum_id"; + $db->sql_query($sql); + + $sql = 'DELETE FROM ' . ACL_USERS_TABLE . " + WHERE forum_id = $forum_id"; + $db->sql_query($sql); } // Resync tree @@ -1290,7 +1369,21 @@ class acp_forums delete_attachments('topic', $topic_ids, false); - switch (SQL_LAYER) + // Before we remove anything we make sure we are able to adjust the post counts later. ;) + $sql = 'SELECT poster_id + FROM ' . POSTS_TABLE . ' + WHERE forum_id = ' . $forum_id . ' + AND post_postcount = 1'; + $result = $db->sql_query($sql); + + $post_counts = array(); + while ($row = $db->sql_fetchrow($result)) + { + $post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1; + } + $db->sql_freeresult($result); + + switch ($db->sql_layer) { case 'mysql4': case 'mysqli': @@ -1365,18 +1458,18 @@ class acp_forums foreach ($tables as $table) { - $db->sql_query("DELETE FROM $table WHERE " . $db->sql_in_set($field, $id_list)); + $db->sql_query("DELETE FROM $table WHERE " . $db->sql_in_set($field, $ids)); } } } while ($row); } - unset($ids, $id_list); + unset($ids); break; } - $table_ary = array(ACL_GROUPS_TABLE, ACL_USERS_TABLE, FORUMS_ACCESS_TABLE, FORUMS_TRACK_TABLE, FORUMS_WATCH_TABLE, LOG_TABLE, MODERATOR_CACHE_TABLE, POSTS_TABLE, TOPICS_TABLE, TOPICS_TRACK_TABLE); + $table_ary = array(FORUMS_ACCESS_TABLE, FORUMS_TRACK_TABLE, FORUMS_WATCH_TABLE, LOG_TABLE, MODERATOR_CACHE_TABLE, POSTS_TABLE, TOPICS_TABLE, TOPICS_TRACK_TABLE); foreach ($table_ary as $table) { @@ -1391,6 +1484,18 @@ class acp_forums $db->sql_query("UPDATE $table SET forum_id = 0 WHERE forum_id = $forum_id"); } + // Adjust users post counts + if (sizeof($post_counts)) + { + foreach ($post_counts as $poster_id => $substract) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_posts = user_posts - ' . $substract . ' + WHERE user_id = ' . $poster_id; + $db->sql_query($sql); + } + } + $db->sql_transaction('commit'); // Make sure the overall post/topic count is correct... @@ -1513,6 +1618,27 @@ class acp_forums return $target['forum_name']; } + + /** + * Display progress bar for syncinc forums + */ + function display_progress_bar($start, $total) + { + global $template, $user; + + adm_page_header($user->lang['SYNC_IN_PROGRESS']); + + $template->set_filenames(array( + 'body' => 'progress_bar.html') + ); + + $template->assign_vars(array( + 'L_PROGRESS' => $user->lang['SYNC_IN_PROGRESS'], + 'L_PROGRESS_EXPLAIN' => ($start && $total) ? sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $start, $total) : $user->lang['SYNC_IN_PROGRESS']) + ); + + adm_page_footer(); + } } ?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php index 9f7e68bfe5..9df1c52d65 100644 --- a/phpBB/includes/acp/acp_groups.php +++ b/phpBB/includes/acp/acp_groups.php @@ -30,7 +30,7 @@ class acp_groups $action = (isset($_POST['add'])) ? 'add' : ((isset($_POST['addusers'])) ? 'addusers' : request_var('action', '')); $group_id = request_var('g', 0); $mark_ary = request_var('mark', array(0)); - $name_ary = request_var('usernames', ''); + $name_ary = request_var('usernames', '', true); $leader = request_var('leader', 0); $default = request_var('default', 0); $start = request_var('start', 0); @@ -52,7 +52,7 @@ class acp_groups if (!$group_row) { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING); } } @@ -64,11 +64,11 @@ class acp_groups case 'promote': if (!$group_id) { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING); } // Approve, demote or promote - group_user_attributes($action, $group_id, $mark_ary, false, ($group_id) ? $group_row['group_name'] : false); + group_user_attributes($action, $group_id, $mark_ary, false, $group_row['group_name']); switch ($action) { @@ -85,13 +85,15 @@ class acp_groups break; } + group_update_listings($group_id); + trigger_error($user->lang[$message] . adm_back_link($this->u_action . '&action=list&g=' . $group_id)); break; case 'default': if (!$group_id) { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING); } if (confirm_box(true)) @@ -134,6 +136,8 @@ class acp_groups group_user_attributes('default', $group_id, $mark_ary, false, $group_row['group_name'], $group_row); } + group_update_listings($group_id); + trigger_error($user->lang['GROUP_DEFS_UPDATED'] . adm_back_link($this->u_action . '&action=list&g=' . $group_id)); } else @@ -155,7 +159,7 @@ class acp_groups { if (!$group_id) { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING); } $error = ''; @@ -165,7 +169,7 @@ class acp_groups case 'delete': if (!$auth->acl_get('a_groupdel')) { - trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); } $error = group_delete($group_id, $group_row['group_name']); @@ -180,7 +184,7 @@ class acp_groups if ($error) { - trigger_error($user->lang[$error] . adm_back_link($back_link)); + trigger_error($user->lang[$error] . adm_back_link($back_link), E_USER_WARNING); } $message = ($action == 'delete') ? 'GROUP_DELETED' : 'GROUP_USERS_REMOVE'; @@ -201,12 +205,12 @@ class acp_groups case 'addusers': if (!$group_id) { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING); } if (!$name_ary) { - trigger_error($user->lang['NO_USERS'] . adm_back_link($this->u_action . '&action=list&g=' . $group_id)); + trigger_error($user->lang['NO_USERS'] . adm_back_link($this->u_action . '&action=list&g=' . $group_id), E_USER_WARNING); } $name_ary = array_unique(explode("\n", $name_ary)); @@ -214,10 +218,10 @@ class acp_groups // Add user/s to group if ($error = group_user_add($group_id, false, $name_ary, $group_row['group_name'], $default, $leader, 0, $group_row)) { - trigger_error($user->lang[$error] . adm_back_link($this->u_action . '&action=list&g=' . $group_id)); + trigger_error($user->lang[$error] . adm_back_link($this->u_action . '&action=list&g=' . $group_id), E_USER_WARNING); } - $message = ($action == 'addleaders') ? 'GROUP_MODS_ADDED' : 'GROUP_USERS_ADDED'; + $message = ($leader) ? 'GROUP_MODS_ADDED' : 'GROUP_USERS_ADDED'; trigger_error($user->lang[$message] . adm_back_link($this->u_action . '&action=list&g=' . $group_id)); break; @@ -228,12 +232,12 @@ class acp_groups if ($action == 'edit' && !$group_id) { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING); } if ($action == 'add' && !$auth->acl_get('a_groupadd')) { - trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); } $error = array(); @@ -313,7 +317,7 @@ class acp_groups { if (isset($group_row['group_avatar']) && $group_row['group_avatar']) { - avatar_delete($group_row['group_avatar']); + avatar_delete('group', $group_row); } } @@ -364,24 +368,7 @@ class acp_groups $db->sql_freeresult($result); // Now insert the data - if (sizeof($groups_sql_ary)) - { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query('INSERT INTO ' . ACL_GROUPS_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $groups_sql_ary)); - break; - - default: - foreach ($groups_sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . ACL_GROUPS_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } - } + $db->sql_multi_insert(ACL_GROUPS_TABLE, $groups_sql_ary); $auth->acl_clear_prefetch(); } @@ -542,7 +529,7 @@ class acp_groups if (!$group_id) { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING); } $this->page_title = 'GROUP_MEMBERS'; @@ -614,6 +601,7 @@ class acp_groups 'U_ACTION' => $this->u_action . "&g=$group_id", 'U_BACK' => $this->u_action, 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=list&field=usernames'), + 'UA_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=list&field=usernames', false), 'U_DEFAULT_ALL' => "{$this->u_action}&action=default&g=$group_id") ); diff --git a/phpBB/includes/acp/acp_icons.php b/phpBB/includes/acp/acp_icons.php index 66aec3a90d..4636b067c2 100644 --- a/phpBB/includes/acp/acp_icons.php +++ b/phpBB/includes/acp/acp_icons.php @@ -60,7 +60,7 @@ class acp_icons if ($action == 'edit' || $action == 'add' || $action == 'import') { $imglist = filelist($phpbb_root_path . $img_path, ''); - + foreach ($imglist as $path => $img_ary) { foreach ($img_ary as $img) @@ -108,6 +108,7 @@ class acp_icons ORDER BY {$fields}_order " . (($icon_id || $action == 'add') ? 'DESC' : 'ASC'); $result = $db->sql_query($sql); + $data = array(); while ($row = $db->sql_fetchrow($result)) { if ($action == 'add') @@ -135,14 +136,13 @@ class acp_icons } $after_txt = ($mode == 'smilies') ? $row['code'] : $row['icons_url']; - $order_list = '<option value="' . ($row[$fields . '_order']) . '"' . $selected . '>' . sprintf($user->lang['AFTER_' . $lang], ' -> ' . htmlspecialchars($after_txt)) . '</option>' . $order_list; + $order_list = '<option value="' . ($row[$fields . '_order'] + 1) . '"' . $selected . '>' . sprintf($user->lang['AFTER_' . $lang], ' -> ' . htmlspecialchars($after_txt)) . '</option>' . $order_list; } } $db->sql_freeresult($result); $order_list = '<option value="1"' . ((!isset($after)) ? ' selected="selected"' : '') . '>' . $user->lang['FIRST'] . '</option>' . $order_list; - $data = array(); if ($action == 'add') { $data = $_images; @@ -242,11 +242,32 @@ class acp_icons ); } + // Image_order holds the 'new' order value if (!empty($image_order[$image])) { $img_sql = array_merge($img_sql, array( - $fields . '_order' => $image_order[$image] . '.5') + $fields . '_order' => $image_order[$image]) ); + + // Since we always add 'after' an item, we just need to increase all following + the current by one + $sql = "UPDATE $table + SET {$fields}_order = {$fields}_order + 1 + WHERE {$fields}_order >= {$image_order[$image]}"; + $db->sql_query($sql); + + // If we adjust the order, we need to adjust all other orders too - they became inaccurate... + foreach ($image_order as $_image => $_order) + { + if ($_image == $image) + { + continue; + } + + if ($_order >= $image_order[$image]) + { + $image_order[$_image]++; + } + } } if ($action == 'modify') @@ -261,45 +282,6 @@ class acp_icons $sql = "INSERT INTO $table " . $db->sql_build_array('INSERT', $img_sql); $db->sql_query($sql); } - - $update = false; - - if ($action == 'modify' && !empty($image_order[$image])) - { - $update = true; - - $sql = "SELECT {$fields}_order - FROM $table - WHERE {$fields}_id = " . $image_id[$image]; - $result = $db->sql_query($sql); - $order_old = (int) $db->sql_fetchfield($fields . '_order'); - $db->sql_freeresult($result); - - if ($order_old == $image_order[$image]) - { - $update = false; - } - - if ($order_old > $image_order[$image]) - { - $sign = '+'; - $where = $fields . '_order >= ' . $image_order[$image] . " AND {$fields}_order < $order_old"; - } - else if ($order_old < $image_order[$image]) - { - $sign = '-'; - $where = "{$fields}_order > $order_old AND {$fields}_order < " . $image_order[$image]; - $sql[$fields . '_order'] = $image_order[$image] - 1; - } - } - - if ($update) - { - $sql = "UPDATE $table - SET {$fields}_order = {$fields}_order $sign 1 - WHERE $where"; - $db->sql_query($sql); - } } } @@ -329,7 +311,7 @@ class acp_icons // The user has already selected a smilies_pak file if ($current == 'delete') { - $db->sql_query(((SQL_LAYER != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . $table); + $db->sql_query((($db->sql_layer != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . $table); switch ($mode) { @@ -363,7 +345,7 @@ class acp_icons if (!($pak_ary = @file($phpbb_root_path . $img_path . '/' . $pak))) { - trigger_error($user->lang['PAK_FILE_NOT_READABLE'] . adm_back_link($this->u_action)); + trigger_error($user->lang['PAK_FILE_NOT_READABLE'] . adm_back_link($this->u_action), E_USER_WARNING); } foreach ($pak_ary as $pak_entry) @@ -374,7 +356,7 @@ class acp_icons if ((sizeof($data[1]) != 4 && $mode == 'icons') || (sizeof($data[1]) != 6 && $mode == 'smilies')) { - trigger_error($user->lang['WRONG_PAK_TYPE'] . adm_back_link($this->u_action)); + trigger_error($user->lang['WRONG_PAK_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING); } // Stripslash here because it got addslashed before... (on export) @@ -523,7 +505,7 @@ class acp_icons } else { - trigger_error($user->lang['NO_' . strtoupper($fields) . '_EXPORT'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_' . strtoupper($fields) . '_EXPORT'] . adm_back_link($this->u_action), E_USER_WARNING); } break; @@ -562,14 +544,40 @@ class acp_icons case 'move_up': case 'move_down': - $image_order = request_var('order', 0); - $order_total = $image_order * 2 + (($action == 'move_up') ? -1 : 1); + // Get current order id... + $sql = "SELECT {$fields}_order as current_order + FROM $table + WHERE {$fields}_id = $icon_id"; + $result = $db->sql_query($sql); + $current_order = (int) $db->sql_fetchfield('current_order'); + $db->sql_freeresult($result); + + if ($current_order == 0 && $action == 'move_up') + { + break; + } + + // on move_down, switch position with next order_id... + // on move_up, switch position with previous order_id... + $switch_order_id = ($action == 'move_down') ? $current_order + 1 : $current_order - 1; - $sql = 'UPDATE ' . $table . ' - SET ' . $fields . "_order = $order_total - " . $fields . '_order - WHERE ' . $fields . "_order IN ($image_order, " . (($action == 'move_up') ? $image_order - 1 : $image_order + 1) . ')'; + // + $sql = "UPDATE $table + SET {$fields}_order = $current_order + WHERE {$fields}_order = $switch_order_id + AND {$fields}_id <> $icon_id"; $db->sql_query($sql); + // Only update the other entry too if the previous entry got updated + if ($db->sql_affectedrows()) + { + $sql = "UPDATE $table + SET {$fields}_order = $switch_order_id + WHERE {$fields}_order = $current_order + AND {$fields}_id = $icon_id"; + $db->sql_query($sql); + } + $cache->destroy('icons'); $cache->destroy('sql', $table); @@ -640,8 +648,8 @@ class acp_icons 'EMOTION' => (isset($row['emotion'])) ? $row['emotion'] : '', 'U_EDIT' => $this->u_action . '&action=edit&id=' . $row[$fields . '_id'], 'U_DELETE' => $this->u_action . '&action=delete&id=' . $row[$fields . '_id'], - 'U_MOVE_UP' => $this->u_action . '&action=move_up&order=' . $row[$fields . '_order'], - 'U_MOVE_DOWN' => $this->u_action . '&action=move_down&order=' . $row[$fields . '_order']) + 'U_MOVE_UP' => $this->u_action . '&action=move_up&id=' . $row[$fields . '_id'], + 'U_MOVE_DOWN' => $this->u_action . '&action=move_down&id=' . $row[$fields . '_id']) ); if (!$spacer && !$row['display_on_posting']) diff --git a/phpBB/includes/acp/acp_inactive.php b/phpBB/includes/acp/acp_inactive.php new file mode 100755 index 0000000000..2834d25181 --- /dev/null +++ b/phpBB/includes/acp/acp_inactive.php @@ -0,0 +1,184 @@ +<?php +/** +* +* @package acp +* @version $Id$ +* @copyright (c) 2006 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @package acp +*/ +class acp_inactive +{ + var $u_action; + var $p_master; + + function acp_inactive(&$p_master) + { + $this->p_master = &$p_master; + } + + function main($id, $mode) + { + global $config, $db, $user, $auth, $template; + global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix; + + $user->add_lang('memberlist'); + + $action = request_var('action', ''); + $mark = (isset($_REQUEST['mark'])) ? request_var('mark', array(0)) : array(); + $start = request_var('start', 0); + + // Sort keys + $sort_days = request_var('st', 0); + $sort_key = request_var('sk', 'i'); + $sort_dir = request_var('sd', 'd'); + + if (sizeof($mark)) + { + switch ($action) + { + case 'activate': + case 'delete': + $sql = 'SELECT username + FROM ' . USERS_TABLE . ' + WHERE ' . $db->sql_in_set('user_id', $mark); + $result = $db->sql_query($sql); + + $user_affected = array(); + while ($row = $db->sql_fetchrow($result)) + { + $user_affected[] = $row['username']; + } + $db->sql_freeresult($result); + + if ($action == 'activate') + { + include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx); + user_active_flip('activate', $mark); + } + else if ($action == 'delete') + { + if (!$auth->acl_get('a_userdel')) + { + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); + } + + $sql = 'DELETE FROM ' . USER_GROUP_TABLE . ' WHERE ' . $db->sql_in_set('user_id', $mark); + $db->sql_query($sql); + $sql = 'DELETE FROM ' . USERS_TABLE . ' WHERE ' . $db->sql_in_set('user_id', $mark); + $db->sql_query($sql); + + add_log('admin', 'LOG_INACTIVE_' . strtoupper($action), implode(', ', $user_affected)); + } + + break; + + case 'remind': + if (empty($config['email_enable'])) + { + trigger_error($user->lang['EMAIL_DISABLED'] . adm_back_link($this->u_action), E_USER_WARNING); + } + + $sql = 'SELECT user_id, username, user_email, user_lang, user_jabber, user_notify_type, user_regdate, user_actkey + FROM ' . USERS_TABLE . ' + WHERE ' . $db->sql_in_set('user_id', $mark); + $result = $db->sql_query($sql); + + if ($row = $db->sql_fetchrow($result)) + { + // Send the messages + include_once($phpbb_root_path . 'includes/functions_messenger.'.$phpEx); + + $messenger = new messenger(); + + $board_url = generate_board_url() . "/ucp.$phpEx?mode=activate"; + + $usernames = array(); + do + { + $messenger->template('user_remind_inactive', $row['user_lang']); + + $messenger->replyto($config['board_email']); + $messenger->to($row['user_email'], $row['username']); + $messenger->im($row['user_jabber'], $row['username']); + + $messenger->assign_vars(array( + 'USERNAME' => htmlspecialchars_decode($row['username']), + 'REGISTER_DATE' => $user->format_date($row['user_regdate']), + 'U_ACTIVATE' => "$board_url&mode=activate&u=" . $row['user_id'] . '&k=' . $row['user_actkey']) + ); + + $messenger->send($row['user_notify_type']); + + $usernames[] = $row['username']; + } + while ($row = $db->sql_fetchrow($result)); + + $messenger->save_queue(); + + add_log('admin', 'LOG_INACTIVE_REMIND', implode(', ', $usernames)); + unset($usernames); + } + $db->sql_freeresult($result); + + break; + } + } + + // Sorting + $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); + $sort_by_text = array('i' => $user->lang['SORT_INACTIVE'], 'j' => $user->lang['SORT_REG_DATE'], 'l' => $user->lang['SORT_LAST_VISIT'], 'r' => $user->lang['SORT_REASON'], 'u' => $user->lang['SORT_USERNAME']); + $sort_by_sql = array('i' => 'user_inactive_time', 'j' => 'user_regdate', 'l' => 'user_lastvisit', 'r' => 'user_inactive_reason', 'u' => 'username'); + + $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; + gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); + + // Define where and sort sql for use in displaying logs + $sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0; + $sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); + + $inactive = array(); + $inactive_count = 0; + + view_inactive_users($inactive, $inactive_count, $config['topics_per_page'], $start, $sql_where, $sql_sort); + + foreach ($inactive as $row) + { + $template->assign_block_vars('inactive', array( + 'INACTIVE_DATE' => $user->format_date($row['user_inactive_time']), + 'JOINED' => $user->format_date($row['user_regdate']), + 'LAST_VISIT' => (!$row['user_lastvisit']) ? ' - ' : $user->format_date($row['user_lastvisit']), + 'REASON' => $row['inactive_reason'], + 'USER_ID' => $row['user_id'], + 'USERNAME' => $row['username'], + 'U_USER_ADMIN' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&mode=overview&u={$row['user_id']}")) + ); + } + + $option_ary = array('activate' => 'ACTIVATE', 'delete' => 'DELETE'); + if ($config['email_enable']) + { + $option_ary += array('remind' => 'REMIND'); + } + + $template->assign_vars(array( + 'S_INACTIVE_USERS' => true, + 'S_INACTIVE_OPTIONS' => build_select($option_ary), + + 'S_LIMIT_DAYS' => $s_limit_days, + 'S_SORT_KEY' => $s_sort_key, + 'S_SORT_DIR' => $s_sort_dir, + 'S_ON_PAGE' => on_page($inactive_count, $config['topics_per_page'], $start), + 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_param", $inactive_count, $config['topics_per_page'], $start, true), + )); + + $this->tpl_name = 'acp_inactive'; + $this->page_title = 'ACP_INACTIVE_USERS'; + } +} + +?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_jabber.php b/phpBB/includes/acp/acp_jabber.php index 7c7e4586e0..afb2ba329a 100644 --- a/phpBB/includes/acp/acp_jabber.php +++ b/phpBB/includes/acp/acp_jabber.php @@ -44,16 +44,9 @@ class acp_jabber $jab_resource = request_var('jab_resource', $config['jab_resource']); $jab_package_size = request_var('jab_package_size', $config['jab_package_size']); - $jabber = new jabber(); + $jabber = new jabber($jab_host, $jab_port, $jab_username, $jab_password, $jab_resource); $error = array(); - // Setup the basis vars for jabber connection - $jabber->server = $jab_host; - $jabber->port = ($jab_port) ? $jab_port : 5222; - $jabber->username = $jab_username; - $jabber->password = $jab_password; - $jabber->resource = $jab_resource; - $message = $user->lang['JAB_SETTINGS_CHANGED']; $log = 'JAB_SETTINGS_CHANGED'; @@ -65,7 +58,7 @@ class acp_jabber { if (!$jabber->connect()) { - trigger_error($user->lang['ERR_JAB_CONNECT'] . adm_back_link($this->u_action)); + trigger_error($user->lang['ERR_JAB_CONNECT'] . adm_back_link($this->u_action), E_USER_WARNING); } // First we'll try to authorise using this account, if that fails we'll try to create it. @@ -94,12 +87,12 @@ class acp_jabber { if (!$jabber->connect()) { - trigger_error($user->lang['ERR_JAB_CONNECT'] . adm_back_link($this->u_action)); + trigger_error($user->lang['ERR_JAB_CONNECT'] . adm_back_link($this->u_action), E_USER_WARNING); } if (!$jabber->send_auth()) { - trigger_error($user->lang['ERR_JAB_AUTH'] . adm_back_link($this->u_action)); + trigger_error($user->lang['ERR_JAB_AUTH'] . adm_back_link($this->u_action), E_USER_WARNING); } $jabber->send_presence(NULL, NULL, 'online'); diff --git a/phpBB/includes/acp/acp_language.php b/phpBB/includes/acp/acp_language.php index 29aabe240f..61310cff01 100644 --- a/phpBB/includes/acp/acp_language.php +++ b/phpBB/includes/acp/acp_language.php @@ -47,8 +47,10 @@ class acp_language $missing_file = request_var('missing_file', array('' => 0)); list($_REQUEST['language_file'], ) = array_keys($missing_file); } - - list($this->language_directory, $this->language_file) = explode('|', request_var('language_file', '|common.' . $phpEx)); + + $selected_lang_file = request_var('language_file', '|common.' . $phpEx); + + list($this->language_directory, $this->language_file) = explode('|', $selected_lang_file); $this->language_directory = basename($this->language_directory); $this->language_file = basename($this->language_file); @@ -76,7 +78,8 @@ class acp_language break; default: - trigger_error($user->lang['INVALID_UPLOAD_METHOD']); + trigger_error($user->lang['INVALID_UPLOAD_METHOD'], E_USER_ERROR); + break; } $test_connection = $transfer->open_session(); @@ -124,7 +127,7 @@ class acp_language if (!$lang_id) { - trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT * @@ -153,14 +156,14 @@ class acp_language case 'download_file': case 'upload_data': - if (!$lang_id || !isset($_POST['entry']) || !is_array($_POST['entry'])) + if (!$lang_id || empty($_POST['entry'])) { - trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING); } if (!$this->language_file || (!$this->language_directory && !in_array($this->language_file, $this->main_files))) { - trigger_error($user->lang['NO_FILE_SELECTED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_FILE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT * @@ -187,7 +190,7 @@ class acp_language { if (!@mkdir($dir, 0777)) { - trigger_error("Could not create directory $dir"); + trigger_error("Could not create directory $dir", E_USER_ERROR); } @chmod($dir, 0777); } @@ -200,7 +203,7 @@ class acp_language if (!$fp) { - trigger_error($user->lang['UNABLE_TO_WRITE_FILE']); + trigger_error(sprintf($user->lang['UNABLE_TO_WRITE_FILE'], $filename) . adm_back_link($this->u_action . '&id=' . $lang_id . '&language_file=' . urlencode($selected_lang_file)), E_USER_WARNING); } if ($this->language_directory == 'email') @@ -284,6 +287,8 @@ class acp_language $file = request_var('file', ''); $dir = request_var('dir', ''); + $selected_lang_file = $dir . '|' . $file; + $old_file = '/' . $this->get_filename($row['lang_iso'], $dir, $file, false, true); $lang_path = 'language/' . $row['lang_iso'] . '/' . (($dir) ? $dir . '/' : ''); @@ -301,12 +306,13 @@ class acp_language break; default: - trigger_error($user->lang['INVALID_UPLOAD_METHOD']); + trigger_error($user->lang['INVALID_UPLOAD_METHOD'], E_USER_ERROR); + break; } if (($result = $transfer->open_session()) !== true) { - trigger_error($user->lang[$result] . adm_back_link($this->u_action)); + trigger_error($user->lang[$result] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id . '&language_file=' . urlencode($selected_lang_file)), E_USER_WARNING); } $transfer->rename($lang_path . $file, $lang_path . $file . '.bak'); @@ -318,7 +324,7 @@ class acp_language add_log('admin', 'LOG_LANGUAGE_FILE_REPLACED', $file); - trigger_error($user->lang['UPLOAD_COMPLETED']); + trigger_error($user->lang['UPLOAD_COMPLETED'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id . '&language_file=' . urlencode($selected_lang_file))); } $action = 'details'; @@ -329,7 +335,7 @@ class acp_language if (!$lang_id) { - trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING); } $this->page_title = 'LANGUAGE_PACK_DETAILS'; @@ -362,28 +368,28 @@ class acp_language case 'email': if (!in_array($this->language_file, $email_files)) { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id)); + trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); } break; case 'acp': if (!in_array($this->language_file, $acp_files)) { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id)); + trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); } break; case 'mods': if (!in_array($this->language_file, $mods_files)) { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id)); + trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); } break; default: if (!in_array($this->language_file, $this->main_files)) { - trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id)); + trigger_error($user->lang['WRONG_LANGUAGE_FILE'] . adm_back_link($this->u_action . '&action=details&id=' . $lang_id), E_USER_WARNING); } } @@ -491,7 +497,7 @@ class acp_language 'S_MISSING_FILES' => true, 'L_MISSING_FILES' => sprintf($user->lang['THOSE_MISSING_LANG_FILES'], $lang_entries['lang_local_name']), 'MISSING_FILES' => implode('<br />', $missing_files)) - ); + ); } if ($is_missing_var) @@ -500,7 +506,7 @@ class acp_language 'S_MISSING_VARS' => true, 'L_MISSING_VARS_EXPLAIN' => sprintf($user->lang['THOSE_MISSING_LANG_VARIABLES'], $lang_entries['lang_local_name']), 'U_MISSING_ACTION' => $this->u_action . "&action=$action&id=$lang_id") - ); + ); foreach ($missing_vars as $file => $vars) { @@ -532,7 +538,7 @@ class acp_language $selected = (!$this->language_directory && $this->language_file == $file) ? ' selected="selected"' : ''; $s_lang_options .= '<option value="|' . $file . '"' . $selected . '>' . $prefix . $file . '</option>'; } - + // Help Files $s_lang_options .= '<option value="|common.' . $phpEx . '" class="sep">' . $user->lang['HELP_FILES'] . '</option>'; foreach ($this->main_files as $file) @@ -559,7 +565,7 @@ class acp_language } $s_lang_options .= '<option value="|common.' . $phpEx . '" class="sep">' . $user->lang[strtoupper($check) . '_FILES'] . '</option>'; - + foreach (${$check . '_files'} as $file) { $prefix = (file_exists($phpbb_root_path . $this->get_filename($lang_iso, $check, $file, true, true))) ? '* ' : ''; @@ -599,6 +605,7 @@ class acp_language unset($help); } } + $print_message = (($this->language_directory) ? $this->language_directory . '/' : '') . $this->language_file; } @@ -611,7 +618,7 @@ class acp_language 'PRINT_MESSAGE' => $print_message, ) ); - + if (!$is_email_file) { $method = ($is_help_file) ? 'print_help_entries' : 'print_language_entries'; @@ -622,7 +629,7 @@ class acp_language { $tpl .= $this->$method($missing_vars[$name], '* '); } - + $tpl .= $this->$method($lang); $template->assign_var('TPL', $tpl); @@ -633,20 +640,21 @@ class acp_language $template->assign_vars(array( 'LANG' => $lang) ); + unset($lang); } return; - + break; case 'delete': - + if (!$lang_id) { - trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING); } - + $sql = 'SELECT * FROM ' . LANG_TABLE . ' WHERE lang_id = ' . $lang_id; @@ -656,18 +664,18 @@ class acp_language if ($row['lang_iso'] == $config['default_lang']) { - trigger_error($user->lang['NO_REMOVE_DEFAULT_LANG'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_REMOVE_DEFAULT_LANG'] . adm_back_link($this->u_action), E_USER_WARNING); } $db->sql_query('DELETE FROM ' . LANG_TABLE . ' WHERE lang_id = ' . $lang_id); $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lang = '{$config['default_lang']}' - WHERE user_lang = '{$row['lang_iso']}'"; + SET user_lang = '" . $db->sql_escape($config['default_lang']) . "' + WHERE user_lang = '" . $db->sql_escape($row['lang_iso']) . "'"; $db->sql_query($sql); - + add_log('admin', 'LOG_LANGUAGE_PACK_DELETED', $row['lang_english_name']); - + trigger_error(sprintf($user->lang['LANGUAGE_PACK_DELETED'], $row['lang_english_name']) . adm_back_link($this->u_action)); break; @@ -677,7 +685,7 @@ class acp_language if (!$lang_iso || !file_exists("{$phpbb_root_path}language/$lang_iso/iso.txt")) { - trigger_error($user->lang['LANGUAGE_PACK_NOT_EXIST'] . adm_back_link($this->u_action)); + trigger_error($user->lang['LANGUAGE_PACK_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); } $file = file("{$phpbb_root_path}language/$lang_iso/iso.txt"); @@ -685,8 +693,8 @@ class acp_language $lang_pack = array( 'iso' => $lang_iso, 'name' => trim(htmlspecialchars($file[0])), - 'local_name'=> trim(htmlspecialchars($file[1])), - 'author' => trim(htmlspecialchars($file[2])) + 'local_name'=> trim(htmlspecialchars($file[1], ENT_COMPAT, 'UTF-8')), + 'author' => trim(htmlspecialchars($file[2], ENT_COMPAT, 'UTF-8')) ); unset($file); @@ -694,18 +702,19 @@ class acp_language FROM ' . LANG_TABLE . " WHERE lang_iso = '" . $db->sql_escape($lang_iso) . "'"; $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); - if ($row = $db->sql_fetchrow($result)) + if ($row) { - trigger_error($user->lang['LANGUAGE_PACK_ALREADY_INSTALLED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['LANGUAGE_PACK_ALREADY_INSTALLED'] . adm_back_link($this->u_action), E_USER_WARNING); } - $db->sql_freeresult($result); if (!$lang_pack['name'] || !$lang_pack['local_name']) { - trigger_error($user->lang['INVALID_LANGUAGE_PACK'] . adm_back_link($this->u_action)); + trigger_error($user->lang['INVALID_LANGUAGE_PACK'] . adm_back_link($this->u_action), E_USER_WARNING); } - + // Add language pack $sql_ary = array( 'lang_iso' => $lang_pack['iso'], @@ -716,18 +725,18 @@ class acp_language ); $db->sql_query('INSERT INTO ' . LANG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); - + add_log('admin', 'LOG_LANGUAGE_PACK_INSTALLED', $lang_pack['name']); - + trigger_error(sprintf($user->lang['LANGUAGE_PACK_INSTALLED'], $lang_pack['name']) . adm_back_link($this->u_action)); break; case 'download': - + if (!$lang_id) { - trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_LANG_ID'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT * @@ -747,7 +756,7 @@ class acp_language { continue; } - + $methods[] = $type; } @@ -768,7 +777,7 @@ class acp_language 'U_ACTION' => $this->u_action . "&action=$action&id=$lang_id", 'RADIO_BUTTONS' => $radio_buttons) ); - + return; } @@ -820,9 +829,9 @@ class acp_language $this->add_to_archive($compress, $mod_files, $row['lang_iso'], 'mods'); // Write ISO File - $iso_src = html_entity_decode($row['lang_english_name']) . "\n"; - $iso_src .= html_entity_decode($row['lang_local_name']) . "\n"; - $iso_src .= html_entity_decode($row['lang_author']); + $iso_src = htmlspecialchars_decode($row['lang_english_name']) . "\n"; + $iso_src .= htmlspecialchars_decode($row['lang_local_name']) . "\n"; + $iso_src .= htmlspecialchars_decode($row['lang_author']); $compress->add_data($iso_src, 'language/' . $row['lang_iso'] . '/iso.txt'); // index.html files @@ -838,7 +847,7 @@ class acp_language $compress->close(); $compress->download('lang_' . $row['lang_iso']); - @unlink($phpbb_root_path . 'store/lang_' . $row['lang_iso'] . '.' . $use_method); + @unlink($phpbb_root_path . 'store/lang_' . $row['lang_iso'] . $use_method); exit; @@ -870,18 +879,16 @@ class acp_language $tagstyle = ($row['lang_iso'] == $config['default_lang']) ? '*' : ''; $template->assign_block_vars('lang', array( - 'U_DETAILS' => $this->u_action . "&action=details&id={$row['lang_id']}", - 'U_DOWNLOAD' => $this->u_action . "&action=download&id={$row['lang_id']}", - 'U_DELETE' => $this->u_action . "&action=delete&id={$row['lang_id']}", - - 'ENGLISH_NAME' => $row['lang_english_name'], - 'TAG' => $tagstyle, - 'LOCAL_NAME' => $row['lang_local_name'], - 'ISO' => $row['lang_iso'], - 'USED_BY' => (isset($lang_count[$row['lang_iso']])) ? $lang_count[$row['lang_iso']] : 0, - - ) - ); + 'U_DETAILS' => $this->u_action . "&action=details&id={$row['lang_id']}", + 'U_DOWNLOAD' => $this->u_action . "&action=download&id={$row['lang_id']}", + 'U_DELETE' => $this->u_action . "&action=delete&id={$row['lang_id']}", + + 'ENGLISH_NAME' => $row['lang_english_name'], + 'TAG' => $tagstyle, + 'LOCAL_NAME' => $row['lang_local_name'], + 'ISO' => $row['lang_iso'], + 'USED_BY' => (isset($lang_count[$row['lang_iso']])) ? $lang_count[$row['lang_iso']] : 0, + )); } $db->sql_freeresult($result); @@ -890,7 +897,7 @@ class acp_language while (($file = readdir($dp)) !== false) { - if ($file{0} != '.' && file_exists("{$phpbb_root_path}language/$file/iso.txt")) + if ($file[0] != '.' && file_exists("{$phpbb_root_path}language/$file/iso.txt")) { if (!in_array($file, $installed)) { @@ -917,14 +924,14 @@ class acp_language foreach ($new_ary as $iso => $lang_ary) { $template->assign_block_vars('notinst', array( - 'ISO' => $lang_ary['iso'], - 'LOCAL_NAME' => $lang_ary['local_name'], - 'NAME' => $lang_ary['name'], + 'ISO' => htmlspecialchars($lang_ary['iso']), + 'LOCAL_NAME' => htmlspecialchars($lang_ary['local_name'], ENT_COMPAT, 'UTF-8'), + 'NAME' => htmlspecialchars($lang_ary['name'], ENT_COMPAT, 'UTF-8'), 'U_INSTALL' => $this->u_action . '&action=install&iso=' . urlencode($lang_ary['iso'])) ); } } - + unset($new_ary); } @@ -942,7 +949,7 @@ class acp_language * {FILENAME} [{LANG_NAME}] * * @package language -* @copyright (c) 2005 phpBB Group +* @copyright (c) 2006 phpBB Group * @author {CHANGED} - {AUTHOR} * @license http://opensource.org/licenses/gpl-license.php GNU Public License * @@ -958,6 +965,8 @@ if (empty($lang) || !is_array($lang)) // DEVELOPERS PLEASE NOTE // +// All language files should use UTF-8 as their encoding and the files must not contain a BOM. +// // Placeholders can now contain order information, e.g. instead of // \'Page %s of %s\' you can (and should) write \'Page %1$s of %2$s\', this allows // translators to re-order the output of data while ensuring it remains correct @@ -1032,7 +1041,7 @@ $lang = array_merge($lang, array( { $tpl .= ' <tr> - <td class="row3" colspan="2">' . $key_prefix . '<b>' . $key . '</b></td> + <td class="row3" colspan="2">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '<b>' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . '</b></td> </tr>'; foreach ($value as $_key => $_value) @@ -1041,23 +1050,23 @@ $lang = array_merge($lang, array( { $tpl .= ' <tr> - <td class="row3" colspan="2">' . $key_prefix . ' <b>' . $_key . '</b></td> + <td class="row3" colspan="2">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . ' <b>' . htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') . '</b></td> </tr>'; foreach ($_value as $__key => $__value) { $tpl .= ' <tr> - <td class="row1" style="white-space: nowrap;">' . $key_prefix . '<b>' . $__key . '</b></td> + <td class="row1" style="white-space: nowrap;">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '<b>' . htmlspecialchars($__key, ENT_COMPAT, 'UTF-8') . '</b></td> <td class="row2">'; if ($input_field) { - $tpl .= '<input type="text" name="entry[' . $key . '][' . $_key . '][' . $__key . ']" value="' . htmlspecialchars($__value) . '" size="50" />'; + $tpl .= '<input type="text" name="entry[' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . '][' . htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') . '][' . htmlspecialchars($__key, ENT_COMPAT, 'UTF-8') . ']" value="' . htmlspecialchars($__value, ENT_COMPAT, 'UTF-8') . '" size="50" />'; } else { - $tpl .= '<b>' . htmlspecialchars($__value) . '</b>'; + $tpl .= '<b>' . htmlspecialchars($__value, ENT_COMPAT, 'UTF-8') . '</b>'; } $tpl .= '</td> @@ -1068,16 +1077,16 @@ $lang = array_merge($lang, array( { $tpl .= ' <tr> - <td class="row1" style="white-space: nowrap;">' . $key_prefix . '<b>' . $_key . '</b></td> + <td class="row1" style="white-space: nowrap;">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '<b>' . htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') . '</b></td> <td class="row2">'; - + if ($input_field) { - $tpl .= '<input type="text" name="entry[' . $key . '][' . $_key . ']" value="' . htmlspecialchars($_value) . '" size="50" />'; + $tpl .= '<input type="text" name="entry[' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . '][' . htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') . ']" value="' . htmlspecialchars($_value, ENT_COMPAT, 'UTF-8') . '" size="50" />'; } else { - $tpl .= '<b>' . htmlspecialchars($_value) . '</b>'; + $tpl .= '<b>' . htmlspecialchars($_value, ENT_COMPAT, 'UTF-8') . '</b>'; } $tpl .= '</td> @@ -1094,16 +1103,16 @@ $lang = array_merge($lang, array( { $tpl .= ' <tr> - <td class="row1" style="white-space: nowrap;">' . $key_prefix . '<b>' . $key . '</b></td> + <td class="row1" style="white-space: nowrap;">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '<b>' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . '</b></td> <td class="row2">'; if ($input_field) { - $tpl .= '<input type="text" name="entry[' . $key . ']" value="' . htmlspecialchars($value) . '" size="50" />'; + $tpl .= '<input type="text" name="entry[' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . ']" value="' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '" size="50" />'; } else { - $tpl .= '<b>' . htmlspecialchars($value) . '</b>'; + $tpl .= '<b>' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '</b>'; } $tpl .= '</td> @@ -1127,23 +1136,23 @@ $lang = array_merge($lang, array( { $tpl .= ' <tr> - <td class="row3" colspan="2">' . $key_prefix . '<b>' . $key . '</b></td> + <td class="row3" colspan="2">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '<b>' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . '</b></td> </tr>'; foreach ($value as $_key => $_value) { $tpl .= ' <tr> - <td class="row1" style="width: 10%; white-space: nowrap;">' . $key_prefix . '<b>' . $_key . '</b></td> + <td class="row1" style="width: 10%; white-space: nowrap;">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '<b>' . htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') . '</b></td> <td class="row2">'; if ($text_field) { - $tpl .= '<textarea name="entry[' . $key . '][' . $_key . ']" cols="80" rows="5" style="width: 90%;">' . htmlspecialchars($_value) . '</textarea>'; + $tpl .= '<textarea name="entry[' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . '][' . htmlspecialchars($_key, ENT_COMPAT, 'UTF-8') . ']" cols="80" rows="5" style="width: 90%;">' . htmlspecialchars($_value, ENT_COMPAT, 'UTF-8') . '</textarea>'; } else { - $tpl .= '<b>' . htmlspecialchars($_value) . '</b>'; + $tpl .= '<b>' . htmlspecialchars($_value, ENT_COMPAT, 'UTF-8') . '</b>'; } $tpl .= '</td> @@ -1159,23 +1168,23 @@ $lang = array_merge($lang, array( { $tpl .= ' <tr> - <td class="row1" style="width: 10%; white-space: nowrap;">' . $key_prefix . '<b>' . $key . '</b></td> + <td class="row1" style="width: 10%; white-space: nowrap;">' . htmlspecialchars($key_prefix, ENT_COMPAT, 'UTF-8') . '<b>' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . '</b></td> <td class="row2">'; if ($text_field) { - $tpl .= '<textarea name="entry[' . $key . ']" cols="80" rows="5" style="width: 90%;">' . htmlspecialchars($value) . '</textarea>'; + $tpl .= '<textarea name="entry[' . htmlspecialchars($key, ENT_COMPAT, 'UTF-8') . ']" cols="80" rows="5" style="width: 90%;">' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '</textarea>'; } else { - $tpl .= '<b>' . htmlspecialchars($value) . '</b>'; + $tpl .= '<b>' . htmlspecialchars($value, ENT_COMPAT, 'UTF-8') . '</b>'; } $tpl .= '</td> </tr>'; } } - + return $tpl; } diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php index bab08bc0ff..a321057fa2 100644 --- a/phpBB/includes/acp/acp_main.php +++ b/phpBB/includes/acp/acp_main.php @@ -20,131 +20,43 @@ class acp_main global $config, $db, $user, $auth, $template; global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix; - $action = request_var('action', ''); - $mark = (isset($_REQUEST['mark'])) ? request_var('mark', array(0)) : array(); - - if (sizeof($mark)) + // Show restore permissions notice + if ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm')) { - switch ($action) - { - case 'activate': - case 'delete': - - if (!$auth->acl_get('a_user')) - { - trigger_error($user->lang['NO_ADMIN']); - } - - $sql = 'SELECT username - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $mark); - $result = $db->sql_query($sql); - - $user_affected = array(); - while ($row = $db->sql_fetchrow($result)) - { - $user_affected[] = $row['username']; - } - $db->sql_freeresult($result); - - if ($action == 'activate') - { - include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx); - - foreach ($mark as $user_id) - { - user_active_flip($user_id, USER_INACTIVE); - } - - set_config('num_users', $config['num_users'] + sizeof($mark), true); - - // Update latest username - update_last_username(); - } - else if ($action == 'delete') - { - if (!$auth->acl_get('a_userdel')) - { - trigger_error($user->lang['NO_ADMIN']); - } - - $sql = 'DELETE FROM ' . USER_GROUP_TABLE . ' WHERE ' . $db->sql_in_set('user_id', $mark); - $db->sql_query($sql); - $sql = 'DELETE FROM ' . USERS_TABLE . ' WHERE ' . $db->sql_in_set('user_id', $mark); - $db->sql_query($sql); - - add_log('admin', 'LOG_INDEX_' . strtoupper($action), implode(', ', $user_affected)); - } - - break; - - case 'remind': - if (!$auth->acl_get('a_user')) - { - trigger_error($user->lang['NO_ADMIN']); - } - - if (empty($config['email_enable'])) - { - trigger_error($user->lang['EMAIL_DISABLED']); - } - - $sql = 'SELECT user_id, username, user_email, user_lang, user_jabber, user_notify_type, user_regdate, user_actkey - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $mark); - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - // Send the messages - include_once($phpbb_root_path . 'includes/functions_messenger.'.$phpEx); - - $messenger = new messenger(); + $this->tpl_name = 'acp_main'; + $this->page_title = 'ACP_MAIN'; - $board_url = generate_board_url() . "/ucp.$phpEx?mode=activate"; - $sig = str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']); - - $usernames = array(); - do - { - $messenger->template('user_remind_inactive', $row['user_lang']); - - $messenger->replyto($config['board_email']); - $messenger->to($row['user_email'], $row['username']); - $messenger->im($row['user_jabber'], $row['username']); - - $messenger->assign_vars(array( - 'EMAIL_SIG' => $sig, - 'USERNAME' => html_entity_decode($row['username']), - 'SITENAME' => $config['sitename'], - 'REGISTER_DATE' => $user->format_date($row['user_regdate']), - - 'U_ACTIVATE' => "$board_url&mode=activate&u=" . $row['user_id'] . '&k=' . $row['user_actkey']) - ); - - $messenger->send($row['user_notify_type']); + $sql = 'SELECT user_id, username, user_colour + FROM ' . USERS_TABLE . ' + WHERE user_id = ' . $user->data['user_perm_from']; + $result = $db->sql_query($sql); + $user_row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); - $usernames[] = $row['username']; - } - while ($row = $db->sql_fetchrow($result)); + $perm_from = '<strong' . (($user_row['user_colour']) ? ' style="color: #' . $user_row['user_colour'] . '">' : '>'); + $perm_from .= ($user_row['user_id'] != ANONYMOUS) ? '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $user_row['user_id']) . '">' : ''; + $perm_from .= $user_row['username']; + $perm_from .= ($user_row['user_id'] != ANONYMOUS) ? '</a>' : ''; + $perm_from .= '</strong>'; - $messenger->save_queue(); + $template->assign_vars(array( + 'S_RESTORE_PERMISSIONS' => true, + 'U_RESTORE_PERMISSIONS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm'), + 'PERM_FROM' => $perm_from, + 'L_PERMISSIONS_TRANSFERED_EXPLAIN' => sprintf($user->lang['PERMISSIONS_TRANSFERED_EXPLAIN'], $perm_from, append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm')), + )); - add_log('admin', 'LOG_INDEX_REMIND', implode(', ', $usernames)); - unset($usernames); - } - $db->sql_freeresult($result); - - break; - } + return; } + $action = request_var('action', ''); + switch ($action) { case 'online': if (!$auth->acl_get('a_board')) { - trigger_error($user->lang['NO_ADMIN']); + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); } set_config('record_online_users', 1, true); @@ -155,47 +67,47 @@ class acp_main case 'stats': if (!$auth->acl_get('a_board')) { - trigger_error($user->lang['NO_ADMIN']); + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT COUNT(post_id) AS stat FROM ' . POSTS_TABLE . ' WHERE post_approved = 1'; $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); + set_config('num_posts', (int) $row['stat'], true); $sql = 'SELECT COUNT(topic_id) AS stat FROM ' . TOPICS_TABLE . ' WHERE topic_approved = 1'; $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); + set_config('num_topics', (int) $row['stat'], true); $sql = 'SELECT COUNT(user_id) AS stat FROM ' . USERS_TABLE . ' WHERE user_type IN (' . USER_NORMAL . ',' . USER_FOUNDER . ')'; $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); + set_config('num_users', (int) $row['stat'], true); $sql = 'SELECT COUNT(attach_id) as stat - FROM ' . ATTACHMENTS_TABLE; + FROM ' . ATTACHMENTS_TABLE . ' + WHERE is_orphan = 0'; $result = $db->sql_query($sql); - set_config('num_files', (int) $db->sql_fetchfield('stat'), true); $db->sql_freeresult($result); $sql = 'SELECT SUM(filesize) as stat - FROM ' . ATTACHMENTS_TABLE; + FROM ' . ATTACHMENTS_TABLE . ' + WHERE is_orphan = 0'; $result = $db->sql_query($sql); - set_config('upload_dir_size', (int) $db->sql_fetchfield('stat'), true); $db->sql_freeresult($result); @@ -205,7 +117,7 @@ class acp_main case 'user': if (!$auth->acl_get('a_board')) { - trigger_error($user->lang['NO_ADMIN']); + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT COUNT(post_id) AS num_posts, poster_id @@ -227,7 +139,7 @@ class acp_main case 'date': if (!$auth->acl_get('a_board')) { - trigger_error($user->lang['NO_ADMIN']); + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); } set_config('board_startdate', time() - 1); @@ -235,7 +147,7 @@ class acp_main break; case 'db_track': - $db->sql_query(((SQL_LAYER != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . TOPICS_POSTED_TABLE); + $db->sql_query((($db->sql_layer != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . TOPICS_POSTED_TABLE); // This can get really nasty... therefore we only do the last six months $get_from_time = time() - (6 * 4 * 7 * 24 * 60 * 60); @@ -290,24 +202,7 @@ class acp_main } unset($posted); - if (sizeof($sql_ary)) - { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $sql_ary)); - break; - - default: - foreach ($sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } - } + $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary); } add_log('admin', 'LOG_RESYNC_POST_MARKING'); @@ -337,7 +232,7 @@ class acp_main { while (($file = readdir($avatar_dir)) !== false) { - if ($file{0} != '.' && $file != 'CVS' && strpos($file, 'index.') === false) + if ($file[0] != '.' && $file != 'CVS' && strpos($file, 'index.') === false) { $avatar_dir_size += filesize($phpbb_root_path . $config['avatar_path'] . '/' . $file); } @@ -375,6 +270,21 @@ class acp_main $files_per_day = $total_files; } + if ($config['allow_attachments'] || $config['allow_pm_attach']) + { + $sql = 'SELECT COUNT(attach_id) AS total_orphan + FROM ' . ATTACHMENTS_TABLE . ' + WHERE is_orphan = 1 + AND filetime < ' . (time() - 3*60*60); + $result = $db->sql_query($sql); + $total_orphan = (int) $db->sql_fetchfield('total_orphan'); + $db->sql_freeresult($result); + } + else + { + $total_orphan = false; + } + $dbsize = get_database_size(); $s_action_options = build_select(array('online' => 'RESET_ONLINE', 'date' => 'RESET_DATE', 'stats' => 'RESYNC_STATS', 'user' => 'RESYNC_POSTCOUNTS', 'db_track' => 'RESYNC_POST_MARKING')); @@ -391,11 +301,14 @@ class acp_main 'AVATAR_DIR_SIZE' => $avatar_dir_size, 'DBSIZE' => $dbsize, 'UPLOAD_DIR_SIZE' => $upload_dir_size, + 'TOTAL_ORPHAN' => $total_orphan, + 'S_TOTAL_ORPHAN' => ($total_orphan === false) ? false : true, 'GZIP_COMPRESSION' => ($config['gzip_compress']) ? $user->lang['ON'] : $user->lang['OFF'], 'DATABASE_INFO' => $db->sql_server_info(), 'U_ACTION' => append_sid("{$phpbb_admin_path}index.$phpEx"), 'U_ADMIN_LOG' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=logs&mode=admin'), + 'U_INACTIVE_USERS' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=inactive&mode=list'), 'S_ACTION_OPTIONS' => ($auth->acl_get('a_board')) ? $s_action_options : '', ) @@ -421,17 +334,18 @@ class acp_main if ($auth->acl_get('a_user')) { - $sql = 'SELECT user_id, username, user_regdate, user_lastvisit - FROM ' . USERS_TABLE . ' - WHERE user_type = ' . USER_INACTIVE . ' - ORDER BY user_regdate ASC'; - $result = $db->sql_query($sql); + $inactive = array(); + $inactive_count = 0; - while ($row = $db->sql_fetchrow($result)) + view_inactive_users($inactive, $inactive_count, 10); + + foreach ($inactive as $row) { $template->assign_block_vars('inactive', array( - 'DATE' => $user->format_date($row['user_regdate']), + 'INACTIVE_DATE' => $user->format_date($row['user_inactive_time']), + 'JOINED' => $user->format_date($row['user_regdate']), 'LAST_VISIT' => (!$row['user_lastvisit']) ? ' - ' : $user->format_date($row['user_lastvisit']), + 'REASON' => $row['inactive_reason'], 'USER_ID' => $row['user_id'], 'USERNAME' => $row['username'], 'U_USER_ADMIN' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&mode=overview&u={$row['user_id']}")) @@ -450,12 +364,6 @@ class acp_main ); } - // Display debug_extra notice - if (defined('DEBUG_EXTRA')) - { - $template->assign_var('S_DEBUG_EXTRA', true); - } - // Warn if install is still present if (file_exists($phpbb_root_path . 'install')) { diff --git a/phpBB/includes/acp/acp_modules.php b/phpBB/includes/acp/acp_modules.php index 7c72a1ca6b..1323c7aee4 100644 --- a/phpBB/includes/acp/acp_modules.php +++ b/phpBB/includes/acp/acp_modules.php @@ -24,6 +24,7 @@ class acp_modules { var $module_class = ''; + var $parent_id; var $u_action; function main($id, $mode) @@ -51,7 +52,7 @@ class acp_modules $this->page_title = strtoupper($this->module_class); - $parent_id = request_var('parent_id', 0); + $this->parent_id = request_var('parent_id', 0); $module_id = request_var('m', 0); $action = request_var('action', ''); $errors = array(); @@ -61,9 +62,9 @@ class acp_modules case 'delete': if (!$module_id) { - trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&parent_id=' . $parent_id)); + trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } - + if (confirm_box(true)) { $errors = $this->delete_module($module_id); @@ -71,7 +72,7 @@ class acp_modules if (!sizeof($errors)) { $this->remove_cache_file(); - trigger_error($user->lang['MODULE_DELETED'] . adm_back_link($this->u_action . '&parent_id=' . $parent_id)); + trigger_error($user->lang['MODULE_DELETED'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); } } else @@ -79,7 +80,7 @@ class acp_modules confirm_box(false, 'DELETE_MODULE', build_hidden_fields(array( 'i' => $id, 'mode' => $mode, - 'parent_id' => $parent_id, + 'parent_id' => $this->parent_id, 'module_id' => $module_id, 'action' => $action, ))); @@ -91,9 +92,9 @@ class acp_modules case 'disable': if (!$module_id) { - trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&parent_id=' . $parent_id)); + trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } - + $sql = 'UPDATE ' . MODULES_TABLE . ' SET module_enabled = ' . (($action == 'enable') ? 1 : 0) . " WHERE module_id = $module_id"; @@ -108,7 +109,7 @@ class acp_modules case 'move_down': if (!$module_id) { - trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&parent_id=' . $parent_id)); + trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } $sql = 'SELECT * @@ -121,7 +122,7 @@ class acp_modules if (!$row) { - trigger_error($user->lang['NO_MODULE'] . adm_back_link($this->u_action . '&parent_id=' . $parent_id)); + trigger_error($user->lang['NO_MODULE'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } $move_module_name = $this->move_module_by($row, $action, 1); @@ -156,7 +157,7 @@ class acp_modules 'module_basename' => $module_basename, 'module_enabled' => 0, 'module_display' => (isset($fileinfo['modes'][$module_mode]['display'])) ? $fileinfo['modes'][$module_mode]['display'] : 1, - 'parent_id' => $parent_id, + 'parent_id' => $this->parent_id, 'module_class' => $this->module_class, 'module_langname' => $fileinfo['modes'][$module_mode]['title'], 'module_mode' => $module_mode, @@ -169,7 +170,7 @@ class acp_modules { $this->remove_cache_file(); - trigger_error($user->lang['MODULE_ADDED'] . adm_back_link($this->u_action . '&parent_id=' . $parent_id)); + trigger_error($user->lang['MODULE_ADDED'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); } } } @@ -178,7 +179,7 @@ class acp_modules confirm_box(false, 'ADD_MODULE', build_hidden_fields(array( 'i' => $id, 'mode' => $mode, - 'parent_id' => $parent_id, + 'parent_id' => $this->parent_id, 'action' => 'quickadd', 'quick_install' => $quick_install, ))); @@ -190,7 +191,7 @@ class acp_modules if (!$module_id) { - trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&parent_id=' . $parent_id)); + trigger_error($user->lang['NO_MODULE_ID'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } $module_row = $this->get_module_row($module_id); @@ -228,7 +229,7 @@ class acp_modules { if (!$module_data['module_langname']) { - trigger_error($user->lang['NO_MODULE_LANGNAME'] . adm_back_link($this->u_action . '&parent_id=' . $parent_id)); + trigger_error($user->lang['NO_MODULE_LANGNAME'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } $module_type = request_var('module_type', 'category'); @@ -257,7 +258,7 @@ class acp_modules { $this->remove_cache_file(); - trigger_error((($action == 'add') ? $user->lang['MODULE_ADDED'] : $user->lang['MODULE_EDITED']) . adm_back_link($this->u_action . '&parent_id=' . $parent_id)); + trigger_error((($action == 'add') ? $user->lang['MODULE_ADDED'] : $user->lang['MODULE_EDITED']) . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); } } @@ -306,8 +307,8 @@ class acp_modules 'S_CAT_OPTIONS' => $s_cat_option . $this->make_module_select($module_data['parent_id'], ($action == 'edit') ? $module_row['module_id'] : false, false, false, false, true), 'S_MODULE_NAMES' => $s_name_options, 'S_MODULE_MODES' => $s_mode_options, - 'U_BACK' => $this->u_action . '&parent_id=' . $parent_id, - 'U_EDIT_ACTION' => $this->u_action . '&parent_id=' . $parent_id, + 'U_BACK' => $this->u_action . '&parent_id=' . $this->parent_id, + 'U_EDIT_ACTION' => $this->u_action . '&parent_id=' . $this->parent_id, 'L_TITLE' => $user->lang[strtoupper($action) . '_MODULE'], @@ -341,7 +342,7 @@ class acp_modules ); } - if (!$parent_id) + if (!$this->parent_id) { $navigation = strtoupper($this->module_class); } @@ -349,12 +350,13 @@ class acp_modules { $navigation = '<a href="' . $this->u_action . '">' . strtoupper($this->module_class) . '</a>'; - $modules_nav = $this->get_module_branch($parent_id, 'parents', 'descending'); + $modules_nav = $this->get_module_branch($this->parent_id, 'parents', 'descending'); + foreach ($modules_nav as $row) { $langname = $this->lang_name($row['module_langname']); - if ($row['module_id'] == $parent_id) + if ($row['module_id'] == $this->parent_id) { $navigation .= ' -> ' . $langname; } @@ -366,11 +368,11 @@ class acp_modules } // Jumpbox - $module_box = $this->make_module_select($parent_id, false, false, false, false); + $module_box = $this->make_module_select($this->parent_id, false, false, false, false); $sql = 'SELECT * FROM ' . MODULES_TABLE . " - WHERE parent_id = $parent_id + WHERE parent_id = {$this->parent_id} AND module_class = '" . $db->sql_escape($this->module_class) . "' ORDER BY left_id"; $result = $db->sql_query($sql); @@ -390,14 +392,17 @@ class acp_modules $module_image = (!$row['module_basename'] || $row['left_id'] + 1 != $row['right_id']) ? '<img src="images/icon_subfolder.gif" width="46" height="25" alt="' . $user->lang['CATEGORY'] . '" />' : '<img src="images/icon_folder.gif" width="46" height="25" alt="' . $user->lang['MODULE'] . '" />'; } - $url = $this->u_action . '&parent_id=' . $parent_id . '&m=' . $row['module_id']; - + $url = $this->u_action . '&parent_id=' . $this->parent_id . '&m=' . $row['module_id']; + $template->assign_block_vars('modules', array( 'MODULE_IMAGE' => $module_image, 'MODULE_TITLE' => $langname, 'MODULE_ENABLED' => ($row['module_enabled']) ? true : false, 'MODULE_DISPLAYED' => ($row['module_display']) ? true : false, + 'S_ACP_CAT_SYSTEM' => ($this->module_class == 'acp' && $row['module_langname'] == 'ACP_CAT_SYSTEM') ? true : false, + 'S_ACP_MODULE_MANAGEMENT' => ($this->module_class == 'acp' && ($row['module_basename'] == 'modules' || $row['module_langname'] == 'ACP_MODULE_MANAGEMENT')) ? true : false, + 'U_MODULE' => $this->u_action . '&parent_id=' . $row['module_id'], 'U_MOVE_UP' => $url . '&action=move_up', 'U_MOVE_DOWN' => $url . '&action=move_down', @@ -409,11 +414,11 @@ class acp_modules } while ($row = $db->sql_fetchrow($result)); } - else if ($parent_id) + else if ($this->parent_id) { - $row = $this->get_module_row($parent_id); + $row = $this->get_module_row($this->parent_id); - $url = $this->u_action . '&parent_id=' . $parent_id . '&m=' . $row['module_id']; + $url = $this->u_action . '&parent_id=' . $this->parent_id . '&m=' . $row['module_id']; $template->assign_vars(array( 'S_NO_MODULES' => true, @@ -449,11 +454,11 @@ class acp_modules } $template->assign_vars(array( - 'U_SEL_ACTION' => $this->u_action, - 'U_ACTION' => $this->u_action . '&parent_id=' . $parent_id, - 'NAVIGATION' => $navigation, - 'MODULE_BOX' => $module_box, - 'PARENT_ID' => $parent_id, + 'U_SEL_ACTION' => $this->u_action, + 'U_ACTION' => $this->u_action . '&parent_id=' . $this->parent_id, + 'NAVIGATION' => $navigation, + 'MODULE_BOX' => $module_box, + 'PARENT_ID' => $this->parent_id, 'S_INSTALL_OPTIONS' => $s_install_options, ) ); @@ -476,7 +481,7 @@ class acp_modules if (!$row) { - trigger_error($user->lang['NO_MODULE']); + trigger_error($user->lang['NO_MODULE'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } return $row; @@ -721,7 +726,7 @@ class acp_modules return 'PARENT_NO_EXIST'; } - trigger_error($user->lang['PARENT_NO_EXIST']); + trigger_error($user->lang['PARENT_NO_EXIST'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } $sql = 'UPDATE ' . MODULES_TABLE . " @@ -1007,6 +1012,14 @@ class acp_modules return $this->lang_name($target['module_langname']); } + + /** + * Check if the module or her childs hold the management module(s) + */ + function is_management_module($module_id) + { + + } } ?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_permission_roles.php b/phpBB/includes/acp/acp_permission_roles.php index 2026aebaf0..004d9f55af 100644 --- a/phpBB/includes/acp/acp_permission_roles.php +++ b/phpBB/includes/acp/acp_permission_roles.php @@ -26,7 +26,7 @@ class acp_permission_roles $auth_admin = new auth_admin(); $user->add_lang('acp/permissions'); - $user->add_lang('acp/permissions_phpbb'); + add_permission_language(); $this->tpl_name = 'acp_permission_roles'; @@ -58,7 +58,8 @@ class acp_permission_roles break; default: - trigger_error('INVALID_MODE'); + trigger_error('NO_MODE', E_USER_ERROR); + break; } $template->assign_vars(array( @@ -75,7 +76,7 @@ class acp_permission_roles if (!$role_id) { - trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT * @@ -87,7 +88,7 @@ class acp_permission_roles if (!$role_row) { - trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); } if (confirm_box(true)) @@ -112,7 +113,7 @@ class acp_permission_roles case 'edit': if (!$role_id) { - trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); } // Get role we edit @@ -125,7 +126,7 @@ class acp_permission_roles if (!$role_row) { - trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); } // no break; @@ -138,22 +139,22 @@ class acp_permission_roles if (!$role_name) { - trigger_error($user->lang['NO_ROLE_NAME_SPECIFIED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_ROLE_NAME_SPECIFIED'] . adm_back_link($this->u_action), E_USER_WARNING); } // if we add/edit a role we check the name to be unique among the settings... $sql = 'SELECT role_id FROM ' . ACL_ROLES_TABLE . " WHERE role_type = '" . $db->sql_escape($permission_type) . "' - AND LOWER(role_name) = '" . $db->sql_escape(strtolower($role_name)) . "'"; + AND role_name = '" . $db->sql_escape($role_name) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); // Make sure we only print out the error if we add the role or change it's name - if ($row && ($mode == 'add' || ($mode == 'edit' && strtolower($role_row['role_name']) != strtolower($role_name)))) + if ($row && ($mode == 'add' || ($mode == 'edit' && $role_row['role_name'] != $role_name))) { - trigger_error(sprintf($user->lang['ROLE_NAME_ALREADY_EXIST'], $role_name) . adm_back_link($this->u_action)); + trigger_error(sprintf($user->lang['ROLE_NAME_ALREADY_EXIST'], $role_name) . adm_back_link($this->u_action), E_USER_WARNING); } $sql_ary = array( @@ -252,7 +253,7 @@ class acp_permission_roles { if (!$role_id) { - trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT * @@ -279,7 +280,7 @@ class acp_permission_roles if (!$role_row) { - trigger_error($user->lang['NO_PRESET_SELECTED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); } $template->assign_vars(array( diff --git a/phpBB/includes/acp/acp_permissions.php b/phpBB/includes/acp/acp_permissions.php index ee4b2a1ade..5354d70f72 100644 --- a/phpBB/includes/acp/acp_permissions.php +++ b/phpBB/includes/acp/acp_permissions.php @@ -27,7 +27,7 @@ class acp_permissions $auth_admin = new auth_admin(); $user->add_lang('acp/permissions'); - $user->add_lang('acp/permissions_phpbb'); + add_permission_language(); $this->tpl_name = 'acp_permissions'; @@ -47,7 +47,7 @@ class acp_permissions return; } - trigger_error('NO_MODE'); + trigger_error('NO_MODE', E_USER_ERROR); } // Set some vars @@ -59,8 +59,8 @@ class acp_permissions $subforum_id = request_var('subforum_id', 0); $forum_id = request_var('forum_id', array(0)); - $username = request_var('username', array('')); - $usernames = request_var('usernames', ''); + $username = request_var('username', array(''), true); + $usernames = request_var('usernames', '', true); $user_id = request_var('user_id', array(0)); $group_id = request_var('group_id', array(0)); @@ -70,7 +70,7 @@ class acp_permissions if ($select_all_groups) { // Add default groups to selection - $sql_and = (!$config['coppa_enable']) ? " AND group_name NOT IN ('INACTIVE_COPPA', 'REGISTERED_COPPA')" : ''; + $sql_and = (!$config['coppa_enable']) ? " AND group_name <> 'REGISTERED_COPPA'" : ''; $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . ' @@ -98,7 +98,7 @@ class acp_permissions if (!sizeof($user_id)) { - trigger_error($user->lang['SELECTED_USER_NOT_EXIST'] . adm_back_link($this->u_action)); + trigger_error($user->lang['SELECTED_USER_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); } } unset($username); @@ -190,7 +190,8 @@ class acp_permissions break; default: - trigger_error('INVALID_MODE'); + trigger_error('NO_MODE', E_USER_ERROR); + break; } $template->assign_vars(array( @@ -203,7 +204,7 @@ class acp_permissions if (!in_array($permission_type, $this->permission_dropdown)) { - trigger_error($user->lang['WRONG_PERMISSION_TYPE'] . adm_back_link($this->u_action)); + trigger_error($user->lang['WRONG_PERMISSION_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING); } @@ -237,14 +238,14 @@ class acp_permissions } else { - trigger_error($user->lang['NO_USER_GROUP_SELECTED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_USER_GROUP_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); } break; case 'apply_permissions': if (!isset($_POST['setting'])) { - trigger_error($user->lang['NO_AUTH_SETTING_FOUND'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_AUTH_SETTING_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); } $this->set_permissions($mode, $permission_type, $auth_admin, $user_id, $group_id); @@ -253,7 +254,7 @@ class acp_permissions case 'apply_all_permissions': if (!isset($_POST['setting'])) { - trigger_error($user->lang['NO_AUTH_SETTING_FOUND'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_AUTH_SETTING_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); } $this->set_all_permissions($mode, $permission_type, $auth_admin, $user_id, $group_id); @@ -330,7 +331,8 @@ class acp_permissions $template->assign_vars(array( 'S_SELECT_USER' => true, - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=select_victim&field=username')) + 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=select_victim&field=username'), + 'UA_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=select_victim&field=username', false)) ); break; @@ -392,17 +394,23 @@ class acp_permissions 'S_DEFINED_USER_OPTIONS' => $items['user_ids_options'], 'S_DEFINED_GROUP_OPTIONS' => $items['group_ids_options'], 'S_ADD_GROUP_OPTIONS' => group_select_options(false, $items['group_ids']), - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=add_user&field=username')) + 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=add_user&field=username'), + 'UA_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=add_user&field=username', false)) ); break; } + // The S_ALLOW_SELECT parameter below is a measure to lower memory usage. + // If there are more than 5 forums selected the admin is not able to select all users/groups too. + // We need to see if the number of forums can be increased or need to be decreased. + $template->assign_vars(array( 'U_ACTION' => $this->u_action, 'ANONYMOUS_USER_ID' => ANONYMOUS, 'S_SELECT_VICTIM' => true, + 'S_ALLOW_ALL_SELECT' => (sizeof($forum_id) > 5) ? false : true, 'S_CAN_SELECT_USER' => ($auth->acl_get('a_authusers')) ? true : false, 'S_CAN_SELECT_GROUP' => ($auth->acl_get('a_authgroups')) ? true : false, 'S_HIDDEN_FIELDS' => $s_hidden_fields) @@ -436,7 +444,7 @@ class acp_permissions // Do not allow forum_ids being set and no other setting defined (will bog down the server too much) if (sizeof($forum_id) && !sizeof($user_id) && !sizeof($group_id)) { - trigger_error($user->lang['ONLY_FORUM_DEFINED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['ONLY_FORUM_DEFINED'] . adm_back_link($this->u_action), E_USER_WARNING); } $template->assign_vars(array( @@ -566,7 +574,7 @@ class acp_permissions if (!sizeof($ids)) { - trigger_error($user->lang['SELECTED_' . strtoupper($mode) . '_NOT_EXIST'] . adm_back_link($this->u_action)); + trigger_error($user->lang['SELECTED_' . strtoupper($mode) . '_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); } } @@ -585,7 +593,7 @@ class acp_permissions // Check the permission setting again if (!$auth->acl_get('a_' . str_replace('_', '', $permission_type) . 'auth') || !$auth->acl_get('a_auth' . $ug_type . 's')) { - trigger_error($user->lang['NO_ADMIN'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); } $ug_id = $forum_id = 0; @@ -643,7 +651,7 @@ class acp_permissions // Remove users who are now moderators or admins from everyones foes list if ($permission_type == 'm_' || $permission_type == 'a_') { - $this->update_foes(); + update_foes(); } $this->log_action($mode, 'add', $permission_type, $ug_type, $ug_id, $forum_id); @@ -664,7 +672,7 @@ class acp_permissions // Check the permission setting again if (!$auth->acl_get('a_' . str_replace('_', '', $permission_type) . 'auth') || !$auth->acl_get('a_auth' . $ug_type . 's')) { - trigger_error($user->lang['NO_ADMIN'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); } $auth_settings = (isset($_POST['setting'])) ? $_POST['setting'] : array(); @@ -710,7 +718,7 @@ class acp_permissions // Remove users who are now moderators or admins from everyones foes list if ($permission_type == 'm_' || $permission_type == 'a_') { - $this->update_foes(); + update_foes(); } $this->log_action($mode, 'add', $permission_type, $ug_type, $ug_ids, $forum_ids); @@ -769,7 +777,7 @@ class acp_permissions // Check the permission setting again if (!$auth->acl_get('a_' . str_replace('_', '', $permission_type) . 'auth') || !$auth->acl_get('a_auth' . $ug_type . 's')) { - trigger_error($user->lang['NO_ADMIN'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); } $auth_admin->acl_delete($ug_type, (($ug_type == 'user') ? $user_id : $group_id), (sizeof($forum_id) ? $forum_id : false), $permission_type); @@ -840,32 +848,6 @@ class acp_permissions } /** - * Update foes - remove moderators and administrators from foe lists... - */ - function update_foes() - { - global $db, $auth; - - $perms = array(); - foreach ($auth->acl_get_list(false, array('a_', 'm_'), false) as $forum_id => $forum_ary) - { - foreach ($forum_ary as $auth_option => $user_ary) - { - $perms = array_merge($perms, $user_ary); - } - } - - if (sizeof($perms)) - { - $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' - WHERE ' . $db->sql_in_set('zebra_id', array_unique($perms)) . ' - AND foe = 1'; - $db->sql_query($sql); - } - unset($perms); - } - - /** * Display a complete trace tree for the selected permission to determine where settings are set/unset */ function permission_trace($user_id, $forum_id, $permission) @@ -888,7 +870,7 @@ class acp_permissions if (!$userdata) { - trigger_error('NO_USERS'); + trigger_error('NO_USERS', E_USER_ERROR); } $forum_name = false; diff --git a/phpBB/includes/acp/acp_php_info.php b/phpBB/includes/acp/acp_php_info.php index 44917bd8fc..fe223b623e 100644 --- a/phpBB/includes/acp/acp_php_info.php +++ b/phpBB/includes/acp/acp_php_info.php @@ -22,7 +22,7 @@ class acp_php_info if ($mode != 'info') { - trigger_error('NO_MODE'); + trigger_error('NO_MODE', E_USER_ERROR); } $this->tpl_name = 'acp_php_info'; diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index c361c47c2e..9ce7f3ed92 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -91,7 +91,7 @@ class acp_profile if (!$field_id) { - trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING); } if (confirm_box(true)) @@ -107,7 +107,7 @@ class acp_profile $db->sql_query('DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . " WHERE field_id = $field_id"); $db->sql_query('DELETE FROM ' . PROFILE_LANG_TABLE . " WHERE field_id = $field_id"); - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'sqlite': $sql = "SELECT sql @@ -119,6 +119,8 @@ class acp_profile $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); + $db->sql_transaction('begin'); + // Create a temp table and populate it, destroy the existing one $db->sql_query(preg_replace('#CREATE\s+TABLE\s+"?' . PROFILE_FIELDS_DATA_TABLE . '"?#i', 'CREATE TEMPORARY TABLE ' . PROFILE_FIELDS_DATA_TABLE . '_temp', $row['sql'])); $db->sql_query('INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . '_temp SELECT * FROM ' . PROFILE_FIELDS_DATA_TABLE); @@ -127,12 +129,13 @@ class acp_profile preg_match('#\((.*)\)#s', $row['sql'], $matches); $new_table_cols = trim($matches[1]); - $old_table_cols = explode(',', $new_table_cols); + $old_table_cols = preg_split('/,(?=[\\sa-z])/im', $new_table_cols); $column_list = array(); - foreach($old_table_cols as $declaration) + + foreach ($old_table_cols as $declaration) { $entities = preg_split('#\s+#', trim($declaration)); - if ($entities[0] !== '_' . $field_ident) + if ($entities[0] !== 'pf_' . $field_ident) { $column_list[] = $entities[0]; } @@ -140,16 +143,18 @@ class acp_profile $columns = implode(',', $column_list); - $new_table_cols = preg_replace('/' . '_' . $field_ident . '[^,]+,/', '', $new_table_cols); + $new_table_cols = preg_replace('/' . 'pf_' . $field_ident . '[^,]+,/', '', $new_table_cols); // create a new table and fill it up. destroy the temp one $db->sql_query('CREATE TABLE ' . PROFILE_FIELDS_DATA_TABLE . ' (' . $new_table_cols . ');'); $db->sql_query('INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . PROFILE_FIELDS_DATA_TABLE . '_temp;'); $db->sql_query('DROP TABLE ' . PROFILE_FIELDS_DATA_TABLE . '_temp'); + + $db->sql_transaction('commit'); break; default: - $db->sql_query('ALTER TABLE ' . PROFILE_FIELDS_DATA_TABLE . " DROP _$field_ident"); + $db->sql_query('ALTER TABLE ' . PROFILE_FIELDS_DATA_TABLE . " DROP pf_$field_ident"); } $order = 0; @@ -192,7 +197,7 @@ class acp_profile if (!$field_id) { - trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT lang_id @@ -204,7 +209,7 @@ class acp_profile if (!in_array($default_lang_id, $lang_defs['entry'][$field_id])) { - trigger_error($user->lang['DEFAULT_LANGUAGE_NOT_FILLED'] . adm_back_link($this->u_action)); + trigger_error($user->lang['DEFAULT_LANGUAGE_NOT_FILLED'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . " @@ -229,7 +234,7 @@ class acp_profile if (!$field_id) { - trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'UPDATE ' . PROFILE_FIELDS_TABLE . " @@ -275,7 +280,7 @@ class acp_profile { if (!$field_id) { - trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_FIELD_ID'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT l.*, f.* @@ -289,7 +294,7 @@ class acp_profile if (!$field_row) { - trigger_error($user->lang['FIELD_NOT_FOUND'] . adm_back_link($this->u_action)); + trigger_error($user->lang['FIELD_NOT_FOUND'] . adm_back_link($this->u_action), E_USER_WARNING); } $field_type = $field_row['field_type']; @@ -319,7 +324,7 @@ class acp_profile if (!$field_type) { - trigger_error($user->lang['NO_FIELD_TYPE'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_FIELD_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING); } $field_row = array_merge($default_values[$field_type], array( @@ -359,7 +364,7 @@ class acp_profile $cp->vars['lang_name'] = request_var('lang_name', $field_row['lang_name'], true); $cp->vars['lang_explain'] = request_var('lang_explain', $field_row['lang_explain'], true); $cp->vars['lang_default_value'] = request_var('lang_default_value', $field_row['lang_default_value'], true); - + // Field option... if (isset($_REQUEST['field_option'])) { @@ -525,7 +530,8 @@ class acp_profile } } - if ($submit && $step == 1) + // Check for general issues in every step + if ($submit) // && $step == 1 { // Check values for step 1 if ($cp->vars['field_ident'] == '') @@ -538,16 +544,39 @@ class acp_profile $error[] = $user->lang['INVALID_CHARS_FIELD_IDENT']; } + if (strlen($cp->vars['field_ident']) > 17) + { + $error[] = $user->lang['INVALID_FIELD_IDENT_LEN']; + } + if ($cp->vars['lang_name'] == '') { $error[] = $user->lang['EMPTY_USER_FIELD_NAME']; } - if ($field_type == FIELD_BOOL || $field_type == FIELD_DROPDOWN) + if ($field_type == FIELD_DROPDOWN && !sizeof($cp->vars['lang_options'])) + { + $error[] = $user->lang['NO_FIELD_ENTRIES']; + } + + if ($field_type == FIELD_BOOL && (empty($cp->vars['lang_options'][0]) || empty($cp->vars['lang_options'][1]))) { - if (!sizeof($cp->vars['lang_options'])) + $error[] = $user->lang['NO_FIELD_ENTRIES']; + } + + // Check for already existing field ident + if ($action != 'edit') + { + $sql = 'SELECT field_ident + FROM ' . PROFILE_FIELDS_TABLE . " + WHERE field_ident = '" . $db->sql_escape($cp->vars['field_ident']) . "'"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if ($row) { - $error[] = $user->lang['NO_FIELD_ENTRIES']; + $error[] = $user->lang['FIELD_IDENT_ALREADY_EXIST']; } } } @@ -730,12 +759,20 @@ class acp_profile ORDER BY field_order'; $result = $db->sql_query($sql); + $s_one_need_edit = false; while ($row = $db->sql_fetchrow($result)) { $active_lang = (!$row['field_active']) ? 'ACTIVATE' : 'DEACTIVATE'; $active_value = (!$row['field_active']) ? 'activate' : 'deactivate'; $id = $row['field_id']; + $s_need_edit = (sizeof($lang_defs['diff'][$row['field_id']])) ? true : false; + + if ($s_need_edit) + { + $s_one_need_edit = true; + } + $template->assign_block_vars('fields', array( 'FIELD_IDENT' => $row['field_ident'], 'FIELD_TYPE' => $user->lang['FIELD_' . strtoupper($cp->profile_types[$row['field_type']])], @@ -743,15 +780,22 @@ class acp_profile 'L_ACTIVATE_DEACTIVATE' => $user->lang[$active_lang], 'U_ACTIVATE_DEACTIVATE' => $this->u_action . "&action=$active_value&field_id=$id", 'U_EDIT' => $this->u_action . "&action=edit&field_id=$id", + 'U_TRANSLATE' => $this->u_action . "&action=edit&field_id=$id&step=3", 'U_DELETE' => $this->u_action . "&action=delete&field_id=$id", 'U_MOVE_UP' => $this->u_action . "&action=move_up&order={$row['field_order']}", 'U_MOVE_DOWN' => $this->u_action . "&action=move_down&order={$row['field_order']}", - 'S_NEED_EDIT' => (sizeof($lang_defs['diff'][$row['field_id']])) ? true : false) + 'S_NEED_EDIT' => $s_need_edit) ); } $db->sql_freeresult($result); + // At least one option field needs editing? + if ($s_one_need_edit) + { + $template->assign_var('S_NEED_EDIT', true); + } + $s_select_type = ''; foreach ($cp->profile_types as $key => $value) { @@ -831,12 +875,11 @@ class acp_profile $lang_options[$lang_id]['lang_iso'] = $lang_iso; foreach ($options as $field => $field_type) { - $value = ($action == 'create') ? request_var('l_' . $field, '', true) : $cp->vars['l_' . $field]; - + $value = ($action == 'create') ? request_var('l_' . $field, array(0 => ''), true) : $cp->vars['l_' . $field]; + if ($field == 'lang_options') { - - $var = ($action == 'create' || !is_array($cp->vars['lang_options'][$lang_id])) ? $cp->vars['lang_options'] : $cp->vars['lang_options'][$lang_id]; + $var = ($action == 'create' || !is_array($cp->vars['l_lang_options'][$lang_id])) ? $cp->vars['lang_options'] : $cp->vars['lang_options'][$lang_id]; switch ($field_type) { @@ -948,7 +991,7 @@ class acp_profile if ($action == 'create') { - $field_ident = '_' . $field_ident; + $field_ident = 'pf_' . $field_ident; $profile_sql[] = $this->add_field_ident($field_ident, $field_type); } @@ -1003,10 +1046,11 @@ class acp_profile } } - $cp->vars['l_lang_name'] = request_var('l_lang_name', '', true); - $cp->vars['l_lang_explain'] = request_var('l_lang_explain', '', true); - $cp->vars['l_lang_default_value'] = request_var('l_lang_default_value', '', true); - $cp->vars['l_lang_options'] = request_var('l_lang_options', '', true); + // These are always arrays because the key is the language id... + $cp->vars['l_lang_name'] = request_var('l_lang_name', array(0 => ''), true); + $cp->vars['l_lang_explain'] = request_var('l_lang_explain', array(0 => ''), true); + $cp->vars['l_lang_default_value'] = request_var('l_lang_default_value', array(0 => ''), true); + $cp->vars['l_lang_options'] = request_var('l_lang_options', array(0 => ''), true); if ($cp->vars['lang_options']) { @@ -1155,7 +1199,7 @@ class acp_profile } else { - add_log('admin', 'LOG_PROFILE_FIELD_CREATE', substr($field_ident, 1) . ':' . $cp->vars['lang_name']); + add_log('admin', 'LOG_PROFILE_FIELD_CREATE', substr($field_ident, 3) . ':' . $cp->vars['lang_name']); trigger_error($user->lang['ADDED_PROFILE_FIELD'] . adm_back_link($this->u_action)); } } @@ -1215,7 +1259,7 @@ class acp_profile { global $db; - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'mysql': case 'mysql4': diff --git a/phpBB/includes/acp/acp_prune.php b/phpBB/includes/acp/acp_prune.php index 4752e7bafe..e71fe33557 100644 --- a/phpBB/includes/acp/acp_prune.php +++ b/phpBB/includes/acp/acp_prune.php @@ -155,7 +155,7 @@ class acp_prune if (!$row) { $db->sql_freeresult($result); - trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action), E_USER_WARNING); } $forum_list = $s_hidden_fields = ''; @@ -196,17 +196,18 @@ class acp_prune { if (confirm_box(true)) { - $users = request_var('users', ''); + $users = request_var('users', '', true); $action = request_var('action', 'deactivate'); $deleteposts = request_var('deleteposts', 0); if ($users) { - $where_sql = ' AND ' . $db->sql_in_set('username', explode("\n", $users)); + $users = explode("\n", $users); + $where_sql = ' AND ' . $db->sql_in_set('username_clean', array_map('utf8_clean_string', $users)); } else { - $username = request_var('username', ''); + $username = request_var('username', '', true); $email = request_var('email', ''); $joined_select = request_var('joined_select', 'lt'); @@ -224,7 +225,7 @@ class acp_prune $sort_by_types = array('username', 'user_email', 'user_posts', 'user_regdate', 'user_lastvisit'); $where_sql = ''; - $where_sql .= ($username) ? " AND username LIKE '" . $db->sql_escape(str_replace('*', '%', $username)) . "'" : ''; + $where_sql .= ($username) ? " AND username_clean LIKE '" . $db->sql_escape(str_replace('*', '%', utf8_clean_string($username))) . "'" : ''; $where_sql .= ($email) ? " AND user_email LIKE '" . $db->sql_escape(str_replace('*', '%', $email)) . "' " : ''; $where_sql .= (sizeof($joined)) ? " AND user_regdate " . $key_match[$joined_select] . ' ' . gmmktime(0, 0, 0, (int) $joined[1], (int) $joined[2], (int) $joined[0]) : ''; $where_sql .= ($count) ? " AND user_posts " . $key_match[$count_select] . " $count " : ''; @@ -244,7 +245,8 @@ class acp_prune $db->sql_freeresult($result); // Do not prune founder members - $sql = 'SELECT username, user_id FROM ' . USERS_TABLE . ' + $sql = 'SELECT user_id, username + FROM ' . USERS_TABLE . ' WHERE user_id <> ' . ANONYMOUS . ' AND user_type <> ' . USER_FOUNDER . " $where_sql"; @@ -267,11 +269,7 @@ class acp_prune { if ($action == 'deactivate') { - foreach ($user_ids as $user_id) - { - user_active_flip($user_id, USER_NORMAL, false, false, true); - } - + user_active_flip('deactivate', $user_ids); $l_log = 'LOG_PRUNE_USER_DEAC'; } else if ($action == 'delete') @@ -309,7 +307,7 @@ class acp_prune 'prune' => 1, 'users' => request_var('users', ''), - 'username' => request_var('username', ''), + 'username' => request_var('username', '', true), 'email' => request_var('email', ''), 'joined_select' => request_var('joined_select', ''), 'joined' => request_var('joined', ''), diff --git a/phpBB/includes/acp/acp_ranks.php b/phpBB/includes/acp/acp_ranks.php index 59505c34c2..db96b173e8 100644 --- a/phpBB/includes/acp/acp_ranks.php +++ b/phpBB/includes/acp/acp_ranks.php @@ -48,14 +48,14 @@ class acp_ranks if (!$rank_title) { - trigger_error($user->lang['NO_RANK_TITLE'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_RANK_TITLE'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql_ary = array( 'rank_title' => $rank_title, 'rank_special' => $special_rank, 'rank_min' => $min_posts, - 'rank_image' => html_entity_decode($rank_image) + 'rank_image' => htmlspecialchars_decode($rank_image) ); if ($rank_id) @@ -96,7 +96,7 @@ class acp_ranks } else { - trigger_error($user->lang['MUST_SELECT_RANK'] . adm_back_link($this->u_action)); + trigger_error($user->lang['MUST_SELECT_RANK'] . adm_back_link($this->u_action), E_USER_WARNING); } break; diff --git a/phpBB/includes/acp/acp_reasons.php b/phpBB/includes/acp/acp_reasons.php index 402663ad90..72419de1ef 100644 --- a/phpBB/includes/acp/acp_reasons.php +++ b/phpBB/includes/acp/acp_reasons.php @@ -61,11 +61,11 @@ class acp_reasons $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - if ($row['reason_title'] == 'other') + if (strtolower($row['reason_title']) == 'other') { $reason_row['reason_title'] = 'other'; } - else if (strtolower($row['reason_title']) != strtolower($reason_row['reason_title'])) + else if ($row['reason_title'] != $reason_row['reason_title']) { $check_double = true; } @@ -76,12 +76,12 @@ class acp_reasons { $sql = 'SELECT reason_id FROM ' . REPORTS_REASONS_TABLE . " - WHERE LOWER(reason_title) = '" . strtolower($db->sql_escape($reason_row['reason_title'])) . "'"; + WHERE reason_title = '" . $db->sql_escape($reason_row['reason_title']) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - if ($row) + if ($row || ($action == 'add' && strtolower($reason_row['reason_title']) == 'other')) { $error[] = $user->lang['REASON_ALREADY_EXIST']; } @@ -137,7 +137,7 @@ class acp_reasons if (!$reason_row) { - trigger_error($user->lang['NO_REASON'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_REASON'] . adm_back_link($this->u_action), E_USER_WARNING); } } @@ -159,10 +159,14 @@ class acp_reasons 'REASON_TITLE' => $reason_row['reason_title'], 'REASON_DESCRIPTION' => $reason_row['reason_description'], - - 'S_EDIT_REASON' => true, - 'S_TRANSLATED' => $translated, - 'S_ERROR' => (sizeof($error)) ? true : false, + + 'TRANSLATED_TITLE' => ($translated) ? $user->lang['report_reasons']['TITLE'][strtoupper($reason_row['reason_title'])] : '', + 'TRANSLATED_DESCRIPTION'=> ($translated) ? $user->lang['report_reasons']['DESCRIPTION'][strtoupper($reason_row['reason_title'])] : '', + + 'S_AVAILABLE_TITLES' => implode(', ', array_map('htmlspecialchars', array_keys($user->lang['report_reasons']['TITLE']))), + 'S_EDIT_REASON' => true, + 'S_TRANSLATED' => $translated, + 'S_ERROR' => (sizeof($error)) ? true : false, ) ); @@ -180,12 +184,12 @@ class acp_reasons if (!$reason_row) { - trigger_error($user->lang['NO_REASON'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_REASON'] . adm_back_link($this->u_action), E_USER_WARNING); } - if ($reason_row['reason_title'] == 'other') + if (strtolower($reason_row['reason_title']) == 'other') { - trigger_error($user->lang['NO_REMOVE_DEFAULT_REASON'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_REMOVE_DEFAULT_REASON'] . adm_back_link($this->u_action), E_USER_WARNING); } // Let the deletion be confirmed... @@ -193,12 +197,12 @@ class acp_reasons { $sql = 'SELECT reason_id FROM ' . REPORTS_REASONS_TABLE . " - WHERE reason_title = 'other'"; + WHERE LOWER(reason_title) = 'other'"; $result = $db->sql_query($sql); $other_reason_id = (int) $db->sql_fetchfield('reason_id'); $db->sql_freeresult($result); - switch (SQL_LAYER) + switch ($db->sql_layer) { // The ugly one! case 'mysqli': @@ -214,9 +218,17 @@ class acp_reasons case 'mssql': case 'mssql_odbc': // Change the reports using this reason to 'other' - $sql = 'UPDATE ' . REPORTS_TABLE . ' - SET reason_id = ' . $other_reason_id . ", report_text = '" . $db->sql_escape($reason_row['reason_description']) . "\n\n' + report_text - WHERE reason_id = $reason_id"; + $sql = "DECLARE @ptrval binary(16) + + SELECT @ptrval = TEXTPTR(report_text) + FROM " . REPORTS_TABLE . " + WHERE reason_id = " . $reason_id . " + + UPDATETEXT " . REPORTS_TABLE . ".report_text @ptrval 0 0 '" . $db->sql_escape($reason_row['reason_description']) . "\n\n' + + UPDATE " . REPORTS_TABLE . ' + SET reason_id = ' . $other_reason_id . " + WHERE reason_id = $reason_id"; break; // Teh standard @@ -319,7 +331,7 @@ class acp_reasons // If the reason is defined within the language file, we will use the localized version, else just use the database entry... if (isset($user->lang['report_reasons']['TITLE'][strtoupper($row['reason_title'])]) && isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])])) { - $row['reson_description'] = $user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])]; + $row['reason_description'] = $user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])]; $row['reason_title'] = $user->lang['report_reasons']['TITLE'][strtoupper($row['reason_title'])]; $translated = true; diff --git a/phpBB/includes/acp/acp_search.php b/phpBB/includes/acp/acp_search.php index b7c37772ed..6b1eefe8e6 100644 --- a/phpBB/includes/acp/acp_search.php +++ b/phpBB/includes/acp/acp_search.php @@ -152,7 +152,7 @@ class acp_search } else { - trigger_error($error); + trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING); } } else @@ -168,7 +168,7 @@ class acp_search } else { - trigger_error($error); + trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING); } } @@ -228,7 +228,8 @@ class acp_search break; default: - trigger_error('NO_ACTION'); + trigger_error('NO_ACTION', E_USER_ERROR); + break; } if (empty($this->state[0])) @@ -240,7 +241,7 @@ class acp_search $error = false; if ($this->init_search($this->state[0], $this->search, $error)) { - trigger_error($error); + trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING); } $action = &$this->state[1]; @@ -262,7 +263,7 @@ class acp_search { $this->state = array(''); $this->save_state(); - trigger_error($error . adm_back_link($this->u_action) . $this->close_popup_js()); + trigger_error($error . adm_back_link($this->u_action) . $this->close_popup_js(), E_USER_WARNING); } } else @@ -294,7 +295,7 @@ class acp_search if ($post_counter <= $this->max_post_id) { - redirect($this->u_action . '&action=delete', 3); + redirect($this->u_action . '&action=delete'); } } @@ -314,12 +315,12 @@ class acp_search { $this->state = array(''); $this->save_state(); - trigger_error($error . adm_back_link($this->u_action) . $this->close_popup_js()); + trigger_error($error . adm_back_link($this->u_action) . $this->close_popup_js(), E_USER_WARNING); } } else { - $sql = 'SELECT post_id, post_subject, post_text, post_encoding, poster_id, forum_id + $sql = 'SELECT post_id, post_subject, post_text, poster_id, forum_id FROM ' . POSTS_TABLE . ' WHERE post_id >= ' . (int) ($post_counter + 1) . ' AND post_id < ' . (int) ($post_counter + $this->batch_size); @@ -327,7 +328,7 @@ class acp_search while ($row = $db->sql_fetchrow($result)) { - $this->search->index('post', $row['post_id'], $row['post_text'], $row['post_subject'], $row['post_encoding'], $row['poster_id'], $row['forum_id']); + $this->search->index('post', $row['post_id'], $row['post_text'], $row['post_subject'], $row['poster_id'], $row['forum_id']); } $db->sql_freeresult($result); @@ -338,7 +339,7 @@ class acp_search if ($post_counter <= $this->max_post_id) { - redirect($this->u_action . '&action=create', 3); + redirect($this->u_action . '&action=create'); } } @@ -440,7 +441,7 @@ class acp_search adm_page_header($user->lang[$l_type]); $template->set_filenames(array( - 'body' => 'search_index_progress_bar.html') + 'body' => 'progress_bar.html') ); $template->assign_vars(array( diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php index 48277dc487..4377dd7e20 100644 --- a/phpBB/includes/acp/acp_styles.php +++ b/phpBB/includes/acp/acp_styles.php @@ -191,7 +191,7 @@ pagination_sep = \'{PAGINATION_SEP}\' if ($style_id == $config['default_style']) { - trigger_error($user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($this->u_action)); + trigger_error($user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'UPDATE ' . STYLES_TABLE . ' @@ -234,7 +234,7 @@ pagination_sep = \'{PAGINATION_SEP}\' if (!$template_row) { - trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); } if (confirm_box(true)) @@ -311,12 +311,12 @@ pagination_sep = \'{PAGINATION_SEP}\' if (!$theme_row) { - trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING); } if (!$theme_row['theme_storedb']) { - trigger_error($user->lang['THEME_ERR_REFRESH_FS'] . adm_back_link($this->u_action)); + trigger_error($user->lang['THEME_ERR_REFRESH_FS'] . adm_back_link($this->u_action), E_USER_WARNING); } if (confirm_box(true)) @@ -369,7 +369,7 @@ pagination_sep = \'{PAGINATION_SEP}\' if (!$imageset_row) { - trigger_error($user->lang['NO_IMAGESET'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_IMAGESET'] . adm_back_link($this->u_action), E_USER_WARNING); } if (confirm_box(true)) @@ -397,9 +397,12 @@ pagination_sep = \'{PAGINATION_SEP}\' } unset($cfg_data); - $sql = 'UPDATE ' . STYLES_IMAGESET_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE imageset_id = $style_id"; - $db->sql_query($sql); + if (sizeof($sql_ary)) + { + $sql = 'UPDATE ' . STYLES_IMAGESET_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " + WHERE imageset_id = $style_id"; + $db->sql_query($sql); + } $cache->destroy('sql', STYLES_IMAGESET_TABLE); @@ -533,7 +536,7 @@ pagination_sep = \'{PAGINATION_SEP}\' while (($file = readdir($dp)) !== false) { $subpath = ($mode != 'style') ? "$mode/" : ''; - if ($file{0} != '.' && file_exists("{$phpbb_root_path}styles/$file/$subpath$mode.cfg")) + if ($file[0] != '.' && file_exists("{$phpbb_root_path}styles/$file/$subpath$mode.cfg")) { if ($cfg = file("{$phpbb_root_path}styles/$file/$subpath$mode.cfg")) { @@ -590,7 +593,7 @@ pagination_sep = \'{PAGINATION_SEP}\' $_POST['template_data'] = (isset($_POST['template_data']) && !empty($_POST['template_data'])) ? str_replace(array("\r\n", "\r"), array("\n", "\n"), $_POST['template_data']) : ''; $template_data = (STRIP) ? stripslashes($_POST['template_data']) : $_POST['template_data']; - $template_file = request_var('template_file', ''); + $template_file = request_var('template_file', ''); $text_rows = max(5, min(999, request_var('text_rows', 20))); $save_changes = (isset($_POST['save'])) ? true : false; @@ -602,12 +605,13 @@ pagination_sep = \'{PAGINATION_SEP}\' FROM ' . STYLES_TEMPLATE_TABLE . " WHERE template_id = $template_id"; $result = $db->sql_query($sql); + $template_info = $db->sql_fetchrow($result); + $db->sql_freeresult($result); - if (!($template_info = $db->sql_fetchrow($result))) + if (!$template_info) { - trigger_error($user->lang['NO_TEMPLATE']); + trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); } - $db->sql_freeresult($result); // save changes to the template if the user submitted any if ($save_changes && $template_file) @@ -621,7 +625,7 @@ pagination_sep = \'{PAGINATION_SEP}\' { if (!($fp = fopen($file, 'wb'))) { - trigger_error($user->lang['NO_TEMPLATE']); + trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); } fwrite($fp, $template_data); fclose($fp); @@ -674,7 +678,7 @@ pagination_sep = \'{PAGINATION_SEP}\' { if (!file_exists($template_path . "/$template_file") || !($template_data = file_get_contents($template_path . "/$template_file"))) { - trigger_error($user->lang['NO_TEMPLATE']); + trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); } } } @@ -779,7 +783,7 @@ pagination_sep = \'{PAGINATION_SEP}\' 'SELECTED_TEMPLATE' => $template_info['template_name'], 'TEMPLATE_FILE' => $template_file, - 'TEMPLATE_DATA' => htmlentities($template_data), + 'TEMPLATE_DATA' => htmlspecialchars($template_data), 'TEXT_ROWS' => $text_rows) ); } @@ -801,12 +805,13 @@ pagination_sep = \'{PAGINATION_SEP}\' FROM ' . STYLES_TEMPLATE_TABLE . " WHERE template_id = $template_id"; $result = $db->sql_query($sql); + $template_row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); - if (!($template_row = $db->sql_fetchrow($result))) + if (!$template_row) { - trigger_error($user->lang['NO_TEMPLATE']); + trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); } - $db->sql_freeresult($result); // User wants to delete one or more files ... if ($submit && $file_ary) @@ -941,7 +946,7 @@ pagination_sep = \'{PAGINATION_SEP}\' if (!($theme_info = $db->sql_fetchrow($result))) { - trigger_error($user->lang['NO_THEME']); + trigger_error($user->lang['NO_THEME'] . adm_bacl_link($this->u_action), E_USER_WARNING); } $db->sql_freeresult($result); @@ -951,7 +956,7 @@ pagination_sep = \'{PAGINATION_SEP}\' { if (!file_exists($stylesheet_path) || !($stylesheet = file_get_contents($stylesheet_path))) { - trigger_error($user->lang['NO_THEME']); + trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING); } } else @@ -961,7 +966,7 @@ pagination_sep = \'{PAGINATION_SEP}\' // Pull out a list of classes $classes = array(); - if (preg_match_all('/^([a-z0-9\.:#> \t]+?)[ \t\n]*?\{.*?\}/msi', $stylesheet, $matches)) + if (preg_match_all('/^([a-z0-9\.,:#> \t]+?)[ \t\n]*?\{.*?\}/msi', $stylesheet, $matches)) { $classes = $matches[1]; } @@ -1007,7 +1012,7 @@ pagination_sep = \'{PAGINATION_SEP}\' // Used in an sprintf statement to generate appropriate output for rawcss mode $map_elements = array( 'colors' => '%s', - 'sizes' => '%d', + 'sizes' => '%1.10f', 'images' => 'url(\'./%s\')', 'repeat' => '%s', 'other' => '%s', @@ -1015,11 +1020,11 @@ pagination_sep = \'{PAGINATION_SEP}\' $units = array('px', '%', 'em', 'pt'); $repeat_types = array( - '' => $user->lang['UNSET'], - 'none' => $user->lang['REPEAT_NO'], - 'repeat-x' => $user->lang['REPEAT_X'], - 'repeat-y' => $user->lang['REPEAT_Y'], - 'both' => $user->lang['REPEAT_ALL'], + '' => $user->lang['UNSET'], + 'none' => $user->lang['REPEAT_NO'], + 'repeat-x' => $user->lang['REPEAT_X'], + 'repeat-y' => $user->lang['REPEAT_Y'], + 'both' => $user->lang['REPEAT_ALL'], ); // Fill css_data with the class contents from the stylesheet @@ -1030,7 +1035,7 @@ pagination_sep = \'{PAGINATION_SEP}\' if (!isset($matches[1])) { - trigger_error($user->lang['NO_CLASS']); + trigger_error($user->lang['NO_CLASS'] . adm_back_link($this->u_action), E_USER_WARNING); } $css_data = implode(";\n", array_diff(array_map('trim', explode("\n", preg_replace("#;[\n]*#s", "\n", $matches[1]))), array(''))); @@ -1183,11 +1188,11 @@ pagination_sep = \'{PAGINATION_SEP}\' $value = ''; $unit = ''; - // retrieve and validate date for this setting + // retrieve and validate data for this setting switch ($type) { case 'sizes': - $value = request_var($var, 0); + $value = request_var($var, 0.0); $unit = request_var($var . '_unit', ''); if ((request_var($var, '') === '') || !in_array($unit, $units)) @@ -1227,7 +1232,7 @@ pagination_sep = \'{PAGINATION_SEP}\' // use the element mapping to create raw css code if ($value !== '') { - $css_data .= $match . ': ' . sprintf($map_elements[$type], $value) . $unit . ";\n"; + $css_data .= $match . ': ' . ($type == 'sizes' ? rtrim(sprintf($map_elements[$type], $value), '0') : sprintf($map_elements[$type], $value)) . $unit . ";\n"; } } } @@ -1262,7 +1267,7 @@ pagination_sep = \'{PAGINATION_SEP}\' // check whether the custom class name is valid if (!preg_match('/^[a-z0-9#:.\- ]+$/i', $add_custom)) { - trigger_error($user->lang['THEME_ERR_CLASS_CHARS'] . adm_back_link($this->u_action . "&action=edit&id=$theme_id&text_rows=$text_rows")); + trigger_error($user->lang['THEME_ERR_CLASS_CHARS'] . adm_back_link($this->u_action . "&action=edit&id=$theme_id&text_rows=$text_rows"), E_USER_WARNING); } else { @@ -1278,7 +1283,7 @@ pagination_sep = \'{PAGINATION_SEP}\' // write stylesheet to file if (!($fp = fopen($stylesheet_path, 'wb'))) { - trigger_error($user->lang['NO_THEME']); + trigger_error($user->lang['NO_THEME'] . adm_back_link($this->u_action), E_USER_WARNING); } fwrite($fp, $stylesheet); fclose($fp); @@ -1348,16 +1353,19 @@ pagination_sep = \'{PAGINATION_SEP}\' if ($imageset_id) { $sql_select = ($imgname) ? ", $imgname" : ''; + $sql = "SELECT imageset_path, imageset_name, imageset_copyright$sql_select FROM " . STYLES_IMAGESET_TABLE . " WHERE imageset_id = $imageset_id"; $result = $db->sql_query($sql); + $imageset_row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); - if (!extract($db->sql_fetchrow($result))) + if (!$imageset_row) { - trigger_error($user->lang['NO_IMAGESET']); + trigger_error($user->lang['NO_IMAGESET'] . adm_back_link($this->u_action), E_USER_WARNING); } - $db->sql_freeresult($result); + extract($imageset_row); // Check to see whether the selected image exists in the table $valid_name = ($update) ? false : true; @@ -1431,7 +1439,7 @@ pagination_sep = \'{PAGINATION_SEP}\' $dp = opendir($dir); while (($file = readdir($dp)) !== false) { - if (!is_file($dir . '/' . $file) && !is_link($dir . '/' . $file) && $file{0} != '.' && strtoupper($file) != 'CVS' && !sizeof($imagesetlist['lang'])) + if (!is_file($dir . '/' . $file) && !is_link($dir . '/' . $file) && $file[0] != '.' && strtoupper($file) != 'CVS' && !sizeof($imagesetlist['lang'])) { $dp2 = opendir("$dir/$file"); while (($file2 = readdir($dp2)) !== false) @@ -1540,7 +1548,7 @@ pagination_sep = \'{PAGINATION_SEP}\' if (!$style_row) { - trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = "SELECT {$mode}_id, {$mode}_name @@ -1561,7 +1569,7 @@ pagination_sep = \'{PAGINATION_SEP}\' } else { - trigger_error($user->lang['ONLY_' . $l_prefix] . adm_back_link($this->u_action)); + trigger_error($user->lang['ONLY_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING); } $db->sql_freeresult($result); @@ -1719,7 +1727,7 @@ pagination_sep = \'{PAGINATION_SEP}\' if (!$style_row) { - trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING); } $var_ary = array('style_id', 'style_name', 'style_copyright', 'template_id', 'template_name', 'template_path', 'template_copyright', 'template_storedb', 'bbcode_bitfield', 'theme_id', 'theme_name', 'theme_path', 'theme_copyright', 'theme_storedb', 'theme_mtime', 'theme_data', 'imageset_id', 'imageset_name', 'imageset_path', 'imageset_copyright'); @@ -1843,7 +1851,7 @@ pagination_sep = \'{PAGINATION_SEP}\' { foreach ($key_array as $key) { - $imageset_cfg .= "\n" . $key . ' = ' . str_replace("styles/{$style_row['imageset_path']}/imageset/", '{PATH}', $style_row[$key]); + $imageset_cfg .= "\nimg_" . $key . ' = ' . str_replace("styles/{$style_row['imageset_path']}/imageset/", '{PATH}', $style_row[$key]); } } @@ -1951,7 +1959,7 @@ pagination_sep = \'{PAGINATION_SEP}\' if (!$style_row) { - trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_' . $l_prefix] . adm_back_link($this->u_action), E_USER_WARNING); } $this->page_title = $l_prefix . '_EXPORT'; @@ -2021,7 +2029,7 @@ pagination_sep = \'{PAGINATION_SEP}\' if (!$style_row) { - trigger_error($user->lang['NO_' . $l_type] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_' . $l_type] . adm_back_link($this->u_action), E_USER_WARNING); } $style_row['style_default'] = ($mode == 'style' && $config['default_style'] == $style_id) ? 1 : 0; @@ -2057,12 +2065,12 @@ pagination_sep = \'{PAGINATION_SEP}\' if (!sizeof($error)) { // Check length settings - if (strlen($name) > 30) + if (utf8_strlen($name) > 30) { $error[] = $user->lang[$l_type . '_ERR_NAME_LONG']; } - if (strlen($copyright) > 60) + if (utf8_strlen($copyright) > 60) { $error[] = $user->lang[$l_type . '_ERR_COPY_LONG']; } @@ -2308,7 +2316,7 @@ pagination_sep = \'{PAGINATION_SEP}\' { foreach ($matches[0] as $idx => $match) { - $stylesheet = str_replace($match, $this->load_css_file($theme_row['theme_path'], $matches[1][$idx]), $stylesheet); + $stylesheet = str_replace($match, acp_styles::load_css_file($theme_row['theme_path'], $matches[1][$idx]), $stylesheet); } } @@ -2331,7 +2339,7 @@ pagination_sep = \'{PAGINATION_SEP}\' { if (!($fp = fopen("{$phpbb_root_path}styles/$template_path$pathfile$file", 'r'))) { - trigger_error("Could not open {$phpbb_root_path}styles/$template_path$pathfile$file"); + trigger_error("Could not open {$phpbb_root_path}styles/$template_path$pathfile$file", E_USER_ERROR); } $template_data = fread($fp, filesize("{$phpbb_root_path}styles/$template_path$pathfile$file")); fclose($fp); @@ -2396,7 +2404,7 @@ pagination_sep = \'{PAGINATION_SEP}\' if (!($dp = @opendir("{$phpbb_root_path}cache"))) { - trigger_error($user->lang['TEMPLATE_ERR_CACHE_READ']); + trigger_error($user->lang['TEMPLATE_ERR_CACHE_READ'] . adm_back_link($this->u_action), E_USER_WARNING); } $file_ary = array(); @@ -2538,7 +2546,7 @@ pagination_sep = \'{PAGINATION_SEP}\' } else { - trigger_error($user->lang['NO_' . $l_type] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_' . $l_type] . adm_back_link($this->u_action), E_USER_WARNING); } $style_row['store_db'] = request_var('store_db', 0); @@ -2822,12 +2830,12 @@ pagination_sep = \'{PAGINATION_SEP}\' } // Check length settings - if (strlen($name) > 30) + if (utf8_strlen($name) > 30) { $error[] = $user->lang['STYLE_ERR_NAME_LONG']; } - if (strlen($copyright) > 60) + if (utf8_strlen($copyright) > 60) { $error[] = $user->lang['STYLE_ERR_COPY_LONG']; } @@ -2932,12 +2940,12 @@ pagination_sep = \'{PAGINATION_SEP}\' } // Check length settings - if (strlen($name) > 30) + if (utf8_strlen($name) > 30) { $error[] = $user->lang[$l_type . '_ERR_NAME_LONG']; } - if (strlen($copyright) > 60) + if (utf8_strlen($copyright) > 60) { $error[] = $user->lang[$l_type . '_ERR_COPY_LONG']; } diff --git a/phpBB/includes/acp/acp_update.php b/phpBB/includes/acp/acp_update.php new file mode 100644 index 0000000000..fac20449bc --- /dev/null +++ b/phpBB/includes/acp/acp_update.php @@ -0,0 +1,61 @@ +<?php +/** +* +* @package acp +* @version $Id$ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @package acp +*/ +class acp_update +{ + var $u_action; + + function main($id, $mode) + { + global $config, $db, $user, $auth, $template, $cache; + global $phpbb_root_path, $phpbb_admin_path, $phpEx; + + $user->add_lang('install'); + + $this->tpl_name = 'acp_update'; + $this->page_title = 'ACP_UPDATE'; + + // Get current and latest version + $errstr = ''; + $errno = 0; + + $info = get_remote_file('www.phpbb.com', '/updatecheck', '30x.txt', $errstr, $errno); + + if ($info === false) + { + trigger_error($errstr . adm_back_link($this->u_action)); + } + + $info = explode("\n", $info); + $latest_version = trim($info[0]); + + $announcement_url = trim($info[1]); + $update_archive_link = 'http://www.phpbb.com/files/releases/phpBB-' . $config['version'] . '_to_' . $latest_version . '.zip'; + $update_link = append_sid($phpbb_root_path . 'install/index.' . $phpEx, 'mode=update'); + + $up_to_date = (version_compare(strtolower($config['version']), strtolower($latest_version), '<')) ? false : true; + + $template->assign_vars(array( + 'S_UP_TO_DATE' => $up_to_date, + 'S_VERSION_CHECK' => true, + 'U_ACTION' => $this->u_action, + + 'LATEST_VERSION' => $latest_version, + 'CURRENT_VERSION' => $config['version'], + + 'UPDATE_INSTRUCTIONS' => sprintf($user->lang['UPDATE_INSTRUCTIONS'], $announcement_url, $update_archive_link, $update_link), + )); + } +} + +?>
\ No newline at end of file diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index e658609c5f..30c4e27b63 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -34,7 +34,7 @@ class acp_users include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx); $error = array(); - $username = request_var('username', ''); + $username = request_var('username', '', true); $user_id = request_var('u', 0); $action = request_var('action', ''); @@ -53,7 +53,7 @@ class acp_users if ($ipwhois = user_ipwhois($user_ip)) { $ipwhois = preg_replace('#(\s)([\w\-\._\+]+@[\w\-\.]+)(\s)#', '\1<a href="mailto:\2">\2</a>\3', $ipwhois); - $ipwhois = preg_replace('#(\s)(http:/{2}[^\s]*)(\s)#', '\1<a href="\2" target="_blank">\2</a>\3', $ipwhois); + $ipwhois = preg_replace('#(\s)(http:/{2}[^\s]*)(\s)#', '\1<a href="\2">\2</a>\3', $ipwhois); } $template->assign_vars(array( @@ -75,6 +75,7 @@ class acp_users 'S_SELECT_USER' => true, 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=select_user&field=username'), + 'UA_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=select_user&field=username', false), ) ); @@ -85,14 +86,14 @@ class acp_users { $sql = 'SELECT user_id FROM ' . USERS_TABLE . " - WHERE username = '" . $db->sql_escape($username) . "'"; + WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $result = $db->sql_query($sql); $user_id = (int) $db->sql_fetchfield('user_id'); $db->sql_freeresult($result); if (!$user_id) { - trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action), E_USER_WARNING); } } @@ -108,7 +109,7 @@ class acp_users if (!$user_row) { - trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_USER'] . adm_back_link($this->u_action), E_USER_WARNING); } // Generate overall "header" for user admin @@ -139,7 +140,7 @@ class acp_users // Prevent normal users/admins change/view founders if they are not a founder by themselves if ($user->data['user_type'] != USER_FOUNDER && $user_row['user_type'] == USER_FOUNDER) { - trigger_error($user->lang['NOT_MANAGE_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang['NOT_MANAGE_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } switch ($mode) @@ -157,23 +158,23 @@ class acp_users { if (!$auth->acl_get('a_userdel')) { - trigger_error($user->lang['NO_ADMIN'] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } // Check if the user wants to remove himself or the guest user account if ($user_id == ANONYMOUS) { - trigger_error($user->lang['CANNOT_REMOVE_ANONYMOUS'] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang['CANNOT_REMOVE_ANONYMOUS'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } if ($user_id == $user->data['user_id']) { - trigger_error($user->lang['CANNOT_REMOVE_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang['CANNOT_REMOVE_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } if (confirm_box(true)) { - user_delete($delete_type, $user_id); + user_delete($delete_type, $user_id, $user_row['username']); add_log('admin', 'LOG_USER_DELETED', $user_row['username']); trigger_error($user->lang['USER_DELETED'] . adm_back_link($this->u_action)); @@ -201,7 +202,12 @@ class acp_users if ($user_id == $user->data['user_id']) { - trigger_error($user->lang['CANNOT_BAN_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang['CANNOT_BAN_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); + } + + if ($user_row['user_type'] == USER_FOUNDER) + { + trigger_error($user->lang['CANNOT_BAN_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } $ban = array(); @@ -241,8 +247,8 @@ class acp_users user_ban(substr($action, 3), $ban, 0, 0, 0, $user->lang[$reason]); - add_log('admin', $log, $user->lang[$reason]); - add_log('user', $user_id, $log, $user->lang[$reason]); + add_log('admin', $log, $user->lang[$reason], implode(', ', $ban)); + add_log('user', $user_id, $log, $user->lang[$reason], implode(', ', $ban)); trigger_error($user->lang['BAN_SUCCESSFUL'] . adm_back_link($this->u_action . '&u=' . $user_id)); @@ -252,7 +258,17 @@ class acp_users if ($user_id == $user->data['user_id']) { - trigger_error($user->lang['CANNOT_FORCE_REACT_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang['CANNOT_FORCE_REACT_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); + } + + if ($user_row['user_type'] == USER_FOUNDER) + { + trigger_error($user->lang['CANNOT_FORCE_REACT_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); + } + + if ($user_row['user_type'] == USER_IGNORE) + { + trigger_error($user->lang['CANNOT_FORCE_REACT_BOT'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } if ($config['email_enable']) @@ -266,9 +282,14 @@ class acp_users $key_len = ($key_len > 6) ? $key_len : 6; $user_actkey = substr($user_actkey, 0, $key_len); - if ($user_row['user_type'] != USER_INACTIVE) + if ($user_row['user_type'] == USER_NORMAL) { - user_active_flip($user_id, $user_row['user_type'], $user_actkey, $user_row['username']); + user_active_flip('deactivate', $user_id, INACTIVE_REMIND); + + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_actkey = '" . $db->sql_escape($user_actkey) . "' + WHERE user_id = $user_id"; + $db->sql_query($sql); } $messenger = new messenger(false); @@ -284,11 +305,8 @@ class acp_users $messenger->headers('X-AntiAbuse: User IP - ' . $user->ip); $messenger->assign_vars(array( - 'SITENAME' => $config['sitename'], - 'WELCOME_MSG' => sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename']), - 'USERNAME' => html_entity_decode($user_row['username']), - 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']), - + 'WELCOME_MSG' => htmlspecialchars_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename'])), + 'USERNAME' => htmlspecialchars_decode($user_row['username']), 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k=$user_actkey") ); @@ -307,27 +325,26 @@ class acp_users if ($user_id == $user->data['user_id']) { // It is only deactivation since the user is already activated (else he would not have reached this page) - trigger_error($user->lang['CANNOT_DEACTIVATE_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang['CANNOT_DEACTIVATE_YOURSELF'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } - user_active_flip($user_id, $user_row['user_type'], false, $user_row['username']); - - $message = ($user_row['user_type'] == USER_INACTIVE) ? 'USER_ADMIN_ACTIVATED' : 'USER_ADMIN_DEACTIVED'; - $log = ($user_row['user_type'] == USER_INACTIVE) ? 'LOG_USER_ACTIVE' : 'LOG_USER_INACTIVE'; - - add_log('user', $user_id, $log . '_USER'); - - if ($user_row['user_type'] == USER_INACTIVE) + if ($user_row['user_type'] == USER_FOUNDER) { - set_config('num_users', $config['num_users'] + 1, true); + trigger_error($user->lang['CANNOT_DEACTIVATE_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } - else + + if ($user_row['user_type'] == USER_IGNORE) { - set_config('num_users', $config['num_users'] - 1, true); + trigger_error($user->lang['CANNOT_DEACTIVATE_BOT'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } - // Update latest username - update_last_username(); + user_active_flip('flip', $user_id); + + $message = ($user_row['user_type'] == USER_INACTIVE) ? 'USER_ADMIN_ACTIVATED' : 'USER_ADMIN_DEACTIVED'; + $log = ($user_row['user_type'] == USER_INACTIVE) ? 'LOG_USER_ACTIVE' : 'LOG_USER_INACTIVE'; + + add_log('admin', $log, $user_row['username']); + add_log('user', $user_id, $log . '_USER'); trigger_error($user->lang[$message] . adm_back_link($this->u_action . '&u=' . $user_id)); @@ -338,7 +355,7 @@ class acp_users $sql_ary = array( 'user_sig' => '', 'user_sig_bbcode_uid' => '', - 'user_sig_bbcode_bitfield' => 0 + 'user_sig_bbcode_bitfield' => '' ); $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " @@ -369,7 +386,7 @@ class acp_users // Delete old avatar if present if ($user_row['user_avatar'] && $user_row['user_avatar_type'] != AVATAR_GALLERY) { - avatar_delete($user_row['user_avatar']); + avatar_delete('user', $user_row); } add_log('admin', 'LOG_USER_DEL_AVATAR', $user_row['username']); @@ -599,32 +616,22 @@ class acp_users break; } - $data = array(); - // Handle registration info updates - $var_ary = array( - 'user' => (string) $user_row['username'], - 'user_founder' => (int) (($user_row['user_type'] == USER_FOUNDER) ? 1 : 0), - 'user_email' => (string) $user_row['user_email'], - 'email_confirm' => (string) '', - 'user_password' => (string) '', - 'password_confirm' => (string) '', - 'warnings' => (int) $user_row['user_warnings'], + $data = array( + 'username' => request_var('user', $user_row['username'], true), + 'user_founder' => request_var('user_founder', ($user_row['user_type'] == USER_FOUNDER) ? 1 : 0), + 'email' => request_var('user_email', $user_row['user_email']), + 'email_confirm' => request_var('email_confirm', ''), + 'user_password' => request_var('user_password', '', true), + 'password_confirm' => request_var('password_confirm', '', true), + 'warnings' => request_var('warnings', $user_row['user_warnings']), ); - // Get the data from the form. Use data from the database if no info is provided - foreach ($var_ary as $var => $default) - { - $data[$var] = request_var($var, $default); - } - - // We use user within the form to circumvent auto filling - $data['username'] = $data['user']; - unset($data['user']); - - // Validation data - $var_ary = array( - 'user_password' => array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), + // Validation data - we do not check the password complexity setting here + $check_ary = array( + 'user_password' => array( + array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), + array('password')), 'password_confirm' => array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), 'warnings' => array('num'), ); @@ -632,7 +639,7 @@ class acp_users // Check username if altered if ($data['username'] != $user_row['username']) { - $var_ary += array( + $check_ary += array( 'username' => array( array('string', false, $config['min_name_chars'], $config['max_name_chars']), array('username', $user_row['username'])), @@ -640,10 +647,10 @@ class acp_users } // Check email if altered - if ($data['user_email'] != $user_row['user_email']) + if ($data['email'] != $user_row['user_email']) { - $var_ary += array( - 'user_email' => array( + $check_ary += array( + 'email' => array( array('string', false, 6, 60), array('email', $user_row['user_email']) ), @@ -651,14 +658,14 @@ class acp_users ); } - $error = validate_data($data, $var_ary); + $error = validate_data($data, $check_ary); if ($data['user_password'] && $data['password_confirm'] != $data['user_password']) { $error[] = 'NEW_PASSWORD_ERROR'; } - if ($data['user_email'] != $user_row['user_email'] && $data['email_confirm'] != $data['user_email']) + if ($data['email'] != $user_row['user_email'] && $data['email_confirm'] != $data['email']) { $error[] = 'NEW_EMAIL_ERROR'; } @@ -667,7 +674,7 @@ class acp_users $update_warning = ($user_row['user_warnings'] != $data['warnings']) ? true : false; $update_username = ($user_row['username'] != $data['username']) ? $data['username'] : false; $update_password = ($data['user_password'] && $user_row['user_password'] != md5($data['user_password'])) ? true : false; - $update_email = ($data['user_email'] != $user_row['user_email']) ? $data['user_email'] : false; + $update_email = ($data['email'] != $user_row['user_email']) ? $data['email'] : false; if (!sizeof($error)) { @@ -686,6 +693,17 @@ class acp_users // Setting a normal member to be a founder if ($data['user_founder'] && $user_row['user_type'] != USER_FOUNDER) { + // Make sure the user is not setting an Inactive or ignored user to be a founder + if ($user_row['user_type'] == USER_IGNORE) + { + trigger_error($user->lang['CANNOT_SET_FOUNDER_BOT'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); + } + + if ($user_row['user_type'] == USER_INACTIVE) + { + trigger_error($user->lang['CANNOT_SET_FOUNDER_INACTIVE'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); + } + $sql_ary['user_type'] = USER_FOUNDER; } else if (!$data['user_founder'] && $user_row['user_type'] == USER_FOUNDER) @@ -705,7 +723,7 @@ class acp_users } else { - trigger_error($user->lang['AT_LEAST_ONE_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang['AT_LEAST_ONE_FOUNDER'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } } } @@ -714,6 +732,7 @@ class acp_users if ($update_username !== false) { $sql_ary['username'] = $update_username; + $sql_ary['username_clean'] = utf8_clean_string($update_username); add_log('user', $user_id, 'LOG_USER_UPDATE_NAME', $user_row['username'], $update_username); } @@ -772,6 +791,7 @@ class acp_users } $user_char_ary = array('.*' => 'USERNAME_CHARS_ANY', '[\w]+' => 'USERNAME_ALPHA_ONLY', '[\w_\+\. \-\[\]]+' => 'USERNAME_ALPHA_SPACERS'); + $pass_char_ary = array('.*' => 'PASS_TYPE_ANY', '[a-zA-Z]' => 'PASS_TYPE_CASE', '[a-zA-Z0-9]' => 'PASS_TYPE_ALPHA', '[a-zA-Z\W]' => 'PASS_TYPE_SYMBOL'); if ($user_id == $user->data['user_id']) { @@ -779,9 +799,21 @@ class acp_users } else { - $quick_tool_ary = array('banuser' => 'BAN_USER', 'banemail' => 'BAN_EMAIL', 'banip' => 'BAN_IP', 'active' => (($user_row['user_type'] == USER_INACTIVE) ? 'ACTIVATE' : 'DEACTIVATE'), 'delsig' => 'DEL_SIG', 'delavatar' => 'DEL_AVATAR', 'moveposts' => 'MOVE_POSTS', 'delposts' => 'DEL_POSTS', 'delattach' => 'DEL_ATTACH'); + $quick_tool_ary = array(); + + if ($user_row['user_type'] != USER_FOUNDER) + { + $quick_tool_ary += array('banuser' => 'BAN_USER', 'banemail' => 'BAN_EMAIL', 'banip' => 'BAN_IP'); + } + + if ($user_row['user_type'] != USER_FOUNDER && $user_row['user_type'] != USER_IGNORE) + { + $quick_tool_ary += array('active' => (($user_row['user_type'] == USER_INACTIVE) ? 'ACTIVATE' : 'DEACTIVATE')); + } - if ($config['email_enable']) + $quick_tool_ary += array('delsig' => 'DEL_SIG', 'delavatar' => 'DEL_AVATAR', 'moveposts' => 'MOVE_POSTS', 'delposts' => 'DEL_POSTS', 'delattach' => 'DEL_ATTACH'); + + if ($config['email_enable'] && ($user_row['user_type'] == USER_NORMAL || $user_row['user_type'] == USER_INACTIVE)) { $quick_tool_ary['reactivate'] = 'FORCE'; } @@ -793,9 +825,25 @@ class acp_users $s_action_options .= '<option value="' . $value . '">' . $user->lang['USER_ADMIN_' . $lang] . '</option>'; } + if ($config['load_onlinetrack']) + { + $sql = 'SELECT MAX(session_time) AS session_time, MIN(session_viewonline) AS session_viewonline + FROM ' . SESSIONS_TABLE . " + WHERE session_user_id = $user_id"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + $user_row['session_time'] = (isset($row['session_time'])) ? $row['session_time'] : 0; + $user_row['session_viewonline'] = (isset($row['session_viewonline'])) ? $row['session_viewonline'] : 0; + unset($row); + } + + $last_visit = (!empty($user_row['session_time'])) ? $user_row['session_time'] : $user_row['user_lastvisit']; + $template->assign_vars(array( - 'L_NAME_CHARS_EXPLAIN' => sprintf($user->lang[$user_char_ary[$config['allow_name_chars']] . '_EXPLAIN'], $config['min_name_chars'], $config['max_name_chars']), - 'L_CHANGE_PASSWORD_EXPLAIN' => sprintf($user->lang['CHANGE_PASSWORD_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), + 'L_NAME_CHARS_EXPLAIN' => sprintf($user->lang[$user_char_ary[str_replace('\\\\', '\\', $config['allow_name_chars'])] . '_EXPLAIN'], $config['min_name_chars'], $config['max_name_chars']), + 'L_CHANGE_PASSWORD_EXPLAIN' => sprintf($user->lang[$pass_char_ary[str_replace('\\\\', '\\', $config['pass_complex'])] . '_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), 'S_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false, 'S_OVERVIEW' => true, @@ -803,6 +851,7 @@ class acp_users 'S_USER_FOUNDER' => ($user_row['user_type'] == USER_FOUNDER) ? true : false, 'S_ACTION_OPTIONS' => $s_action_options, 'S_OWN_ACCOUNT' => ($user_id == $user->data['user_id']) ? true : false, + 'S_USER_INACTIVE' => ($user_row['user_type'] == USER_INACTIVE) ? true : false, 'U_SHOW_IP' => $this->u_action . "&u=$user_id&ip=" . (($ip == 'ip') ? 'hostname' : 'ip'), 'U_WHOIS' => $this->u_action . "&action=whois&user_ip={$user_row['user_ip']}", @@ -812,7 +861,7 @@ class acp_users 'USER' => $user_row['username'], 'USER_REGISTERED' => $user->format_date($user_row['user_regdate']), 'REGISTERED_IP' => ($ip == 'hostname') ? gethostbyaddr($user_row['user_ip']) : $user_row['user_ip'], - 'USER_LASTACTIVE' => ($user_row['user_lastvisit']) ? $user->format_date($user_row['user_lastvisit']) : ' - ', + 'USER_LASTACTIVE' => ($last_visit) ? $user->format_date($last_visit) : ' - ', 'USER_EMAIL' => $user_row['user_email'], 'USER_WARNINGS' => $user_row['user_warnings'], 'USER_POSTS' => $user_row['user_posts'], @@ -917,40 +966,45 @@ class acp_users $cp = new custom_profile(); $cp_data = $cp_error = array(); - $data = array(); $sql = 'SELECT lang_id FROM ' . LANG_TABLE . " - WHERE lang_iso = '" . $db->sql_escape($user_row['user_lang']) . "'"; + WHERE lang_iso = '" . $db->sql_escape($user->data['user_lang']) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); $user_row['iso_lang_id'] = $row['lang_id']; - if ($submit) + $data = array( + 'icq' => request_var('icq', $user_row['user_icq']), + 'aim' => request_var('aim', $user_row['user_aim']), + 'msn' => request_var('msn', $user_row['user_msnm']), + 'yim' => request_var('yim', $user_row['user_yim']), + 'jabber' => request_var('jabber', $user_row['user_jabber']), + 'website' => request_var('website', $user_row['user_website']), + 'location' => request_var('location', $user_row['user_from'], true), + 'occupation' => request_var('occupation', $user_row['user_occ'], true), + 'interests' => request_var('interests', $user_row['user_interests'], true), + 'bday_day' => 0, + 'bday_month' => 0, + 'bday_year' => 0, + ); + + utf8_normalize_nfc(array(&$data['location'], &$data['occupation'], &$data['interests'])); + + if ($user_row['user_birthday']) { - $var_ary = array( - 'icq' => (string) '', - 'aim' => (string) '', - 'msn' => (string) '', - 'yim' => (string) '', - 'jabber' => (string) '', - 'website' => (string) '', - 'location' => (string) '', - 'occupation' => (string) '', - 'interests' => (string) '', - 'bday_day' => 0, - 'bday_month' => 0, - 'bday_year' => 0, - ); + list($data['bday_day'], $data['bday_month'], $data['bday_year']) = explode('-', $user_row['user_birthday']); + } - foreach ($var_ary as $var => $default) - { - $data[$var] = (in_array($var, array('location', 'occupation', 'interests'))) ? request_var($var, $default, true) : $data[$var] = request_var($var, $default); - } + $data['bday_day'] = request_var('bday_day', $data['bday_day']); + $data['bday_month'] = request_var('bday_month', $data['bday_month']); + $data['bday_year'] = request_var('bday_year', $data['bday_year']); - $var_ary = array( + if ($submit) + { + $error = validate_data($data, array( 'icq' => array( array('string', true, 3, 15), array('match', true, '#^[0-9]+$#i')), @@ -969,9 +1023,7 @@ class acp_users 'bday_day' => array('num', true, 1, 31), 'bday_month' => array('num', true, 1, 12), 'bday_year' => array('num', true, 1901, gmdate('Y', time())), - ); - - $error = validate_data($data, $var_ary); + )); // validate custom profile fields $cp->submit_cp_field('profile', $user_row['iso_lang_id'], $cp_data, $cp_error); @@ -1004,7 +1056,7 @@ class acp_users // Update Custom Fields if (sizeof($cp_data)) { - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'oracle': case 'firebird': @@ -1057,18 +1109,6 @@ class acp_users $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); } - if (!isset($data['bday_day'])) - { - if ($user_row['user_birthday']) - { - list($data['bday_day'], $data['bday_month'], $data['bday_year']) = explode('-', $user_row['user_birthday']); - } - else - { - $data['bday_day'] = $data['bday_month'] = $data['bday_year'] = 0; - } - } - $s_birthday_day_options = '<option value="0"' . ((!$data['bday_day']) ? ' selected="selected"' : '') . '>--</option>'; for ($i = 1; $i < 32; $i++) { @@ -1094,15 +1134,15 @@ class acp_users unset($now); $template->assign_vars(array( - 'ICQ' => (isset($data['icq'])) ? $data['icq'] : $user_row['user_icq'], - 'YIM' => (isset($data['yim'])) ? $data['yim'] : $user_row['user_yim'], - 'AIM' => (isset($data['aim'])) ? $data['aim'] : $user_row['user_aim'], - 'MSN' => (isset($data['msn'])) ? $data['msn'] : $user_row['user_msnm'], - 'JABBER' => (isset($data['jabber'])) ? $data['jabber'] : $user_row['user_jabber'], - 'WEBSITE' => (isset($data['website'])) ? $data['website']: $user_row['user_website'], - 'LOCATION' => (isset($data['location'])) ? $data['location'] : $user_row['user_from'], - 'OCCUPATION' => (isset($data['occupation'])) ? $data['occupation'] : $user_row['user_occ'], - 'INTERESTS' => (isset($data['interests'])) ? $data['interests'] : $user_row['user_interests'], + 'ICQ' => $data['icq'], + 'YIM' => $data['yim'], + 'AIM' => $data['aim'], + 'MSN' => $data['msn'], + 'JABBER' => $data['jabber'], + 'WEBSITE' => $data['website'], + 'LOCATION' => $data['location'], + 'OCCUPATION' => $data['occupation'], + 'INTERESTS' => $data['interests'], 'S_BIRTHDAY_DAY_OPTIONS' => $s_birthday_day_options, 'S_BIRTHDAY_MONTH_OPTIONS' => $s_birthday_month_options, @@ -1120,51 +1160,44 @@ class acp_users case 'prefs': - $data = array(); + $data = array( + 'dateformat' => request_var('dateformat', $user_row['user_dateformat']), + 'lang' => request_var('lang', $user_row['user_lang']), + 'tz' => request_var('tz', (float) $user_row['user_timezone']), + 'style' => request_var('style', $user_row['user_style']), + 'dst' => request_var('dst', $user_row['user_dst']), + 'viewemail' => request_var('viewemail', $user_row['user_allow_viewemail']), + 'massemail' => request_var('massemail', $user_row['user_allow_massemail']), + 'hideonline' => request_var('hideonline', !$user_row['user_allow_viewonline']), + 'notifymethod' => request_var('notifymethod', $user_row['user_notify_type']), + 'notifypm' => request_var('notifypm', $user_row['user_notify_pm']), + 'popuppm' => request_var('popuppm', $this->optionget($user_row, 'popuppm')), + 'allowpm' => request_var('allowpm', $user_row['user_allow_pm']), + + 'topic_sk' => request_var('topic_sk', ($user_row['user_topic_sortby_type']) ? $user_row['user_topic_sortby_type'] : 't'), + 'topic_sd' => request_var('topic_sd', ($user_row['user_topic_sortby_dir']) ? $user_row['user_topic_sortby_dir'] : 'd'), + 'topic_st' => request_var('topic_st', ($user_row['user_topic_show_days']) ? $user_row['user_topic_show_days'] : 0), + + 'post_sk' => request_var('post_sk', ($user_row['user_post_sortby_type']) ? $user_row['user_post_sortby_type'] : 't'), + 'post_sd' => request_var('post_sd', ($user_row['user_post_sortby_dir']) ? $user_row['user_post_sortby_dir'] : 'a'), + 'post_st' => request_var('post_st', ($user_row['user_post_show_days']) ? $user_row['user_post_show_days'] : 0), + + 'view_images' => request_var('view_images', $this->optionget($user_row, 'viewimg')), + 'view_flash' => request_var('view_flash', $this->optionget($user_row, 'viewflash')), + 'view_smilies' => request_var('view_smilies', $this->optionget($user_row, 'viewsmilies')), + 'view_sigs' => request_var('view_sigs', $this->optionget($user_row, 'viewsigs')), + 'view_avatars' => request_var('view_avatars', $this->optionget($user_row, 'viewavatars')), + 'view_wordcensor' => request_var('view_wordcensore', $this->optionget($user_row, 'viewcensors')), + + 'bbcode' => request_var('bbcode', $this->optionget($user_row, 'bbcode')), + 'smilies' => request_var('smilies', $this->optionget($user_row, 'smilies')), + 'sig' => request_var('sig', $this->optionget($user_row, 'attachsig')), + 'notify' => request_var('notify', $user_row['user_notify']), + ); if ($submit) { - $var_ary = array( - 'dateformat' => (string) $config['default_dateformat'], - 'lang' => (string) $config['default_lang'], - 'tz' => (float) $config['board_timezone'], - 'style' => (int) $config['default_style'], - 'dst' => (bool) $config['board_dst'], - 'viewemail' => false, - 'massemail' => true, - 'hideonline' => false, - 'notifymethod' => 0, - 'notifypm' => true, - 'popuppm' => false, - 'allowpm' => true, - - 'topic_sk' => (string) 't', - 'topic_sd' => (string) 'd', - 'topic_st' => 0, - - 'post_sk' => (string) 't', - 'post_sd' => (string) 'a', - 'post_st' => 0, - - 'view_images' => true, - 'view_flash' => false, - 'view_smilies' => true, - 'view_sigs' => true, - 'view_avatars' => true, - 'view_wordcensor' => false, - - 'bbcode' => true, - 'smilies' => true, - 'sig' => true, - 'notify' => false, - ); - - foreach ($var_ary as $var => $default) - { - $data[$var] = request_var($var, $default); - } - - $var_ary = array( + $error = validate_data($data, array( 'dateformat' => array('string', false, 3, 30), 'lang' => array('match', false, '#^[a-z_\-]{2,}$#i'), 'tz' => array('num', false, -14, 14), @@ -1173,9 +1206,7 @@ class acp_users 'topic_sd' => array('string', false, 1, 1), 'post_sk' => array('string', false, 1, 1), 'post_sd' => array('string', false, 1, 1), - ); - - $error = validate_data($data, $var_ary); + )); if (!sizeof($error)) { @@ -1229,17 +1260,10 @@ class acp_users $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); } - $notify_method = (isset($data['notifymethod'])) ? $data['notifymethod'] : $user_row['user_notify_type']; - $dateformat = (isset($data['dateformat'])) ? $data['dateformat'] : $user_row['user_dateformat']; - $lang = (isset($data['lang'])) ? $data['lang'] : $user_row['user_lang']; - $style = (isset($data['style'])) ? $data['style'] : $user_row['user_style']; - $tz = (isset($data['tz'])) ? $data['tz'] : $user_row['user_timezone']; - $dateformat_options = ''; - foreach ($user->lang['dateformats'] as $format => $null) { - $dateformat_options .= '<option value="' . $format . '"' . (($format == $dateformat) ? ' selected="selected"' : '') . '>'; + $dateformat_options .= '<option value="' . $format . '"' . (($format == $data['dateformat']) ? ' selected="selected"' : '') . '>'; $dateformat_options .= $user->format_date(time(), $format, true) . ((strpos($format, '|') !== false) ? ' [' . $user->lang['RELATIVE_DAYS'] . ']' : ''); $dateformat_options .= '</option>'; } @@ -1247,22 +1271,13 @@ class acp_users $s_custom = false; $dateformat_options .= '<option value="custom"'; - if (!in_array($dateformat, array_keys($user->lang['dateformats']))) + if (!in_array($data['dateformat'], array_keys($user->lang['dateformats']))) { $dateformat_options .= ' selected="selected"'; $s_custom = true; } $dateformat_options .= '>' . $user->lang['CUSTOM_DATEFORMAT'] . '</option>'; - $topic_sk = (isset($data['topic_sk'])) ? $data['topic_sk'] : (($user_row['user_topic_sortby_type']) ? $user_row['user_topic_sortby_type'] : 't'); - $post_sk = (isset($data['post_sk'])) ? $data['post_sk'] : (($user_row['user_post_sortby_type']) ? $user_row['user_post_sortby_type'] : 't'); - - $topic_sd = (isset($data['topic_sd'])) ? $data['topic_sd'] : (($user_row['user_topic_sortby_dir']) ? $user_row['user_topic_sortby_dir'] : 'd'); - $post_sd = (isset($data['post_sd'])) ? $data['post_sd'] : (($user_row['user_post_sortby_dir']) ? $user_row['user_post_sortby_dir'] : 'd'); - - $topic_st = (isset($data['topic_st'])) ? $data['topic_st'] : (($user_row['user_topic_show_days']) ? $user_row['user_topic_show_days'] : 0); - $post_st = (isset($data['post_st'])) ? $data['post_st'] : (($user_row['user_post_show_days']) ? $user_row['user_post_show_days'] : 0); - $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); // Topic ordering options @@ -1279,7 +1294,7 @@ class acp_users ${'s_limit_' . $sort_option . '_days'} = '<select name="' . $sort_option . '_st">'; foreach (${'limit_' . $sort_option . '_days'} as $day => $text) { - $selected = (${$sort_option . '_st'} == $day) ? ' selected="selected"' : ''; + $selected = ($data[$sort_option . '_st'] == $day) ? ' selected="selected"' : ''; ${'s_limit_' . $sort_option . '_days'} .= '<option value="' . $day . '"' . $selected . '>' . $text . '</option>'; } ${'s_limit_' . $sort_option . '_days'} .= '</select>'; @@ -1287,7 +1302,7 @@ class acp_users ${'s_sort_' . $sort_option . '_key'} = '<select name="' . $sort_option . '_sk">'; foreach (${'sort_by_' . $sort_option . '_text'} as $key => $text) { - $selected = (${$sort_option . '_sk'} == $key) ? ' selected="selected"' : ''; + $selected = ($data[$sort_option . '_sk'] == $key) ? ' selected="selected"' : ''; ${'s_sort_' . $sort_option . '_key'} .= '<option value="' . $key . '"' . $selected . '>' . $text . '</option>'; } ${'s_sort_' . $sort_option . '_key'} .= '</select>'; @@ -1295,7 +1310,7 @@ class acp_users ${'s_sort_' . $sort_option . '_dir'} = '<select name="' . $sort_option . '_sd">'; foreach ($sort_dir_text as $key => $value) { - $selected = (${$sort_option . '_sd'} == $key) ? ' selected="selected"' : ''; + $selected = ($data[$sort_option . '_sd'] == $key) ? ' selected="selected"' : ''; ${'s_sort_' . $sort_option . '_dir'} .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>'; } ${'s_sort_' . $sort_option . '_dir'} .= '</select>'; @@ -1303,28 +1318,28 @@ class acp_users $template->assign_vars(array( 'S_PREFS' => true, - 'S_JABBER_DISABLED' => ($config['jab_enable'] && $user->data['user_jabber'] && @extension_loaded('xml')) ? false : true, + 'S_JABBER_DISABLED' => ($config['jab_enable'] && $user_row['user_jabber'] && @extension_loaded('xml')) ? false : true, - 'VIEW_EMAIL' => (isset($data['viewemail'])) ? $data['viewemail'] : $user_row['user_allow_viewemail'], - 'MASS_EMAIL' => (isset($data['massemail'])) ? $data['massemail'] : $user_row['user_allow_massemail'], - 'ALLOW_PM' => (isset($data['allowpm'])) ? $data['allowpm'] : $user_row['user_allow_pm'], - 'HIDE_ONLINE' => (isset($data['hideonline'])) ? $data['hideonline'] : !$user_row['user_allow_viewonline'], - 'NOTIFY_EMAIL' => ($notify_method == NOTIFY_EMAIL) ? true : false, - 'NOTIFY_IM' => ($notify_method == NOTIFY_IM) ? true : false, - 'NOTIFY_BOTH' => ($notify_method == NOTIFY_BOTH) ? true : false, - 'NOTIFY_PM' => (isset($data['notifypm'])) ? $data['notifypm'] : $user_row['user_notify_pm'], - 'POPUP_PM' => (isset($data['popuppm'])) ? $data['popuppm'] : $this->optionget($user_row, 'popuppm'), - 'DST' => (isset($data['dst'])) ? $data['dst'] : $user_row['user_dst'], - 'BBCODE' => (isset($data['bbcode'])) ? $data['bbcode'] : $this->optionget($user_row, 'bbcode'), - 'SMILIES' => (isset($data['smilies'])) ? $data['smilies'] : $this->optionget($user_row, 'smilies'), - 'ATTACH_SIG' => (isset($data['sig'])) ? $data['sig'] : $this->optionget($user_row, 'attachsig'), - 'NOTIFY' => (isset($data['notify'])) ? $data['notify'] : $user_row['user_notify'], - 'VIEW_IMAGES' => (isset($data['view_images'])) ? $data['view_images'] : $this->optionget($user_row, 'viewimg'), - 'VIEW_FLASH' => (isset($data['view_flash'])) ? $data['view_flash'] : $this->optionget($user_row, 'viewflash'), - 'VIEW_SMILIES' => (isset($data['view_smilies'])) ? $data['view_smilies'] : $this->optionget($user_row, 'viewsmilies'), - 'VIEW_SIGS' => (isset($data['view_sigs'])) ? $data['view_sigs'] : $this->optionget($user_row, 'viewsigs'), - 'VIEW_AVATARS' => (isset($data['view_avatars'])) ? $data['view_avatars'] : $this->optionget($user_row, 'viewavatars'), - 'VIEW_WORDCENSOR' => (isset($data['view_wordcensor'])) ? $data['view_wordcensor'] : $this->optionget($user_row, 'viewcensors'), + 'VIEW_EMAIL' => $data['viewemail'], + 'MASS_EMAIL' => $data['massemail'], + 'ALLOW_PM' => $data['allowpm'], + 'HIDE_ONLINE' => $data['hideonline'], + 'NOTIFY_EMAIL' => ($data['notifymethod'] == NOTIFY_EMAIL) ? true : false, + 'NOTIFY_IM' => ($data['notifymethod'] == NOTIFY_IM) ? true : false, + 'NOTIFY_BOTH' => ($data['notifymethod'] == NOTIFY_BOTH) ? true : false, + 'NOTIFY_PM' => $data['notifypm'], + 'POPUP_PM' => $data['popuppm'], + 'DST' => $data['dst'], + 'BBCODE' => $data['bbcode'], + 'SMILIES' => $data['smilies'], + 'ATTACH_SIG' => $data['sig'], + 'NOTIFY' => $data['notify'], + 'VIEW_IMAGES' => $data['view_images'], + 'VIEW_FLASH' => $data['view_flash'], + 'VIEW_SMILIES' => $data['view_smilies'], + 'VIEW_SIGS' => $data['view_sigs'], + 'VIEW_AVATARS' => $data['view_avatars'], + 'VIEW_WORDCENSOR' => $data['view_wordcensor'], 'S_TOPIC_SORT_DAYS' => $s_limit_topic_days, 'S_TOPIC_SORT_KEY' => $s_sort_topic_key, @@ -1333,15 +1348,15 @@ class acp_users 'S_POST_SORT_KEY' => $s_sort_post_key, 'S_POST_SORT_DIR' => $s_sort_post_dir, - 'DATE_FORMAT' => $dateformat, + 'DATE_FORMAT' => $data['dateformat'], 'S_DATEFORMAT_OPTIONS' => $dateformat_options, 'S_CUSTOM_DATEFORMAT' => $s_custom, 'DEFAULT_DATEFORMAT' => $config['default_dateformat'], 'A_DEFAULT_DATEFORMAT' => addslashes($config['default_dateformat']), - 'S_LANG_OPTIONS' => language_select($lang), - 'S_STYLE_OPTIONS' => style_select($style), - 'S_TZ_OPTIONS' => tz_select($tz, true), + 'S_LANG_OPTIONS' => language_select($data['lang']), + 'S_STYLE_OPTIONS' => style_select($data['style']), + 'S_TZ_OPTIONS' => tz_select($data['tz'], true), ) ); @@ -1359,26 +1374,19 @@ class acp_users { $delete = request_var('delete', ''); - $var_ary = array( - 'uploadurl' => (string) '', - 'remotelink' => (string) '', - 'width' => (string) '', - 'height' => (string) '', + $data = array( + 'uploadurl' => request_var('uploadurl', ''), + 'remotelink' => request_var('remotelink', ''), + 'width' => request_var('width', ''), + 'height' => request_var('height', ''), ); - foreach ($var_ary as $var => $default) - { - $data[$var] = request_var($var, $default); - } - - $var_ary = array( + $error = validate_data($data, array( 'uploadurl' => array('string', true, 5, 255), 'remotelink' => array('string', true, 5, 255), 'width' => array('string', true, 1, 3), 'height' => array('string', true, 1, 3), - ); - - $error = validate_data($data, $var_ary); + )); if (!sizeof($error)) { @@ -1440,7 +1448,7 @@ class acp_users // Delete old avatar if present if ($user_row['user_avatar'] && $filename != $user_row['user_avatar'] && $user_row['user_avatar_type'] != AVATAR_GALLERY) { - avatar_delete($user_row['user_avatar']); + avatar_delete('user', $user_row); } } @@ -1545,6 +1553,8 @@ class acp_users $enable_urls = request_var('enable_urls', true); $signature = request_var('signature', $user_row['user_sig'], true); + utf8_normalize_nfc(&$signature); + $preview = (isset($_POST['preview'])) ? true : false; if ($submit || $preview) @@ -1554,7 +1564,7 @@ class acp_users $message_parser = new parse_message($signature); // Allowing Quote BBCode - $message_parser->parse($enable_bbcode, $enable_urls, $enable_smilies, $config['allow_sig_img'], $config['allow_sig_flash'], true, true, 'sig'); + $message_parser->parse($enable_bbcode, ($config['allow_sig_links']) ? $enable_urls : false, $enable_smilies, $config['allow_sig_img'], $config['allow_sig_flash'], true, $config['allow_sig_links'], true, 'sig'); if (sizeof($message_parser->warn_msg)) { @@ -1566,7 +1576,7 @@ class acp_users $sql_ary = array( 'user_sig' => (string) $message_parser->message, 'user_sig_bbcode_uid' => (string) $message_parser->bbcode_uid, - 'user_sig_bbcode_bitfield' => (int) $message_parser->bbcode_bitfield + 'user_sig_bbcode_bitfield' => (string) $message_parser->bbcode_bitfield ); $sql = 'UPDATE ' . USERS_TABLE . ' @@ -1602,17 +1612,19 @@ class acp_users 'S_SMILIES_CHECKED' => (!$enable_smilies) ? 'checked="checked"' : '', 'S_MAGIC_URL_CHECKED' => (!$enable_urls) ? 'checked="checked"' : '', - 'BBCODE_STATUS' => ($config['allow_sig_bbcode']) ? sprintf($user->lang['BBCODE_IS_ON'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '" onclick="target=\'_phpbbcode\';">', '</a>') : sprintf($user->lang['BBCODE_IS_OFF'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '" onclick="target=\'_phpbbcode\';">', '</a>'), + 'BBCODE_STATUS' => ($config['allow_sig_bbcode']) ? sprintf($user->lang['BBCODE_IS_ON'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>') : sprintf($user->lang['BBCODE_IS_OFF'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>'), 'SMILIES_STATUS' => ($config['allow_sig_smilies']) ? $user->lang['SMILIES_ARE_ON'] : $user->lang['SMILIES_ARE_OFF'], 'IMG_STATUS' => ($config['allow_sig_img']) ? $user->lang['IMAGES_ARE_ON'] : $user->lang['IMAGES_ARE_OFF'], 'FLASH_STATUS' => ($config['allow_sig_flash']) ? $user->lang['FLASH_IS_ON'] : $user->lang['FLASH_IS_OFF'], + 'URL_STATUS' => ($config['allow_sig_links']) ? $user->lang['URL_IS_ON'] : $user->lang['URL_IS_OFF'], 'L_SIGNATURE_EXPLAIN' => sprintf($user->lang['SIGNATURE_EXPLAIN'], $config['max_sig_chars']), 'S_BBCODE_ALLOWED' => $config['allow_sig_bbcode'], 'S_SMILIES_ALLOWED' => $config['allow_sig_smilies'], 'S_BBCODE_IMG' => ($config['allow_sig_img']) ? true : false, - 'S_BBCODE_FLASH' => ($config['allow_sig_flash']) ? true : false) + 'S_BBCODE_FLASH' => ($config['allow_sig_flash']) ? true : false, + 'S_LINKS_ALLOWED' => ($config['allow_sig_links']) ? true : false) ); // Assigning custom bbcodes @@ -1686,7 +1698,12 @@ class acp_users $s_sort_dir .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>'; } - $order_by = $sk_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'); + if (!isset($sk_sql[$sort_key])) + { + $sort_key = 'a'; + } + + $order_by = $sk_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'); $sql = 'SELECT COUNT(attach_id) as num_attachments FROM ' . ATTACHMENTS_TABLE . " @@ -1772,12 +1789,12 @@ class acp_users { if (!$group_id) { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } if ($error = group_user_del($group_id, $user_id)) { - trigger_error($user->lang[$error] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang[$error] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } $error = array(); @@ -1801,13 +1818,13 @@ class acp_users { if (!$group_id) { - trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } // Add user/s to group if ($error = group_user_add($group_id, $user_id)) { - trigger_error($user->lang[$error] . adm_back_link($this->u_action . '&u=' . $user_id)); + trigger_error($user->lang[$error] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); } $error = array(); @@ -1847,11 +1864,11 @@ class acp_users $s_group_options = ''; while ($row = $db->sql_fetchrow($result)) { - if (!$config['coppa_enable'] && in_array($row['group_name'], array('INACTIVE_COPPA', 'REGISTERED_COPPA'))) + if (!$config['coppa_enable'] && $row['group_name'] == 'REGISTERED_COPPA') { continue; } - + $s_group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="sep"' : '') . ' value="' . $row['group_id'] . '">' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</option>'; } $db->sql_freeresult($result); @@ -1899,14 +1916,14 @@ class acp_users $auth_admin = new auth_admin(); $user->add_lang('acp/permissions'); - $user->add_lang('acp/permissions_phpbb'); + add_permission_language(); // Select auth options $sql = 'SELECT auth_option, is_local, is_global FROM ' . ACL_OPTIONS_TABLE . " WHERE auth_option LIKE '%\_'"; - if (SQL_LAYER == 'mssql' || SQL_LAYER == 'mssql_odbc') + if ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') { $sql .= " ESCAPE '\\'"; } @@ -1926,7 +1943,7 @@ class acp_users FROM ' . ACL_OPTIONS_TABLE . " WHERE auth_option LIKE '%\_'"; - if (SQL_LAYER == 'mssql' || SQL_LAYER == 'mssql_odbc') + if ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') { $sql .= " ESCAPE '\\'"; } diff --git a/phpBB/includes/acp/acp_words.php b/phpBB/includes/acp/acp_words.php index cacea98d97..8fe99b8c80 100644 --- a/phpBB/includes/acp/acp_words.php +++ b/phpBB/includes/acp/acp_words.php @@ -40,7 +40,7 @@ class acp_words if (!$word_id) { - trigger_error($user->lang['NO_WORD'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_WORD'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT * @@ -71,10 +71,12 @@ class acp_words $word_id = request_var('id', 0); $word = request_var('word', '', true); $replacement = request_var('replacement', '', true); + + utf8_normalize_nfc(array(&$word, &$replacement)); if (!$word || !$replacement) { - trigger_error($user->lang['ENTER_WORD'] . adm_back_link($this->u_action)); + trigger_error($user->lang['ENTER_WORD'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql_ary = array( @@ -107,7 +109,7 @@ class acp_words if (!$word_id) { - trigger_error($user->lang['NO_WORD'] . adm_back_link($this->u_action)); + trigger_error($user->lang['NO_WORD'] . adm_back_link($this->u_action), E_USER_WARNING); } $sql = 'SELECT word diff --git a/phpBB/includes/acp/auth.php b/phpBB/includes/acp/auth.php index 71d17bd40d..436e3f017b 100644 --- a/phpBB/includes/acp/auth.php +++ b/phpBB/includes/acp/auth.php @@ -724,24 +724,7 @@ class auth_admin extends auth } } - if (sizeof($sql_ary)) - { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query('INSERT INTO ' . ACL_OPTIONS_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $sql_ary)); - break; - - default: - foreach ($sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . ACL_OPTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } - } + $db->sql_multi_insert(ACL_OPTIONS_TABLE, $sql_ary); $cache->destroy('acl_options'); $this->acl_clear_prefetch(); @@ -874,24 +857,7 @@ class auth_admin extends auth } } - if (sizeof($sql_ary)) - { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query("INSERT INTO $table " . $db->sql_build_array('MULTI_INSERT', $sql_ary)); - break; - - default: - foreach ($sql_ary as $ary) - { - $db->sql_query("INSERT INTO $table " . $db->sql_build_array('INSERT', $ary)); - } - break; - } - } + $db->sql_multi_insert($table, $sql_ary); if ($clear_prefetch) { @@ -956,21 +922,8 @@ class auth_admin extends auth WHERE role_id = ' . $role_id; $db->sql_query($sql); - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query('INSERT INTO ' . ACL_ROLES_DATA_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $sql_ary)); - break; - - default: - foreach ($sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . ACL_ROLES_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } + // Now insert the new values + $db->sql_multi_insert(ACL_ROLES_DATA_TABLE, $sql_ary); $this->acl_clear_prefetch(); } @@ -1009,7 +962,9 @@ class auth_admin extends auth // Get permission type $sql = 'SELECT auth_option, auth_option_id FROM ' . ACL_OPTIONS_TABLE . " - WHERE auth_option LIKE '" . $db->sql_escape($permission_type) . "%'"; + WHERE auth_option LIKE '" . $db->sql_escape(str_replace('_', "\_", $permission_type)) . "%'"; + $sql .= ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') ? " ESCAPE '\\'" : ''; + $result = $db->sql_query($sql); $auth_id_ary = array(); diff --git a/phpBB/includes/acp/info/acp_inactive.php b/phpBB/includes/acp/info/acp_inactive.php new file mode 100755 index 0000000000..bee9d977d4 --- /dev/null +++ b/phpBB/includes/acp/info/acp_inactive.php @@ -0,0 +1,37 @@ +<?php +/** +* +* @package acp +* @version $Id$ +* @copyright (c) 2006 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @package module_install +*/ +class acp_inactive_info +{ + function module() + { + return array( + 'filename' => 'acp_inactive', + 'title' => 'ACP_INACTIVE_USERS', + 'version' => '1.0.0', + 'modes' => array( + 'list' => array('title' => 'ACP_INACTIVE_USERS', 'auth' => 'acl_a_user', 'cat' => array('ACP_CAT_USERS')), + ), + ); + } + + function install() + { + } + + function uninstall() + { + } +} + +?>
\ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_update.php b/phpBB/includes/acp/info/acp_update.php new file mode 100644 index 0000000000..014d67ff2b --- /dev/null +++ b/phpBB/includes/acp/info/acp_update.php @@ -0,0 +1,37 @@ +<?php +/** +* +* @package acp +* @version $Id$ +* @copyright (c) 2005 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +* @package module_install +*/ +class acp_update_info +{ + function module() + { + return array( + 'filename' => 'acp_update', + 'title' => 'ACP_UPDATE', + 'version' => '1.0.0', + 'modes' => array( + 'version_check' => array('title' => 'ACP_VERSION_CHECK', 'auth' => 'acl_a_', 'cat' => array('ACP_AUTOMATION')), + ), + ); + } + + function install() + { + } + + function uninstall() + { + } +} + +?>
\ No newline at end of file diff --git a/phpBB/includes/auth.php b/phpBB/includes/auth.php index 4e6a8af1d8..8ee4a23abb 100644 --- a/phpBB/includes/auth.php +++ b/phpBB/includes/auth.php @@ -396,7 +396,7 @@ class auth $hold_str .= str_repeat("\n", $f - $last_f); // Convert bitstring for storage - we do not use binary/bytes because PHP's string functions are not fully binary safe - for ($i = 0; $i < strlen($bitstring); $i += 31) + for ($i = 0, $bit_length = strlen($bitstring); $i < $bit_length; $i += 31) { $hold_str .= str_pad(base_convert(str_pad(substr($bitstring, $i, 31), 31, 0, STR_PAD_RIGHT), 2, 36), 6, 0, STR_PAD_LEFT); } @@ -478,18 +478,11 @@ class auth $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? "user_id = $user_id" : $db->sql_in_set('user_id', $user_id)) : ''; $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? "AND a.forum_id = $forum_id" : 'AND ' . $db->sql_in_set('a.forum_id', $forum_id)) : ''; - $sql_opts = ''; + $sql_opts = $sql_escape = ''; if ($opts !== false) { - if (!is_array($opts)) - { - $sql_opts = (strpos($opts, '%') !== false) ? "AND ao.auth_option LIKE '" . $db->sql_escape($opts) . "'" : "AND ao.auth_option = '" . $db->sql_escape($opts) . "'"; - } - else - { - $sql_opts = 'AND ' . $db->sql_in_set('ao.auth_option', $opts); - } + $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts, $sql_escape); } $hold_ary = array(); @@ -519,7 +512,7 @@ class auth 'ORDER_BY' => 'a.forum_id, ao.auth_option' )); - $result = $db->sql_query($sql); + $result = $db->sql_query($sql . $sql_escape); while ($row = $db->sql_fetchrow($result)) { @@ -595,18 +588,11 @@ class auth $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? "user_id = $user_id" : $db->sql_in_set('user_id', $user_id)) : ''; $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? "AND a.forum_id = $forum_id" : 'AND ' . $db->sql_in_set('a.forum_id', $forum_id)) : ''; - $sql_opts = ''; + $sql_opts = $sql_escape = ''; if ($opts !== false) { - if (!is_array($opts)) - { - $sql_opts = (strpos($opts, '%') !== false) ? "AND ao.auth_option LIKE '" . $db->sql_escape($opts) . "'" : "AND ao.auth_option = '" . $db->sql_escape($opts) . "'"; - } - else - { - $sql_opts = 'AND ' . $db->sql_in_set('ao.auth_option', $opts); - } + $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts, $sql_escape); } $hold_ary = array(); @@ -634,7 +620,7 @@ class auth 'ORDER_BY' => 'a.forum_id, ao.auth_option' )); - $result = $db->sql_query($sql); + $result = $db->sql_query($sql . $sql_escape); while ($row = $db->sql_fetchrow($result)) { @@ -656,16 +642,11 @@ class auth $sql_group = ($group_id !== false) ? ((!is_array($group_id)) ? "group_id = $group_id" : $db->sql_in_set('group_id', $group_id)) : ''; $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? "AND a.forum_id = $forum_id" : 'AND ' . $db->sql_in_set('a.forum_id', $forum_id)) : ''; + $sql_opts = $sql_escape = ''; + if ($opts !== false) { - if (!is_array($opts)) - { - $sql_opts = (strpos($opts, '%') !== false) ? "AND ao.auth_option LIKE '" . $db->sql_escape($opts) . "'" : "AND ao.auth_option = '" . $db->sql_escape($opts) . "'"; - } - else - { - $sql_opts = 'AND ' . $db->sql_in_set('ao.auth_option', $opts); - } + $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts, $sql_escape); } $hold_ary = array(); @@ -693,7 +674,7 @@ class auth 'ORDER_BY' => 'a.forum_id, ao.auth_option' )); - $result = $db->sql_query($sql); + $result = $db->sql_query($sql . $sql_escape); while ($row = $db->sql_fetchrow($result)) { @@ -726,14 +707,14 @@ class auth // we are going to use the user_add function so include functions_user.php if it wasn't defined yet if (!function_exists('user_add')) { - include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx); + include($phpbb_root_path . 'includes/functions_user.' . $phpEx); } user_add($login['user_row'], (isset($login['cp_data'])) ? $login['cp_data'] : false); $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type FROM ' . USERS_TABLE . " - WHERE username = '" . $db->sql_escape($username) . "'"; + WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -757,11 +738,36 @@ class auth // If login succeeded, we will log the user in... else we pass the login array through... if ($login['status'] == LOGIN_SUCCESS) { + $old_session_id = $user->session_id; + + if ($admin) + { + global $SID, $_SID; + + $cookie_expire = time() - 31536000; + $user->set_cookie('u', '', $cookie_expire); + $user->set_cookie('sid', '', $cookie_expire); + unset($cookie_expire); + + $SID = '?sid='; + $user->session_id = $_SID = ''; + } + $result = $user->session_create($login['user_row']['user_id'], $admin, $autologin, $viewonline); // Successful session creation if ($result === true) { + // If admin re-authentication we remove the old session entry because a new one has been created... + if ($admin) + { + // the login array is used because the user ids do not differ for re-authentication + $sql = 'DELETE FROM ' . SESSIONS_TABLE . " + WHERE session_id = '" . $db->sql_escape($old_session_id) . "' + AND session_user_id = {$login['user_row']['user_id']}"; + $db->sql_query($sql); + } + return array( 'status' => LOGIN_SUCCESS, 'error_msg' => false, @@ -781,6 +787,72 @@ class auth trigger_error('Authentication method not found', E_USER_ERROR); } + + /** + * Fill auth_option statement for later querying based on the supplied options + */ + function build_auth_option_statement($key, $auth_options, &$sql_opts, &$sql_escape) + { + global $db; + + if (!is_array($auth_options)) + { + if (strpos($auth_options, '%') !== false) + { + if (strpos($auth_options, '_') !== false) + { + $sql_opts = "AND $key LIKE '" . $db->sql_escape(str_replace('_', "\_", $auth_options)) . "'"; + $sql_escape = ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') ? " ESCAPE '\\'" : ''; + } + else + { + $sql_opts = "AND $key LIKE '" . $db->sql_escape($auth_options) . "'"; + } + } + else + { + $sql_opts = "AND $key = '" . $db->sql_escape($auth_options) . "'"; + } + } + else + { + $is_like_expression = $is_underline = false; + + foreach ($auth_options as $option) + { + if (strpos($option, '%') !== false) + { + $is_like_expression = true; + } + + if (strpos($option, '_') !== false) + { + $is_underline = true; + } + } + + if (!$is_like_expression) + { + $sql_opts = 'AND ' . $db->sql_in_set($key, $auth_options); + } + else + { + $sql = array(); + + foreach ($auth_options as $option) + { + $sql[] = $key . " LIKE '" . $db->sql_escape(str_replace('_', "\_", $option)) . "'"; + } + + $sql_opts = 'AND (' . implode(' OR ', $sql) . ')'; + + if ($is_underline) + { + $sql_escape = ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') ? " ESCAPE '\\'" : ''; + } + } + } + } } ?>
\ No newline at end of file diff --git a/phpBB/includes/auth/auth_apache.php b/phpBB/includes/auth/auth_apache.php index 3ee0f1347f..4c8293c707 100644 --- a/phpBB/includes/auth/auth_apache.php +++ b/phpBB/includes/auth/auth_apache.php @@ -136,12 +136,19 @@ function autologin_apache() return ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) ? array() : $row; } + if (!function_exists('user_add')) + { + global $phpbb_root_path, $phpEx; + + include($phpbb_root_path . 'includes/functions_user.' . $phpEx); + } + // create the user if he does not exist yet user_add(user_row_apache($php_auth_user, $php_auth_pw)); $sql = 'SELECT * FROM ' . USERS_TABLE . " - WHERE username = '" . $db->sql_escape($php_auth_user) . "'"; + WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($php_auth_user)) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -178,7 +185,7 @@ function user_row_apache($username, $password) // generate user account data return array( 'username' => $username, - 'user_password' => $password, + 'user_password' => md5($password), 'user_email' => '', 'group_id' => (int) $row['group_id'], 'user_type' => USER_NORMAL, diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php index 9477fd92c3..618ad0a387 100644 --- a/phpBB/includes/auth/auth_db.php +++ b/phpBB/includes/auth/auth_db.php @@ -22,7 +22,7 @@ function login_db(&$username, &$password) $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts FROM ' . USERS_TABLE . " - WHERE username = '" . $db->sql_escape($username) . "'"; + WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); diff --git a/phpBB/includes/auth/auth_ldap.php b/phpBB/includes/auth/auth_ldap.php index 889f6d8661..988da577c0 100644 --- a/phpBB/includes/auth/auth_ldap.php +++ b/phpBB/includes/auth/auth_ldap.php @@ -38,7 +38,7 @@ function init_ldap() $search = @ldap_search( $ldap, $config['ldap_base_dn'], - '(' . $config['ldap_uid'] . '=' . ldap_escape(html_entity_decode($user->data['username'])) . ')', + '(' . $config['ldap_uid'] . '=' . ldap_escape(htmlspecialchars_decode($user->data['username'])) . ')', (empty($config['ldap_email'])) ? array($config['ldap_uid']) : array($config['ldap_uid'], $config['ldap_email']), 0, 1 @@ -98,7 +98,7 @@ function login_ldap(&$username, &$password) $search = @ldap_search( $ldap, $config['ldap_base_dn'], - '(' . $config['ldap_uid'] . '=' . ldap_escape(html_entity_decode($username)) . ')', + '(' . $config['ldap_uid'] . '=' . ldap_escape(htmlspecialchars_decode($username)) . ')', (empty($config['ldap_email'])) ? array($config['ldap_uid']) : array($config['ldap_uid'], $config['ldap_email']), 0, 1 @@ -108,13 +108,13 @@ function login_ldap(&$username, &$password) if (is_array($ldap_result) && sizeof($ldap_result) > 1) { - if (@ldap_bind($ldap, $ldap_result[0]['dn'], html_entity_decode($password))) + if (@ldap_bind($ldap, $ldap_result[0]['dn'], htmlspecialchars_decode($password))) { @ldap_close($ldap); $sql ='SELECT user_id, username, user_password, user_passchg, user_email, user_type FROM ' . USERS_TABLE . " - WHERE username = '" . $db->sql_escape($username) . "'"; + WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -159,7 +159,7 @@ function login_ldap(&$username, &$password) // generate user account data $ldap_user_row = array( 'username' => $username, - 'user_password' => $password, + 'user_password' => md5($password), 'user_email' => (!empty($config['ldap_email'])) ? $ldap_result[0][$config['ldap_email']][0] : '', 'group_id' => (int) $row['group_id'], 'user_type' => USER_NORMAL, diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php index 7293f07dc9..409aab18e4 100644 --- a/phpBB/includes/bbcode.php +++ b/phpBB/includes/bbcode.php @@ -155,6 +155,12 @@ class bbcode while ($row = $db->sql_fetchrow($result)) { + // To circumvent replacing newlines with <br /> for the generated html, + // we just remove newlines here. We do not do this within the admin panel to + // let the admin lay out his html code nicely + $row['bbcode_tpl'] = str_replace(array("\n", "\r"), '', $row['bbcode_tpl']); + $row['second_pass_replace'] = str_replace(array("\n", "\r"), '', $row['second_pass_replace']); + $rowset[$row['bbcode_id']] = $row; } $db->sql_freeresult($result); @@ -530,7 +536,7 @@ class bbcode $username = str_replace('\"', '"', $username); // remove newline at the beginning - if ($quote{0} == "\n") + if ($quote[0] == "\n") { $quote = substr($quote, 1); } @@ -566,7 +572,7 @@ class bbcode $code = str_replace(' ', ' ', $code); // remove newline at the beginning - if (!empty($code) && $code{0} == "\n") + if (!empty($code) && $code[0] == "\n") { $code = substr($code, 1); } diff --git a/phpBB/includes/cache.php b/phpBB/includes/cache.php index a3a251d194..6266d32c0f 100644 --- a/phpBB/includes/cache.php +++ b/phpBB/includes/cache.php @@ -70,13 +70,13 @@ class cache extends acm * Obtain list of naughty words and build preg style replacement arrays for use by the * calling script */ - function obtain_word_list(&$censors) + function obtain_word_list() { global $config, $user, $db; if (!$user->optionget('viewcensors') && $config['allow_nocensors']) { - return false; + return array(); } if (($censors = $this->get('word_censors')) === false) @@ -96,13 +96,13 @@ class cache extends acm $this->put('word_censors', $censors); } - return true; + return $censors; } /** * Obtain currently listed icons */ - function obtain_icons(&$icons) + function obtain_icons() { if (($icons = $this->get('icons')) === false) { @@ -127,13 +127,13 @@ class cache extends acm $this->put('icons', $icons); } - return; + return $icons; } /** * Obtain ranks */ - function obtain_ranks(&$ranks) + function obtain_ranks() { if (($ranks = $this->get('ranks')) === false) { @@ -168,13 +168,13 @@ class cache extends acm $this->put('ranks', $ranks); } - return; + return $ranks; } /** * Obtain allowed extensions */ - function obtain_attach_extensions(&$extensions, $forum_id = false) + function obtain_attach_extensions($forum_id = false) { if (($extensions = $this->get('_extensions')) === false) { @@ -254,19 +254,19 @@ class cache extends acm $extensions['_allowed_'] = array(); } - return; + return $extensions; } /** * Obtain active bots */ - function obtain_bots(&$bots) + function obtain_bots() { if (($bots = $this->get('bots')) === false) { global $db; - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'mssql': case 'mssql_odbc': @@ -280,7 +280,7 @@ class cache extends acm $sql = 'SELECT user_id, bot_agent, bot_ip FROM ' . BOTS_TABLE . ' WHERE bot_active = 1 - ORDER BY STRLEN(bot_agent) DESC'; + ORDER BY CHAR_LENGTH(bot_agent) DESC'; break; // LENGTH supported by MySQL, IBM DB2 and Oracle for sure... @@ -303,7 +303,7 @@ class cache extends acm $this->put('bots', $bots); } - return; + return $bots; } /** @@ -354,6 +354,32 @@ class cache extends acm return $parsed_items; } + + /** + * Obtain disallowed usernames + */ + function obtain_disallowed_usernames() + { + if (($usernames = $this->get('_disallowed_usernames')) === false) + { + global $db; + + $sql = 'SELECT disallow_username + FROM ' . DISALLOW_TABLE; + $result = $db->sql_query($sql); + + $usernames = array(); + while ($row = $db->sql_fetchrow($result)) + { + $usernames[] = utf8_clean_string(str_replace('%', '.*?', preg_quote($row['disallow_username'], '$#'))); + } + $db->sql_freeresult($result); + + $this->put('_disallowed_usernames', $usernames); + } + + return $usernames; + } } ?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/captcha_gd.php b/phpBB/includes/captcha/captcha_gd.php index 8a2bf70242..e249a46c04 100644 --- a/phpBB/includes/captcha/captcha_gd.php +++ b/phpBB/includes/captcha/captcha_gd.php @@ -8,3420 +8,158 @@ * */ - /** -* Main gd based captcha class -* -* Thanks to Robert Hetzler (Xore) +* Based on PHP-Class hn_captcha Version 1.3, released 11-Apr-2006 +* Original Author - Horst Nogajski, horst@nogajski.de * * @package VC */ class captcha { - /** - * Create the image containing $code - */ - function execute($code, $policy) - { - $this->$policy(str_split($code)); - } - - /** - * Send image and destroy - */ - function send_image(&$image) - { - header('Content-Type: image/png'); - header('Cache-control: no-cache, no-store'); - imagepng($image); - imagedestroy($image); - } - - /** - * - */ - function wave_height($x, $y, $factor = 1, $tweak = 1) - { - return ((sin($x / (3 * $factor)) + sin($y / (3 * $factor))) * 10 * $tweak); - } - - /** - * - */ - function grid_height($x, $y, $factor = 1, $x_grid, $y_grid) - { - return ( (!($x % ($x_grid * $factor)) || !($y % ($y_grid * $factor))) ? 3 : 0); - } - - /** - * - */ - function draw_shape($type, $img, $x_min, $y_min, $x_max, $y_max, $color) - { - switch ($type) - { - case 'Square': - imagefilledpolygon($img, array($x_min, $y_max, $x_min, $y_min, $x_max, $y_min, $x_max, $y_max), 4, $color); - break; - - case 'TriangleUp': - imagefilledpolygon($img, array($x_min, $y_max, ($x_min + $x_max) / 2, $y_min, $x_max, $y_max), 3, $color); - break; - - case 'TriangleDown': - imagefilledpolygon($img, array($x_min, $y_min, ($x_min + $x_max) / 2, $y_max, $x_max, $y_min), 3, $color); - break; - - case 'Circle': - imagefilledellipse($img, ($x_min + $x_max) / 2, ($y_min + $y_max) / 2, $x_max - $x_min, $y_max - $y_min, $color); - break; - } - } - - /** - * - */ - function draw_pattern($seed, $img, $x_min, $y_min, $x_max, $y_max, $colors, $thickness = 1) - { - $x_size = ($x_max - $x_min) / 4; - $y_size = ($y_max - $y_min) / 4; - $bitmap = substr($seed, 16, 4); - $numcolors = sizeof($colors) - 1; - for ($y = 0; $y < 4; ++$y) - { - $map = hexdec(substr($bitmap, $y, 1)); - for ($x = 0; $x < 4; ++$x) - { - if ($map & (1 << $x)) - { - $char = hexdec(substr($seed, ($y << 2) + $x, 1)); - if (!($char >> 2)) - { - switch ($char & 3) - { - case 0: - $shape = 'Circle'; - break; - - case 1: - $shape = 'Square'; - break; - - case 2: - $shape = 'TriangleUp'; - break; - - case 3: - $shape = 'TriangleDown'; - break; - } - $this->draw_shape($shape, $img, $x_min + ($x * $x_size), $y_min + ($y * $y_size), $x_min + (($x + 1) * $x_size), $y_min + (($y + 1) * $y_size), $colors[array_rand($colors)]); - } - } - } - } - - $cells = array(); - for ($i = 0; $i < 6; ++$i) - { - $cells = hexdec(substr($seed, 20 + ($i << 1), 2)); - $x1 = $cells & 3; - $cells = $cells >> 2; - $y1 = $cells & 3; - $cells = $cells >> 2; - $x2 = $cells & 3; - $cells = $cells >> 2; - $y2 = $cells & 3; - $x1_real = $x_min + (($x1 + 0.5) * $x_size); - $y1_real = $y_min + (($y1 + 0.5) * $y_size); - $x2_real = $x_min + (($x2 + 0.5) * $x_size); - $y2_real = $y_min + (($y2 + 0.5) * $y_size); - if ($thickness > 1) - { - imagesetthickness($img, $thickness); - } - imageline($img, $x1_real, $y1_real, $x2_real, $y2_real, $colors[array_rand($colors)]); - if ($thickness > 1) - { - imagesetthickness($img, 1); - } - } - } - - /** - * - */ - function get_char_string() - { - static $chars = false; - static $charcount = 0; - if (!$chars) - { - $chars = array_merge(range('A', 'Z'), range('1', '9')); - } - $word = ''; - for ($i = mt_rand(6, 8); $i > 0; --$i) - { - $word .= $chars[array_rand($chars)]; - } - return $word; - } - - /** - * shape - */ - function policy_shape($code) - { - global $config, $user; - // Generate image - $img_x = 800; - $img_y = 250; - $img = imagecreatetruecolor($img_x, $img_y); - - // Generate colors - $c = new color_manager($img, array( - 'random' => true, - 'min_saturation' => 70, - 'min_value' => 65, - )); - - $primaries = $c->color_scheme('background', 'tetradic', false); - - $noise = array_shift($primaries); - $noise = $c->mono_range($noise, 'value', 5, false); - $primaries = $c->mono_range($primaries, 'value', 5, false); - - // Generate code characters - $characters = array(); - $sizes = array(); - $bounding_boxes = array(); - $width_avail = $img_x; - $code_num = sizeof($code); - $char_class = $this->captcha_char('char_ttf'); - for ( $i = 0; $i < $code_num; ++$i ) - { - $characters[$i] = new $char_class($code[$i]); - list($min, $max) = $characters[$i]->range(); - $sizes[$i] = mt_rand($min, $max / 2); - $box = $characters[$i]->dimensions($sizes[$i]); - $width_avail -= ($box[2] - $box[0]); - $bounding_boxes[$i] = $box; - } - - // Redistribute leftover x-space - $offset = array(); - for ( $i = 0; $i < $code_num; ++$i ) - { - $denom = ($code_num - $i); - $denom = max(1.5, $denom); - $offset[$i] = mt_rand(0, (1.5 * $width_avail) / $denom); - $width_avail -= $offset[$i]; - } - - // Add some line noise - if ($config['policy_shape_noise_line']) - { - $this->noise_line($img, 0, 0, $img_x, $img_y, $c->r('background'), $primaries, $noise); - } - - $real = mt_rand(0, 3); - $patterns = array('', '', '', ''); - for ($i = 32; $i > 0; --$i) - { - $patterns[$i & 3] .= str_pad(dechex(mt_rand(0, 65535)), 4, '0', STR_PAD_LEFT); - } - - - for ($i = 0; $i < 4; ++$i) - { - /*if ($i) - { - $y = 5 + ($i * 60); - imageline($img, 550, $y, 650, $y, $fontcolors[0]); - }*/ - $this->draw_pattern($patterns[$i], $img, 525, 10 + ($i * 60), 575, ($i + 1) * 60, $primaries); - if ($i == $real) - { - $this->draw_pattern($patterns[$i], $img, 25, 25, 225, 225, $primaries, 3); - for ($j = 0; $j < $code_num; ++$j) - { - $character = new $char_class($code[$j]); - $character->drawchar(25, 600 + ($j * 25), 35 + ($i * 60), $img, $c->r('background'), $primaries); - } - } - else - { - $word = $this->get_char_string(); - for ($j = strlen($word) - 1; $j >= 0; --$j) - { - $character = new $char_class(substr($word, $j, 1)); - $character->drawchar(25, 600 + ($j * 25), 35 + ($i * 60), $img, $c->r('background'), $primaries); - } - } - } - - $count = sizeof($user->lang['CAPTCHA']['shape']); - $line_height = $img_y / ($count + 1); - for ($i = 0; $i < $count; ++$i) - { - $text = $user->lang['CAPTCHA']['shape'][$i]; - $line_width = strlen($text) * 4.5; // ( / 2, * 9 ) - imagestring($img, 6, ($img_x / 2) - $line_width - 1, $line_height * ($i + 1) - 1, $text, $c->r('black')); - imagestring($img, 6, ($img_x / 2) - $line_width - 1, $line_height * ($i + 1) + 1, $text, $c->r('black')); - imagestring($img, 6, ($img_x / 2) - $line_width + 1, $line_height * ($i + 1) + 1, $text, $c->r('black')); - imagestring($img, 6, ($img_x / 2) - $line_width + 1, $line_height * ($i + 1) - 1, $text, $c->r('black')); - imagestring($img, 6, ($img_x / 2) - $line_width, $line_height * ($i + 1), $text, $c->r('white')); - } - - - // Add some pixel noise - if ($config['policy_shape_noise_pixel']) - { - $this->noise_pixel($img, 0, 0, $img_x, $img_y, $c->r('background'), $primaries, $noise, $config['policy_shape_noise_pixel']); - } - - // Send image - $this->send_image($img); - } - - function policy_composite($code) - { - // Generate image - $img_x = 800; - $img_y = 250; - $img = imagecreate($img_x, $img_y); - - $map = captcha_vectors(); - $fonts = captcha_load_ttf_fonts(); - - // Generate basic colors - $c = new color_manager($img, 'white'); - $c->allocate_named('primary', array( - 'random' => true, - 'min_saturation' => 50, - 'min_value' => 75, - )); - $bg_colors = $c->color_scheme('primary', 'triadic', false); - $text_colors = $c->mono_range('primary', 'saturation', 6); - $bg_colors = $c->mono_range($bg_colors, 'saturation', 6); - - // Specificy image portion dimensions. - $count = sizeof($code); - $cellsize = $img_x / $count; - $y_range = min($cellsize, $img_y); - $y_max = $img_y - $y_range; - $y_off = array(); // consecutive vertical offset of characters - $color = array(); // color of characters - $y_off[0] = mt_rand(0, $y_max); - for ($i = 1; $i < $count; ++$i) - { - // each consective character can be as much as 50% closer to the top or bottom of the image as the previous - $diff = mt_rand(-50, 50); - if ($diff > 0) - { - $y_off[$i] = $y_off[$i - 1] + ((($y_max - $y_off[$i - 1]) * $diff) / 100); - } - else - { - $y_off[$i] = $y_off[$i - 1] * ((100 + $diff) / 100); - } - } - - $range = 0.075; - - $chars = array_merge(range('A', 'Z'), range('1', '9')); - - // draw some characters. if they're within the vector spec of the code character, color them differently - for ($i = 0; $i < 8000; ++$i) - { - $degree = mt_rand(-30, 30); - $x = mt_rand(0, $img_x - 1); - $y = mt_rand(0, $img_y); - $text = $chars[array_rand($chars)]; - $char = $x / $cellsize; - $meta_x = ((($x % $cellsize) / $cellsize) * 1.5) - 0.25; - $meta_y = (($img_y - $y) - $y_off[$char]) / $y_range; - $font = $fonts[array_rand($fonts)]; - - $distance = vector_distance($map[$code[$char]], $meta_x, $meta_y, $range); - - $switch = !(rand() % 100); - - imagettftext($img, 10, $degree, $x, $y, - (($distance <= $range) xor $switch) ? - $c->r_rand($text_colors) : - $c->r_rand($bg_colors), - $font, $text); - - } - - // Send image - $this->send_image($img); - } - - function policy_stencil($code) - { - // Generate image - $img_x = 800; - $img_y = 250; - $img = imagecreatetruecolor($img_x, $img_y); - $stencil = imagecreatetruecolor($img_x, $img_y); - - $map = captcha_vectors(); - $fonts = captcha_load_ttf_fonts(); - - // Generate colors - $c = new color_manager($img, 'black'); - $cs = new color_manager($stencil, 'gray'); - - $c->allocate_named('primary', array( - 'random' => true, - 'min_saturation' => 75, - 'min_value' => 80, - )); - - $secondary = $c->color_scheme('primary', 'triadic', false); - - //imagefill($stencil, 0, 0, $black2); - //imagefill($img, 0, 0, $white1); - - $chars = array_merge(range('A', 'Z'), range('1', '9')); - $step = 20; - $density = 4; - for ($i = 0; $i < $img_x; $i += $step) - { - for ($j = 0; $j < $img_y; $j += $step) - { - for ($k = 0; $k < $density; ++$k) - { - $degree = mt_rand(-30, 30); - $x = mt_rand($i, $i + $step); - $y = mt_rand($j, $j + $step); - $char = $chars[array_rand($chars)]; - $font = $fonts[array_rand($fonts)]; - imagettftext($stencil, mt_rand(20, 30), $degree, $x, $y, $cs->r('black'), $font, $char); - } - } - } - - for ($i = 0; $i < 3; ++$i) - { - $degree1 = mt_rand(-30, 30); - $degree2 = mt_rand(-30, 30); - $x1 = mt_rand(0, $img_x - 1); - $x2 = mt_rand(0, $img_x - 1); - $y1 = mt_rand(0, $img_y); - $y2 = mt_rand(0, $img_y); - $char1 = $chars[array_rand($chars)]; - $char2 = $chars[array_rand($chars)]; - $font1 = $fonts[array_rand($fonts)]; - $font2 = $fonts[array_rand($fonts)]; - - imagettftext($img, mt_rand(75, 100), $degree1, $x1, $y1, $secondary[0], $font1, $char1); - imagettftext($img, mt_rand(75, 100), $degree2, $x2, $y2, $secondary[1], $font2, $char2); - } - - $characters = array(); - $sizes = array(); - $bounding_boxes = array(); - $width_avail = $img_x; - $code_num = sizeof($code); - $char_class = $this->captcha_char('char_ttf'); - for ($i = 0; $i < $code_num; ++$i) - { - $characters[$i] = new $char_class($code[$i]); - $sizes[$i] = mt_rand(75, 100); - $box = $characters[$i]->dimensions($sizes[$i]); - $width_avail -= ($box[2] - $box[0]); - $bounding_boxes[$i] = $box; - } - - // - // Redistribute leftover x-space - // - $offset = array(); - for ($i = 0; $i < $code_num; ++$i) - { - $denom = ($code_num - $i); - $denom = max(1.5, $denom); - $offset[$i] = mt_rand(0, (1.5 * $width_avail) / $denom); - $width_avail -= $offset[$i]; - } - - // Draw the text - $xoffset = 0; - for ($i = 0; $i < $code_num; ++$i) - { - $characters[$i] = new $char_class($code[$i]); - $dimm = $bounding_boxes[$i]; - $xoffset += ($offset[$i] - $dimm[0]); - $yoffset = mt_rand(-$dimm[1], $img_y - $dimm[3]); - $characters[$i]->drawchar($sizes[$i], $xoffset, $yoffset, $img, $c->r('background'), array($c->r('primary'))); - $xoffset += $dimm[2]; - } - - for ($i = 0; $i < $img_x; ++$i) - { - for ($j = 0; $j < $img_y; ++$j) - { - // if the stencil is not black, set the pixel in the image to gray - if (imagecolorat($stencil, $i, $j)) - { - imagesetpixel($img, $i, $j, $c->r('gray')); - } - } - } - - // Send image - $this->send_image($img); - } - - function policy_cells($code) - { - global $user; - // Generate image - $img_x = 800; - $img_y = 250; - $img = imagecreate($img_x, $img_y); - - $fonts = captcha_load_ttf_fonts(); - - $map = captcha_vectors(); - - // - // Generate colors - // - $c = new color_manager($img, 'white'); - - $c->allocate_named('primary', array( - 'random' => true, - 'min_saturation' => 30, - 'min_value' => 65, - )); - $primaries = $c->color_scheme('primary', 'tetradic'); - $bg_colors = $c->mono_range($primaries, 'value', 4, false); - shuffle($primaries); - shuffle($bg_colors); - - // Randomize the characters on the right and the left - $left_characters = array(); - $right_characters = array(); - $chars = array_merge(range('A', 'Z'), range('1', '9')); - $chars_size = sizeof($chars) - 1; - $alpha = range('A', 'Z'); - $alpha_size = sizeof($alpha) - 1; - for ($i = 0; $i < 25; ++$i) - { - $left_characters[$i] = $alpha[mt_rand(0, $alpha_size)]; - $right_characters[$i] = $chars[mt_rand(0, $chars_size)]; - } - - // Pick locations for our code, shuffle the rest into 3 separate queues - $code_count = sizeof($code); - $code_order = range(0, 24); - shuffle($code_order); - $remaining = array_splice($code_order, $code_count); - $lineups = array($code_order, array(), array(), array()); - for ($i = sizeof($remaining) - 1; $i >= 0; --$i) - { - $lineups[mt_rand(1, 3)][] = $remaining[$i]; - } - - // overwrite the randomized left and right values with our code, where applicable - for ($i = 0; $i < $code_count; ++$i) - { - $left_characters[$code_order[$i]] = $i + 1; - $right_characters[$code_order[$i]] = $code[$i]; - } - - - $offset1 = 50; - $offset2 = 550; - - // Draw the cells and right hand characters - $xs = $ys = array(); - for ($i = 0; $i < 25; ++$i) - { - $xs[$i] = $offset1 + 20 + (($i % 5) * 40) + mt_rand(-13, 13); - $ys[$i] = 45 + (intval($i / 5) * 40) + mt_rand(-13, 13); - - $bg = $c->r_rand($bg_colors); - - // fill the cells with the background colors - imagefilledrectangle($img, - $offset1 + 1 + (($i % 5) * 40), 26 + (intval($i / 5) * 40), - $offset1 + 39 + (($i % 5) * 40), 64 + (intval($i / 5) * 40), - $bg); - imagefilledrectangle($img, - $offset2 + 1 + (($i % 5) * 40), 26 + (intval($i / 5) * 40), - $offset2 + 39 + (($i % 5) * 40), 64 + (intval($i / 5) * 40), - $bg); - - $level = intval($i / 5); - $pos = $i % 5; - imagettftext($img, 12, 0, - $offset2 + 15 + ($pos * 40), 50 + ($level * 40), - $c->is_dark($bg) ? $c->r('white'): $c->r('black'), $fonts['genr102.ttf'], $right_characters[$i]); - } - - // draw the lines that appear between nodes (visual hint) - for ($k = 0; $k < 4; ++$k ) - { - $lineup = $lineups[$k]; - for ($i = 1, $size = sizeof($lineup); $i < $size; ++$i ) - { - imageline($img, - $xs[$lineup[$i - 1]], $ys[$lineup[$i - 1]], - $xs[$lineup[$i]], $ys[$lineup[$i]], - $primaries[$k]); - } - } - - // draw the actual nodes - $textcolor = $c->is_dark($primaries[0]) ? $c->r('white') : $c->r('black'); - for ($k = 0; $k < 4; ++$k ) - { - for ($j = 0, $size = sizeof($lineups[$k]); $j < $size; ++$j ) - { - $i = $lineups[$k][$j]; - imagefilledellipse($img, - $xs[$i], $ys[$i], - 20, 20, - $primaries[$k]); - imagettftext($img, 12, 0, - $xs[$i] - 5, $ys[$i] + 5, - $textcolor, $fonts['genr102.ttf'], $left_characters[$i]); - } - } - - // Draw poly behind explain text - $points = mt_rand(3, 6); - $arc = 360 / $points; - $vertices = array(); - $c_x = $img_x / 2; - $c_y = $img_y / 2; - $radius = $img_y / 2.5; - $start = deg2rad(mt_rand(0, 360)); - for ($i = 0; $i < $points; ++$i) - { - $rad = $start + deg2rad(($arc * $i) + mt_rand(-10, 10)); - $vertices[] = $c_x + (cos($rad) * $radius); - $vertices[] = $c_y + (sin($rad) * $radius); - } - imagefilledpolygon($img, $vertices, $points, $primaries[mt_rand(0,3)]); - - // draw explain text - $count = sizeof($user->lang['CAPTCHA']['cells']); - $line_height = $img_y / ($count + 1); - for ($i = 0; $i < $count; ++$i) - { - $text = $user->lang['CAPTCHA']['cells'][$i]; - $line_width = strlen($text) * 4.5; // ( / 2, * 9 ) - imagestring($img, 6, ($img_x / 2) - $line_width - 1, $line_height * ($i + 1) - 1, $text, $c->r('black')); - imagestring($img, 6, ($img_x / 2) - $line_width - 1, $line_height * ($i + 1) + 1, $text, $c->r('black')); - imagestring($img, 6, ($img_x / 2) - $line_width + 1, $line_height * ($i + 1) + 1, $text, $c->r('black')); - imagestring($img, 6, ($img_x / 2) - $line_width + 1, $line_height * ($i + 1) - 1, $text, $c->r('black')); - imagestring($img, 6, ($img_x / 2) - $line_width, $line_height * ($i + 1), $text, $c->r('white')); - } - - // Send image - $this->send_image($img); - } - - /** - * entropy - */ - function policy_entropy($code) + function execute($code) { global $config; - // Generate image - $img_x = 800; - $img_y = 250; - $img = imagecreatetruecolor($img_x, $img_y); - - // Generate colors - $c = new color_manager($img, array( - 'random' => true, - 'min_value' => 60, - ), 'hsv'); - - $scheme = $c->color_scheme('background', 'triadic', false); - $scheme = $c->mono_range($scheme, 'both', 10, false); - shuffle($scheme); - $bg_colors = array_splice($scheme, mt_rand(6, 12)); + $stats = gd_info(); - // Generate code characters - $characters = $sizes = $bounding_boxes = array(); - $width_avail = $img_x; - $code_num = sizeof($code); - - for ($i = 0; $i < $code_num; ++$i) - { - $char_class = $this->captcha_char(); - $characters[$i] = new $char_class($code[$i]); - - list($min, $max) = $characters[$i]->range(); - $sizes[$i] = mt_rand($min, $max); - $box = $characters[$i]->dimensions($sizes[$i]); - $width_avail -= ($box[2] - $box[0]); - $bounding_boxes[$i] = $box; - } - - // Redistribute leftover x-space - $offset = array(); - for ($i = 0; $i < $code_num; ++$i) + if (substr($stats['GD Version'], 0, 7) === 'bundled') { - $denom = ($code_num - $i); - $denom = max(1.5, $denom); - $offset[$i] = mt_rand(0, (1.5 * $width_avail) / $denom); - $width_avail -= $offset[$i]; + $bundled = true; } - - // Add some line noise - if ($config['policy_entropy_noise_line']) - { - $this->noise_line($img, 0, 0, $img_x, $img_y, $c->r('background'), $scheme, $bg_colors); - } - - // Draw the text - $xoffset = 0; - for ($i = 0; $i < $code_num; ++$i) - { - $dimm = $bounding_boxes[$i]; - $xoffset += ($offset[$i] - $dimm[0]); - $yoffset = mt_rand(-$dimm[1], $img_y - $dimm[3]); - $characters[$i]->drawchar($sizes[$i], $xoffset, $yoffset, $img, $c->r('background'), $scheme); - $xoffset += $dimm[2]; - } - - // Add some pixel noise - if ($config['policy_entropy_noise_pixel']) - { - $this->noise_pixel($img, 0, 0, $img_x, $img_y, $c->r('background'), $scheme, $bg_colors, $config['policy_entropy_noise_pixel']); - } - - // Send image - $this->send_image($img); - } - - /** - * 3dbitmap - */ - function policy_3dbitmap($code) - { - // Generate image - $img_x = 700; - $img_y = 225; - $img = imagecreatetruecolor($img_x, $img_y); - $x_grid = mt_rand(6, 10); - $y_grid = mt_rand(6, 10); - - // Ok, so lets cut to the chase. We could accurately represent this in 3d and - // do all the appropriate linear transforms. my questions is... why bother? - // The computational overhead is unnecessary when you consider the simple fact: - // we're not here to accurately represent a model, but to just show off some random-ish - // polygons - - // Conceive of 3 spaces. - // 1) planar-space (discrete "pixel" grid) - // 2) 3-space. (planar-space with z/height aspect) - // 3) image space (pixels on the screen) - - // resolution of the planar-space we're embedding the text code in - $plane_x = 90; - $plane_y = 25; - - $subdivision_factor = 2; - - // $box is the 4 points in img_space that correspond to the corners of the plane in 3-space - $box = array(array(), array(), array(), array()); - - // Top left - $box[0][0] = mt_rand(20, 40); - $box[0][1] = mt_rand(40, 60); - - // Top right - $box[1][0] = mt_rand($img_x - 80, $img_x - 60); - $box[1][1] = mt_rand(10, 30); - - // Bottom right - $box[2][0] = mt_rand($img_x - 40, $img_x - 20); - $box[2][1] = mt_rand($img_y - 50, $img_y - 30); - - // Bottom left. - // because we want to be able to make shortcuts in the 3d->2d, - // we'll calculate the 4th point so that it forms a proper trapezoid - $box[3][0] = $box[2][0] + $box[0][0] - $box[1][0]; - $box[3][1] = $box[2][1] + $box[0][1] - $box[1][1]; - $c = new color_manager($img, array( - 'random' => true, - 'min_saturation' => 50, - 'min_value' => 65, - )); - - $r1 = $c->random_color(array( - 'min_value' => 20, - 'max_value' => 50, - )); - $r2 = $c->random_color(array( - 'min_value' => 70, - 'max_value' => 100, - )); - $rdata = mt_rand(0,1) ? array( - $c->colors[$r1], - $c->colors[$r2], - ) : array( - $c->colors[$r2], - $c->colors[$r1], - ); - - $colors = array(); - for ($i = 0; $i < 60; ++$i) - { - $colors[$i - 30] = $c->allocate(array( - $rdata[0][0], - (($i * $rdata[0][1]) + ((60 - $i) * $rdata[1][1])) / 60, - (($i * $rdata[0][2]) + ((60 - $i) * $rdata[1][2])) / 60, - )); - } - - // $img_buffer is the last row of 3-space positions (converted to img-space), cached - // (using this means we don't need to recalculate all 4 positions for each new polygon, - // merely the newest point that we're adding, which is then cached. - $img_buffer = array(array(), array()); - - // In image-space, the x- and y-offset necessary to move one unit in the x-direction in planar-space - $dxx = ($box[1][0] - $box[0][0]) / ($subdivision_factor * $plane_x); - $dxy = ($box[1][1] - $box[0][1]) / ($subdivision_factor * $plane_x); - - // In image-space, the x- and y-offset necessary to move one unit in the y-direction in planar-space - $dyx = ($box[3][0] - $box[0][0]) / ($subdivision_factor * $plane_y); - $dyy = ($box[3][1] - $box[0][1]) / ($subdivision_factor * $plane_y); - - // Initial captcha-letter offset in planar-space - $plane_offset_x = 2; - $plane_offset_y = 5; - - // character map - $map = captcha_bitmaps(); - - // matrix - $plane = array(); - - // for each character, we'll silkscreen it into our boolean pixel plane - for ($c = 0, $code_num = sizeof($code); $c < $code_num; ++$c) - { - $letter = $code[$c]; - - for ($x = $map['width'] - 1; $x >= 0; --$x) - { - for ($y = $map['height'] - 1; $y >= 0; --$y) - { - if ($map['data'][$letter][$y][$x]) - { - $plane[$y + $plane_offset_y + (($c & 1) ? 1 : -1)][$x + $plane_offset_x] = true; - } - } - } - $plane_offset_x += 11; - } - - // calculate our first buffer, we can't actually draw polys with these yet - // img_pos_prev == screen x,y location to our immediate left. - // img_pos_cur == current screen x,y location - // we calculate screen position of our - // current cell based on the difference from the previous cell - // rather than recalculating from absolute coordinates - // What we cache into the $img_buffer contains the raised text coordinates. - $img_pos_prev = $img_buffer[0][0] = $box[0]; - $cur_height = $prev_height = $this->wave_height(0, 0, $subdivision_factor); - $full_x = $plane_x * $subdivision_factor; - $full_y = $plane_y * $subdivision_factor; - - for ($x = 1; $x <= $full_x; ++$x) - { - $cur_height = $this->wave_height($x, 0, $subdivision_factor); - $offset = $cur_height - $prev_height; - $img_pos_cur = array($img_pos_prev[0] + $dxx, - $img_pos_prev[1] + $dxy + $offset); - - $img_buffer[0][$x] = $img_pos_cur; - $img_pos_prev = $img_pos_cur; - $prev_height = $cur_height; - } - - for ($y = 1; $y <= $full_y; ++$y) - { - // swap buffers - $buffer_cur = $y & 1; - $buffer_prev = 1 - $buffer_cur; - - $prev_height = $this->wave_height(0, $y, $subdivision_factor); - $offset = $prev_height - $this->wave_height(0, $y - 1, $subdivision_factor); - $img_pos_cur = array($img_buffer[$buffer_prev][0][0] + $dyx, - $img_buffer[$buffer_prev][0][1] + $dyy + $offset); - $img_pos_prev = $img_pos_cur; - - $img_buffer[$buffer_cur][0] = $img_pos_cur; - - for ($x = 1; $x <= $full_x; ++$x) - { - $cur_height = $this->wave_height($x, $y, $subdivision_factor) + $this->grid_height($x, $y, 1, $x_grid, $y_grid); - - //height is a z-factor, not a y-factor - $offset = $cur_height - $prev_height; - $img_pos_cur = array($img_pos_prev[0] + $dxx, - $img_pos_prev[1] + $dxy + $offset); - - //(height is float, index it to an int, get closest color) - $color = $colors[intval($cur_height)]; - $img_pos_prev = $img_pos_cur; - $prev_height = $cur_height; - - $y_index_old = intval(($y - 1) / $subdivision_factor); - $y_index_new = intval($y / $subdivision_factor); - $x_index_old = intval(($x - 1) / $subdivision_factor); - $x_index_new = intval($x / $subdivision_factor); - - if (!empty($plane[$y_index_new][$x_index_new])) - { - $offset2 = $this->wave_height($x, $y, $subdivision_factor, 1) - 30 - $cur_height; - $img_pos_cur[1] += $offset2; - $color = $colors[20]; - } - $img_buffer[$buffer_cur][$x] = $img_pos_cur; - - // Smooth the edges as much as possible by having not more than one low<->high traingle per square - // Otherwise, just - $diag_down = (empty($plane[$y_index_old][$x_index_old]) == empty($plane[$y_index_new][$x_index_new])); - $diag_up = (empty($plane[$y_index_old][$x_index_new]) == empty($plane[$y_index_new][$x_index_old])); - - // natural switching - $mode = ($x + $y) & 1; - - // override if it requires it - if ($diag_down != $diag_up) - { - $mode = $diag_up; - } - - if ($mode) - { - // +-/ / - // 1 |/ 2 /| - // / /-+ - $poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x]); - $poly2 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_cur][$x], $img_buffer[$buffer_prev][$x]); - } - else - { - // \ \-+ - // 1 |\ 2 \| - // +-\ \ - $poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_cur][$x]); - $poly2 = array_merge($img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x], $img_buffer[$buffer_cur][$x]); - } - - imagefilledpolygon($img, $poly1, 3, $color); - imagefilledpolygon($img, $poly2, 3, $color); - } - } - - // Send image on it's merry way - $this->send_image($img); - } - - /** - * overlap - */ - function policy_overlap($code) - { - global $config; - $char_size = 40; - $overlap_factor = .32; - - // Generate image - $img_x = 250; - $img_y = 120; - $img = imagecreatetruecolor($img_x, $img_y); - - // Generate colors - $c = new color_manager($img, array( - 'random' => true, - 'min_saturation' => 70, - 'min_value' => 65, - )); - - $primaries = $c->color_scheme('background', 'triadic', false); - $text = mt_rand(0, 1); - $c->name_color('text', $primaries[$text]); - $noise = $c->mono_range($primaries[1 - $text], 'both', 6, false); - - // Generate code characters - $characters = $bounding_boxes = array(); - $width_avail = $img_x; - - // Get the character rendering scheme - $char_class = $this->captcha_char('char_ttf'); - $code_num = sizeof($code); - - for ($i = 0; $i < $code_num; ++$i) - { - $characters[$i] = new $char_class($code[$i], array('angle' => 0)); - $box = $characters[$i]->dimensions($char_size); - $width_avail -= ((1 - $overlap_factor) * ($box[2] - $box[0])); - $bounding_boxes[$i] = $box; - } - - // Redistribute leftover x-space - $offset = mt_rand(0, $width_avail); - - // Add some line noise - if ($config['policy_overlap_noise_line']) - { - $this->noise_line($img, 0, 0, $img_x, $img_y, $c->r('background'), array($c->r('text')), $noise); - } - - // Draw the text - $min = 10 - $bounding_boxes[0][1]; - $max = ($img_y - 10) - $bounding_boxes[0][3]; - $med = ($max + $min) / 2; - - $yoffset = mt_rand($med, $max); - $char_num = sizeof($characters); - - imagesetthickness($img, 3); - for ($i = 0; $i < $char_num; ++$i) - { - if ($i) - { - imageline($img, $old_x + mt_rand(-3, 3), $old_y - 70 + mt_rand(-3, 3), $offset + mt_rand(-3, 3), $yoffset - 70 + mt_rand(-3, 3), $c->r('text')); - imageline($img, $old_x + mt_rand(-3, 3), $old_y + 30 + mt_rand(-3, 3), $offset + mt_rand(-3, 3), $yoffset + 30 + mt_rand(-3, 3), $c->r('text')); - } - - $dimm = $bounding_boxes[$i]; - $offset -= $dimm[0]; - $characters[$i]->drawchar($char_size, $offset, $yoffset, $img, $c->r('background'), array($c->r('text'))); - - $old_x = $offset; - $old_y = $yoffset; - - $offset += $dimm[2]; - $offset -= (($dimm[2] - $dimm[0]) * $overlap_factor); - $yoffset += ($i & 1) ? ((1 - $overlap_factor) * ($dimm[3] - $dimm[1])) : ((1 - $overlap_factor) * ($dimm[1] - $dimm[3])); - } - - imagesetthickness($img, 1); - - // Add some medium pixel noise - if ($config['policy_overlap_noise_pixel']) - { - $this->noise_pixel($img, 0, 0, $img_x, $img_y, $c->r('background'), array($c->r('text')), $noise, $config['policy_overlap_noise_pixel']); - } - - // Send image - $this->send_image($img); - } - - /** - * Noise pixel - */ - function noise_pixel($img, $min_x, $min_y, $max_x, $max_y, $bg, $font, $non_font, $override = false) - { - $noise_modules = array('noise_pixel_light', 'noise_pixel_medium', 'noise_pixel_heavy'); - - if ($override == false) - { - $override = array_rand($override); - } - - // Use the module $override, else a random picked one... - $module = $noise_modules[intval($override) - 1]; - - switch ($module) - { - case 'noise_pixel_light': - - for ($x = $min_x; $x < $max_x; $x += mt_rand(9, 18)) - { - for ($y = $min_y; $y < $max_y; $y += mt_rand(4, 9)) - { - imagesetpixel($img, $x, $y, $non_font[array_rand($non_font)]); - } - } - - for ($y = $min_y; $y < $max_y; $y += mt_rand(9, 18)) - { - for ($x = $min_x; $x < $max_x; $x += mt_rand(4, 9)) - { - imagesetpixel($img, $x, $y, $non_font[array_rand($non_font)]); - } - } - - break; - - case 'noise_pixel_medium': - - for ($x = $min_x; $x < $max_x; $x += mt_rand(4, 9)) - { - for ($y = $min_y; $y < $max_y; $y += mt_rand(2, 5)) - { - imagesetpixel($img, $x, $y, $non_font[array_rand($non_font)]); - } - } - - for ($y = $min_y; $y < $max_y; $y += mt_rand(4, 9)) - { - for ($x = $min_x; $x < $max_x; $x += mt_rand(2, 5)) - { - imagesetpixel($img, $x, $y, $non_font[array_rand($non_font)]); - } - } - - break; - - case 'noise_pixel_heavy': - - for ($x = $min_x; $x < $max_x; $x += mt_rand(4, 9)) - { - for ($y = $min_y; $y < $max_y; $y++) - { - imagesetpixel($img, $x, $y, $non_font[array_rand($non_font)]); - } - } - - for ($y = $min_y; $y < $max_y; $y+= mt_rand(4, 9)) - { - for ($x = $min_x; $x < $max_x; $x++) - { - imagesetpixel($img, $x, $y, $non_font[array_rand($non_font)]); - } - } - - break; - } - } - - /** - * Noise line - */ - function noise_line($img, $min_x, $min_y, $max_x, $max_y, $bg, $font, $non_font) - { - imagesetthickness($img, 2); - $x1 = $min_x; - $x2 = $max_x; - $y1 = $min_y; - $y2 = $min_y; - - do + else { - $line = array_merge( - array_fill(0, mt_rand(30, 60), $non_font[array_rand($non_font)]), - array_fill(0, mt_rand(30, 60), $bg) - ); - - imagesetstyle($img, $line); - imageline($img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); - - $y1 += mt_rand(12, 35); - $y2 += mt_rand(12, 35); + $bundled = false; } - while ($y1 < $max_y && $y2 < $max_y); - - $x1 = $min_x; - $x2 = $min_x; - $y1 = $min_y; - $y2 = $max_y; - do + preg_match('/[\\d.]+/', $stats['GD Version'], $version); + if (version_compare($version[0], '2.0.1', '>=')) { - $line = array_merge( - array_fill(0, mt_rand(30, 60), $non_font[array_rand($non_font)]), - array_fill(0, mt_rand(30, 60), $bg) - ); - - imagesetstyle($img, $line); - imageline($img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); - - $x1 += mt_rand(12, 35); - $x2 += mt_rand(12, 35); + $gd_version = 2; } - while ($x1 < $max_x && $x2 < $max_x); - imagesetthickness($img, 1); - } - - /** - * Randomly determine which char class to use - * Able to define static one with override - */ - function captcha_char($override = false) - { - static $character_classes = array(); - - // Some people have GD but no TTF support - if (sizeof($character_classes) == 0) + else { - $character_classes = array('char_vector', 'char_hatches', 'char_cube3d', 'char_dots'); - - if (function_exists('imagettfbbox') && function_exists('imagettftext')) - { - $character_classes[] = 'char_ttf'; - } + $gd_version = 1; } - // Use the module $override, else a random picked one... - $class = ($override !== false && in_array($override, $character_classes)) ? $override : $character_classes[array_rand($character_classes)]; - - return $class; - } -} - -/** -* @package VC -*/ -class char_dots -{ - var $vectors; - var $space; - var $radius; - var $letter; - var $width_percent; + // set dimension of image + $lx = 360; + $ly = 96; - /** - * Constuctor - */ - function char_dots($letter = '', $args = false) - { - $width_percent = false; - if (is_array($args)) + // create the image, stay compat with older versions of GD + if ($gd_version === 2) { - $width_percent = (!empty($args['width_percent'])) ? $args['width_percent'] : false; + $func1 = 'imagecreatetruecolor'; + $func2 = 'imagecolorallocate'; } - - $this->vectors = captcha_vectors(); - $this->width_percent = (!empty($width_percent)) ? max(25, min(150, intval($width_percent))) : mt_rand(60, 90); - - $this->space = 10; - $this->radius = 3; - $this->density = 3; - $this->letter = $letter; - } - - /** - * Draw a character - */ - function drawchar($scale, $xoff, $yoff, $img, $background, $colors) - { - $vectorset = $this->vectors[$this->letter]; - $height = $scale; - $width = (($scale * $this->width_percent) / 100); - $color = $colors[array_rand($colors)]; - - if (sizeof($vectorset)) + else { - foreach ($vectorset as $veclist) - { - switch ($veclist[0]) - { - case 'line': - - $dx = ($veclist[3] - $veclist[1]) * $width; - $dy = ($veclist[4] - $veclist[2]) * -$height; - - $len = sqrt(($dx * $dx) + ($dy * $dy)); - - $inv_dx = -($dy / $len); - $inv_dy = ($dx / $len); - - for ($i = 0; $i < $len; ++$i) - { - for ($k = 0; $k <= $this->density; ++$k) - { - $shift = mt_rand(-$this->radius, $this->radius); - imagesetpixel($img, - $xoff + ($veclist[1] * $width) + (($i * $dx) / $len) + ($inv_dx * $shift), - $yoff + ((1 - $veclist[2]) * $height) + (($i * $dy) / $len) + ($inv_dy * $shift), - $color); - } - } - - break; - - case 'arc': - - $arclengthdeg = $veclist[6] - $veclist[5]; - $arclengthdeg += ( $arclengthdeg < 0 ) ? 360 : 0; - - $arclength = ((($veclist[3] * $width) + ($veclist[4] * $height)) * M_PI) / 2; - - $arclength = ($arclength * $arclengthdeg) / 360; - - $x_c = $veclist[1] * $width; - $y_c = (1 - $veclist[2]) * $height; - $increment = ($arclengthdeg / $arclength); - - for ($i = 0; $i < $arclengthdeg; $i += $increment) - { - $theta = deg2rad(($i + $veclist[5]) % 360); - $x_o = cos($theta); - $y_o = sin($theta); - $pre_width = ($veclist[3] * 0.5 * $width); - $pre_height = ($veclist[4] * 0.5 * $height); - for ($k = 0; $k <= $this->density; ++$k) - { - $shift = mt_rand(-$this->radius, $this->radius); - $x_o1 = $x_o * ($pre_width + $shift); - $y_o1 = $y_o * ($pre_height + $shift); - imagesetpixel($img, - $xoff + $x_c + $x_o1, - $yoff + $y_c + $y_o1, - $color); - } - } - - break; - - default: - // Do nothing with bad input - break; - } - } + $func1 = 'imagecreate'; + $func2 = 'imagecolorclosest'; } - } - /* - * return a roughly acceptable range of sizes for rendering with this texttype - */ - function range() - { - return array(60, 80); - } + $image = $func1($lx, $ly); - /** - * dimensions - */ - function dimensions($size) - { - return array(-4, -4, (($size * $this->width_percent) / 100) + 4, $size + 4); - } -} - -/** -* @package VC -*/ -class char_vector -{ - var $vectors; - var $width_percent; - var $letter; - - /** - * Constructor - */ - function char_vector($letter = '', $args = false) - { - $width_percent = false; - if (is_array($args)) + if ($bundled) { - $width_percent = (!empty($args['width_percent'])) ? $args['width_percent'] : false; + imageantialias($image, true); } - $this->vectors = captcha_vectors(); - $this->width_percent = (!empty($width_percent)) ? max(25, min(150, intval($width_percent))) : mt_rand(60,90); - $this->letter = $letter; - } - - /** - * Draw a character - */ - function drawchar($scale, $xoff, $yoff, $img, $background, $colors) - { - $vectorset = $this->vectors[$this->letter]; - $height = $scale; - $width = (($scale * $this->width_percent) / 100); - $color = $colors[array_rand($colors)]; + // set background color + $back = imagecolorallocate($image, mt_rand(224, 255), mt_rand(224, 255), mt_rand(224, 255)); + imagefilledrectangle($image, 0, 0, $lx, $ly, $back); - if (sizeof($vectorset)) + // allocates the 216 websafe color palette to the image + if ($gd_version === 1) { - foreach ($vectorset as $veclist) + for ($r = 0; $r <= 255; $r += 51) { - for ($i = 0; $i < 9; ++$i) + for ($g = 0; $g <= 255; $g += 51) { - $xp = $i % 3; - $yp = ($i - $xp) / 3; - $xp--; - $yp--; - - switch ($veclist[0]) + for ($b = 0; $b <= 255; $b += 51) { - case 'line': - imageline($img, - $xoff + $xp + ($veclist[1] * $width), - $yoff + $yp + ((1 - $veclist[2]) * $height), - $xoff + $xp + ($veclist[3] * $width), - $yoff + $yp + ((1 - $veclist[4]) * $height), - $color - ); - break; - - case 'arc': - imagearc($img, - $xoff + $xp + ($veclist[1] * $width), - $yoff + $yp + ((1 - $veclist[2]) * $height), - $veclist[3] * $width, - $veclist[4] * $height, - $veclist[5], - $veclist[6], - $color - ); - break; + imagecolorallocate($image, $r, $g, $b); } } } } - } - - /* - * return a roughly acceptable range of sizes for rendering with this texttype - */ - function range() - { - return array(50, 80); - } - - /** - * dimensions - */ - function dimensions($size) - { - return array(-2, -2, (($size * $this->width_percent) / 100 ) + 2, $size + 2); - } -} - -/** -* @package VC -*/ -class char_ttf -{ - var $angle = 0; - var $fontfile = ''; - var $letter = ''; - - /** - * Constructor - */ - function char_ttf($letter = '', $args = false) - { - $font = $angle = false; - - if (is_array($args)) - { - $font = (!empty($args['font'])) ? $args['font'] : false; - $angle = (isset($args['angle'])) ? $args['angle'] : false; - } - - $fonts = captcha_load_ttf_fonts(); - - if (empty($font) || !isset($fonts[$font])) - { - $font = array_rand($fonts); - } - - $this->fontfile = $fonts[$font]; - $this->angle = ($angle !== false) ? intval($angle) : mt_rand(-40, 40); - $this->letter = $letter; - } - - /** - * Draw a character - */ - function drawchar($scale, $xoff, $yoff, $img, $background, $colors) - { - $color = $colors[array_rand($colors)]; - imagettftext($img, $scale, $this->angle, $xoff, $yoff, $color, $this->fontfile, $this->letter); - } - - /* - * return a roughly acceptable range of sizes for rendering with this texttype - */ - function range() - { - return array(36, 150); - } - - /** - * Dimensions - */ - function dimensions($scale) - { - $data = imagettfbbox($scale, $this->angle, $this->fontfile, $this->letter); - return ($this->angle > 0) ? array($data[6], $data[5], $data[2], $data[1]) : array($data[0], $data[7], $data[4], $data[3]); - } -} - -/** -* @package VC -*/ -class char_hatches -{ - var $vectors; - var $space; - var $radius; - var $letter; - - /** - * Constructor - */ - function char_hatches($letter = '', $args = false) - { - $width_percent = false; - if (is_array($args)) - { - $width_percent = (!empty($args['width_percent'])) ? $args['width_percent'] : false; - } - - $this->vectors = captcha_vectors(); - $this->width_percent = (!empty($width_percent)) ? max(25, min(150, intval($width_percent))) : mt_rand(60, 90); - $this->space = 10; - $this->radius = 3; - $this->letter = $letter; - } - - /** - * Draw a character - */ - function drawchar($scale, $xoff, $yoff, $img, $background, $colors) - { - $vectorset = $this->vectors[$this->letter]; - $height = $scale; - $width = (($scale * $this->width_percent) / 100); - $color = $colors[array_rand($colors)]; - if (sizeof($vectorset)) + // fill with noise or grid + if ($config['captcha_gd_noise']) { - foreach ($vectorset as $veclist) + // random characters in background with random position, angle, color + for ($i = 0 ; $i < 72; $i++) { - switch ($veclist[0]) - { - case 'line': - $dx = ($veclist[3] - $veclist[1]) * $width; - $dy = ($veclist[4] - $veclist[2]) * -$height; - - $idx = -$dy; - $idy = $dx; - - $length = sqrt(pow($dx, 2) + pow($dy, 2)); - - $hatches = $length / $this->space; - - for ($p = 0; $p <= $hatches; ++$p) - { - if (!$p && !mt_rand(0, 9) && ($hatches > 3)) - { - continue; - } - - $xp = 1; - $yp = -2; - for ($i = 0; $i < 9; ++$i) - { - $xp += !($i % 3) ? -2 : 1; - $yp += !($i % 3) ? 1 : 0; - - $x_o = ((($p * $veclist[1]) + (($hatches - $p) * $veclist[3])) * $width ) / $hatches; - $y_o = $height - (((($p * $veclist[2]) + (($hatches - $p) * $veclist[4])) * $height ) / $hatches); - $x_1 = $xoff + $xp + $x_o; - $y_1 = $yoff + $yp + $y_o; - - $x_d1 = (($dx - $idx) * $this->radius) / $length; - $y_d1 = (($dy - $idy) * $this->radius) / $length; - - $x_d2 = (($dx - $idx) * -$this->radius) / $length; - $y_d2 = (($dy - $idy) * -$this->radius) / $length; - - imageline($img, $x_1 + $x_d1, $y_1 + $y_d1, $x_1 + $x_d2, $y_1 + $y_d2, $color); - } - } - break; - - case 'arc': - $arclengthdeg = $veclist[6] - $veclist[5]; - $arclengthdeg += ( $arclengthdeg < 0 ) ? 360 : 0; - - $arclength = ((($veclist[3] * $width) + ($veclist[4] * $height)) * M_PI) / 2; - $arclength = ($arclength * $arclengthdeg) / 360; - - $hatches = $arclength / $this->space; - - $hatchdeg = ($arclengthdeg * $this->space) / $arclength; - $shiftdeg = ($arclengthdeg * $this->radius) / $arclength; - - $x_c = $veclist[1] * $width; - $y_c = (1 - $veclist[2]) * $height; - - for ($p = 0; $p <= $arclengthdeg; $p += $hatchdeg) - { - if (!mt_rand(0, 9) && ($hatches > 3) && !$p) - { - continue; - } - - $theta1 = deg2rad(($p + $veclist[5] - $shiftdeg) % 360); - $theta2 = deg2rad(($p + $veclist[5] + $shiftdeg) % 360); - $x_o1 = cos($theta1) * (($veclist[3] * 0.5 * $width) - $this->radius); - $y_o1 = sin($theta1) * (($veclist[4] * 0.5 * $height) - $this->radius); - $x_o2 = cos($theta2) * (($veclist[3] * 0.5 * $width) + $this->radius); - $y_o2 = sin($theta2) * (($veclist[4] * 0.5 * $height) + $this->radius); - - $xp = 1; - $yp = -2; - for ($i = 0; $i < 9; ++$i) - { - $xp += !($i % 3) ? -2 : 1; - $yp += !($i % 3) ? 1 : 0; - - imageline($img, - $xoff + $xp + $x_c + $x_o1, - $yoff + $yp + $y_c + $y_o1, - $xoff + $xp + $x_c + $x_o2, - $yoff + $yp + $y_c + $y_o2, - $color - ); - } - } - break; - } + $size = mt_rand(8, 23); + $angle = mt_rand(0, 360); + $x = mt_rand(0, 360); + $y = mt_rand(0, (int)($ly - ($size / 5))); + $color = $func2($image, mt_rand(160, 224), mt_rand(160, 224), mt_rand(160, 224)); + $text = chr(mt_rand(45, 250)); + imagettftext($image, $size, $angle, $x, $y, $color, $this->get_font(), $text); } } - } - - /* - * return a roughly acceptable range of sizes for rendering with this texttype - */ - function range() - { - return array(60, 80); - } - - /** - * Dimensions - */ - function dimensions($size) - { - return array(-4, -4, (($size * $this->width_percent) / 100) + 4, $size + 4); - } -} - -/** -* @package VC -*/ -class char_cube3d -{ - // need to abstract out the cube3d from the cubechar - var $bitmaps; - - var $basis_matrix = array(array(1, 0, 0), array(0, 1, 0), array(0, 0, 1)); - var $abs_x = array(1, 0); - var $abs_y = array(0, 1); - var $x = 0; - var $y = 1; - var $z = 2; - var $letter = ''; - - function char_cube3d($letter) - { - $this->bitmaps = captcha_bitmaps(); - - $this->basis_matrix[0][0] = mt_rand(-600, 600); - $this->basis_matrix[0][1] = mt_rand(-600, 600); - $this->basis_matrix[0][2] = (mt_rand(0, 1) * 2000) - 1000; - $this->basis_matrix[1][0] = mt_rand(-1000, 1000); - $this->basis_matrix[1][1] = mt_rand(-1000, 1000); - $this->basis_matrix[1][2] = mt_rand(-1000, 1000); - - $this->normalize($this->basis_matrix[0]); - $this->normalize($this->basis_matrix[1]); - $this->basis_matrix[2] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[1]); - $this->normalize($this->basis_matrix[2]); - - // $this->basis_matrix[1] might not be (probably isn't) orthogonal to $basis_matrix[0] - $this->basis_matrix[1] = $this->cross_product($this->basis_matrix[0], $this->basis_matrix[2]); - $this->normalize($this->basis_matrix[1]); - - // Make sure our cube is facing into the canvas (assuming +z == in) - for ($i = 0; $i < 3; ++$i) + else { - if ($this->basis_matrix[$i][2] < 0) + // generate grid + for ($i = 0; $i < $lx; $i += 13) { - $this->basis_matrix[$i][0] *= -1; - $this->basis_matrix[$i][1] *= -1; - $this->basis_matrix[$i][2] *= -1; + $color = $func2($image, mt_rand(160, 224), mt_rand(160, 224), mt_rand(160, 224)); + imageline($image, $i, 0, $i, $ly, $color); } - } - - // Force our "z" basis vector to be the one with greatest absolute z value - $this->x = 0; - $this->y = 1; - $this->z = 2; - - // Swap "y" with "z" - if ($this->basis_matrix[1][2] > $this->basis_matrix[2][2]) - { - $this->z = 1; - $this->y = 2; - } - - // Swap "x" with "z" - if ($this->basis_matrix[0][2] > $this->basis_matrix[$this->z][2]) - { - $this->x = $this->z; - $this->z = 0; - } - - // Still need to determine which of $x,$y are which. - // wrong orientation if y's y-component is less than it's x-component - // likewise if x's x-component is less than it's y-component - // if they disagree, go with the one with the greater weight difference. - // rotate if positive - $weight = (abs($this->basis_matrix[$this->x][1]) - abs($this->basis_matrix[$this->x][0])) + - (abs($this->basis_matrix[$this->y][0]) - abs($this->basis_matrix[$this->y][1])); - - // Swap "x" with "y" - if ($weight > 0) - { - list($this->x, $this->y) = array($this->y, $this->x); - } - - $this->abs_x = array($this->basis_matrix[$this->x][0], $this->basis_matrix[$this->x][1]); - $this->abs_y = array($this->basis_matrix[$this->y][0], $this->basis_matrix[$this->y][1]); - - if ($this->abs_x[0] < 0) - { - $this->abs_x[0] *= -1; - $this->abs_x[1] *= -1; - } - - if ($this->abs_y[1] > 0) - { - $this->abs_y[0] *= -1; - $this->abs_y[1] *= -1; - } - - $this->letter = $letter; - } - - /** - * - */ - function draw($im, $scale, $xoff, $yoff, $face, $xshadow, $yshadow) - { - $origin = array(0, 0, 0); - $xvec = $this->scale($this->basis_matrix[$this->x], $scale); - $yvec = $this->scale($this->basis_matrix[$this->y], $scale); - $face_corner = $this->sum2($xvec, $yvec); - - $zvec = $this->scale($this->basis_matrix[$this->z], $scale); - $x_corner = $this->sum2($xvec, $zvec); - $y_corner = $this->sum2($yvec, $zvec); - - imagefilledpolygon($im, $this->gen_poly($xoff, $yoff, $origin, $xvec, $x_corner, $zvec), 4, $yshadow); - imagefilledpolygon($im, $this->gen_poly($xoff, $yoff, $origin, $yvec, $y_corner, $zvec), 4, $xshadow); - imagefilledpolygon($im, $this->gen_poly($xoff, $yoff, $origin, $xvec, $face_corner, $yvec), 4, $face); - } - - /** - * Draw a character - */ - function drawchar($scale, $xoff, $yoff, $img, $background, $colors) - { - $width = $this->bitmaps['width']; - $height = $this->bitmaps['height']; - $bitmap = $this->bitmaps['data'][$this->letter]; - - $color1 = $colors[array_rand($colors)]; - $color2 = $colors[array_rand($colors)]; - - $swapx = ($this->basis_matrix[$this->x][0] > 0); - $swapy = ($this->basis_matrix[$this->y][1] < 0); - - for ($y = 0; $y < $height; ++$y) - { - for ($x = 0; $x < $width; ++$x) + for ($i = 0; $i < $ly; $i += 11) { - $xp = ($swapx) ? ($width - $x - 1) : $x; - $yp = ($swapy) ? ($height - $y - 1) : $y; - - if ($bitmap[$height - $yp - 1][$xp]) - { - $dx = $this->scale($this->abs_x, ($xp - ($swapx ? ($width / 2) : ($width / 2) - 1)) * $scale); - $dy = $this->scale($this->abs_y, ($yp - ($swapy ? ($height / 2) : ($height / 2) - 1)) * $scale); - $xo = $xoff + $dx[0] + $dy[0]; - $yo = $yoff + $dx[1] + $dy[1]; - - $origin = array(0, 0, 0); - $xvec = $this->scale($this->basis_matrix[$this->x], $scale); - $yvec = $this->scale($this->basis_matrix[$this->y], $scale); - $face_corner = $this->sum2($xvec, $yvec); - - $zvec = $this->scale($this->basis_matrix[$this->z], $scale); - $x_corner = $this->sum2($xvec, $zvec); - $y_corner = $this->sum2($yvec, $zvec); - - imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $xvec, $x_corner,$zvec), 4, $color1); - imagefilledpolygon($img, $this->gen_poly($xo, $yo, $origin, $yvec, $y_corner,$zvec), 4, $color2); - - $face = $this->gen_poly($xo, $yo, $origin, $xvec, $face_corner, $yvec); - - imagefilledpolygon($img, $face, 4, $background); - imagepolygon($img, $face, 4, $color1); - } + $color = $func2($image, mt_rand(160, 224), mt_rand(160, 224), mt_rand(160, 224)); + imageline($image, 0, $i, $lx, $i, $color); } } - } - - /* - * return a roughly acceptable range of sizes for rendering with this texttype - */ - function range() - { - return array(5, 10); - } - /** - * Vector length - */ - function vectorlen($vector) - { - return sqrt(pow($vector[0], 2) + pow($vector[1], 2) + pow($vector[2], 2)); - } - - /** - * Normalize - */ - function normalize(&$vector, $length = 1) - { - $length = (( $length < 1) ? 1 : $length); - $length /= $this->vectorlen($vector); - $vector[0] *= $length; - $vector[1] *= $length; - $vector[2] *= $length; - } - - /** - * - */ - function cross_product($vector1, $vector2) - { - $retval = array(0, 0, 0); - $retval[0] = (($vector1[1] * $vector2[2]) - ($vector1[2] * $vector2[1])); - $retval[1] = -(($vector1[0] * $vector2[2]) - ($vector1[2] * $vector2[0])); - $retval[2] = (($vector1[0] * $vector2[1]) - ($vector1[1] * $vector2[0])); + $len = strlen($code); - return $retval; - } - - /** - * - */ - function sum($vector1, $vector2) - { - return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1], $vector1[2] + $vector2[2]); - } - - /** - * - */ - function sum2($vector1, $vector2) - { - return array($vector1[0] + $vector2[0], $vector1[1] + $vector2[1]); - } - - /** - * - */ - function scale($vector, $length) - { - if (sizeof($vector) == 2) + for ($i = 0, $x = mt_rand(20, 40); $i < $len; $i++) { - return array($vector[0] * $length, $vector[1] * $length); - } + $text = strtoupper($code[$i]); + $angle = mt_rand(-30, 30); + $size = mt_rand(20, 40); + $y = mt_rand((int)($size * 1.5), (int)($ly - ($size / 7))); - return array($vector[0] * $length, $vector[1] * $length, $vector[2] * $length); - } + $color = $func2($image, mt_rand(0, 127), mt_rand(0, 127), mt_rand(0, 127)); + $shadow = $func2($image, mt_rand(127, 254), mt_rand(127, 254), mt_rand(127, 254)); + $font = $this->get_font(); - /** - * - */ - function gen_poly($xoff, $yoff, &$vec1, &$vec2, &$vec3, &$vec4) - { - $poly = array(); - $poly[0] = $xoff + $vec1[0]; - $poly[1] = $yoff + $vec1[1]; - $poly[2] = $xoff + $vec2[0]; - $poly[3] = $yoff + $vec2[1]; - $poly[4] = $xoff + $vec3[0]; - $poly[5] = $yoff + $vec3[1]; - $poly[6] = $xoff + $vec4[0]; - $poly[7] = $yoff + $vec4[1]; + imagettftext($image, $size, $angle, $x + (int)($size / 15), $y, $shadow, $font, $text); + imagettftext($image, $size, $angle, $x, $y - (int)($size / 15), $color, $font, $text); - return $poly; - } - - /** - * dimensions - */ - function dimensions($size) - { - $xn = $this->scale($this->basis_matrix[$this->x], -($this->bitmaps['width'] / 2) * $size); - $xp = $this->scale($this->basis_matrix[$this->x], ($this->bitmaps['width'] / 2) * $size); - $yn = $this->scale($this->basis_matrix[$this->y], -($this->bitmaps['height'] / 2) * $size); - $yp = $this->scale($this->basis_matrix[$this->y], ($this->bitmaps['height'] / 2) * $size); - - $p = array(); - $p[0] = $this->sum2($xn, $yn); - $p[1] = $this->sum2($xp, $yn); - $p[2] = $this->sum2($xp, $yp); - $p[3] = $this->sum2($xn, $yp); - - $min_x = $max_x = $p[0][0]; - $min_y = $max_y = $p[0][1]; - - for ($i = 1; $i < 4; ++$i) - { - $min_x = ($min_x > $p[$i][0]) ? $p[$i][0] : $min_x; - $min_y = ($min_y > $p[$i][1]) ? $p[$i][1] : $min_y; - $max_x = ($max_x < $p[$i][0]) ? $p[$i][0] : $max_x; - $max_y = ($max_y < $p[$i][1]) ? $p[$i][1] : $max_y; + $x += $size + 4; } - return array($min_x, $min_y, $max_x, $max_y); - } -} - -/** -* Return bitmaps -*/ -function captcha_bitmaps() -{ - return array( - 'width' => 9, - 'height' => 15, - 'data' => array( - 'A' => array( - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,1,1,1,1,1,1,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - ), - 'B' => array( - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - ), - 'C' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - 'D' => array( - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - ), - 'E' => array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,1,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,1,1), - ), - 'F' => array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - ), - 'G' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,1,1,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - 'H' => array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - ), - 'I' => array( - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(1,1,1,1,1,1,1,1,1), - ), - 'J' => array( - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(0,1,0,0,1,0,0,0,0), - array(0,0,1,1,0,0,0,0,0), - ), - 'K' => array( // New 'K', supplied by NeoThermic - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,1,0,0,0,0), - array(1,0,0,1,0,0,0,0,0), - array(1,0,1,0,0,0,0,0,0), - array(1,1,0,0,0,0,0,0,0), - array(1,0,1,0,0,0,0,0,0), - array(1,0,0,1,0,0,0,0,0), - array(1,0,0,0,1,0,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - ), - 'L' => array( - array(0,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,1,1), - ), - 'M' => array( - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - array(1,0,1,0,0,0,1,0,1), - array(1,0,1,0,0,0,1,0,1), - array(1,0,1,0,0,0,1,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - ), - 'N' => array( - array(1,1,0,0,0,0,0,0,1), - array(1,1,0,0,0,0,0,0,1), - array(1,0,1,0,0,0,0,0,1), - array(1,0,1,0,0,0,0,0,1), - array(1,0,0,1,0,0,0,0,1), - array(1,0,0,1,0,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,0,1,0,0,1), - array(1,0,0,0,0,1,0,0,1), - array(1,0,0,0,0,0,1,0,1), - array(1,0,0,0,0,0,1,0,1), - array(1,0,0,0,0,0,0,1,1), - array(1,0,0,0,0,0,0,1,1), - ), - 'O' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - 'P' => array( - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - ), - 'Q' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,1,0,0,1), - array(1,0,0,0,0,0,1,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,1), - ), - 'R' => array( - array(1,1,1,1,1,1,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,0,0), - array(1,1,1,0,0,0,0,0,0), - array(1,0,0,1,0,0,0,0,0), - array(1,0,0,0,1,0,0,0,0), - array(1,0,0,0,0,1,0,0,0), - array(1,0,0,0,0,0,1,0,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - ), - 'S' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - 'T' => array( - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - ), - 'U' => array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - 'V' => array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - ), - 'W' => array( // New 'W', supplied by MHobbit - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,0,1,0,0,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,0,1,0,1,0,0,1), - array(1,0,1,0,0,0,1,0,1), - array(1,0,1,0,0,0,1,0,1), - array(1,0,1,0,0,0,1,0,1), - array(1,1,0,0,0,0,0,1,1), - array(1,1,0,0,0,0,0,1,1), - ), - 'X' => array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,1,0,0,0,0,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - ), - 'Y' => array( - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,0,0,1,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - ), - 'Z' => array( // New 'Z' supplied by Anon - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,1,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,1), - array(1,1,1,1,1,1,1,1,1), - ), - '1' => array( - array(0,0,0,1,1,0,0,0,0), - array(0,0,1,0,1,0,0,0,0), - array(0,1,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,1,1,1,1,1,1,1,0), - ), - '2' => array( // New '2' supplied by Anon - array(0,0,0,1,1,1,0,0,0), - array(0,0,1,0,0,0,1,0,0), - array(0,1,0,0,0,0,1,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,1,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,0,0), - ), - '3' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,1,1,0,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - '4' => array( - array(0,0,0,0,0,0,1,1,0), - array(0,0,0,0,0,1,0,1,0), - array(0,0,0,0,1,0,0,1,0), - array(0,0,0,1,0,0,0,1,0), - array(0,0,1,0,0,0,0,1,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,1,0), - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - ), - '5' => array( - array(1,1,1,1,1,1,1,1,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,0,1,1,1,1,1,0,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - '6' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,1,1,1,1,0,0), - array(1,0,1,0,0,0,0,1,0), - array(1,1,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - '7' => array( - array(1,1,1,1,1,1,1,1,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,0,1,0), - array(0,0,0,0,0,0,1,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,0,1,0,0,0), - array(0,0,0,0,1,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,0,1,0,0,0,0,0), - array(0,0,1,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(0,1,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - array(1,0,0,0,0,0,0,0,0), - ), - '8' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - '9' => array( - array(0,0,1,1,1,1,1,0,0), - array(0,1,0,0,0,0,0,1,0), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,1,1), - array(0,1,0,0,0,0,1,0,1), - array(0,0,1,1,1,1,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(0,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(1,0,0,0,0,0,0,0,1), - array(0,1,0,0,0,0,0,1,0), - array(0,0,1,1,1,1,1,0,0), - ), - ) - ); -} - - -/** -* Load True Type Fonts -*/ -function captcha_load_ttf_fonts() -{ - static $load_files = array(); - - if (sizeof($load_files) > 0) - { - return $load_files; + // Output image + header('Content-Type: image/png'); + header('Cache-control: no-cache, no-store'); + imagepng($image); + imagedestroy($image); } - global $phpbb_root_path; - - $dr = opendir($phpbb_root_path . 'includes/captcha/fonts'); - while (false !== ($entry = readdir($dr))) + function get_font() { - if (strtolower(pathinfo($entry, PATHINFO_EXTENSION)) == 'ttf') - { - $load_files[$entry] = $phpbb_root_path . 'includes/captcha/fonts/' . $entry; - } - } - closedir($dr); - - return $load_files; -} - - -/** -* Return vectors -*/ -function captcha_vectors() -{ - return array( - 'A' => array( - array('line', 0.00, 0.00, 0.50, 1.00, 1.10714871779, 1.11803398875), - array('line', 1.00, 0.00, 0.50, 1.00, 2.0344439358, 1.11803398875), - array('line', 0.25, 0.50, 0.75, 0.50, 0.00, 0.50), - ), - 'B' => array( - array('line', 0.00, 0.00, 0.00, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 1.00, 0.70, 1.00, 0.00, 0.70), - array('line', 0.00, 0.50, 0.70, 0.50, 0.00, 0.70), - array('line', 0.00, 0.00, 0.70, 0.00, 0.00, 0.70), - array('arc', 0.70, 0.75, 0.60, 0.50, 270, 90), - array('arc', 0.70, 0.25, 0.60, 0.50, 270, 90), - ), - 'C' => array( - array('arc', 0.50, 0.50, 1.00, 1.00, 45, 315), - ), - 'D' => array( - array('line', 0.00, 0.00, 0.00, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 0.00, 0.50, 0.00, 0.00, 0.50), - array('line', 0.00, 1.00, 0.50, 1.00, 0.00, 0.50), - array('arc', 0.50, 0.50, 1.00, 1.00, 270, 90), - ), - 'E' => array( - array('line', 0.00, 0.00, 1.00, 0.00, 0.00, 1.00), - array('line', 0.00, 0.00, 0.00, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 1.00, 1.00, 1.00, 0.00, 1.00), - array('line', 0.00, 0.50, 0.50, 0.50, 0.00, 0.50), - ), - 'F' => array( - array('line', 0.00, 0.00, 0.00, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 1.00, 1.00, 1.00, 0.00, 1.00), - array('line', 0.00, 0.50, 0.50, 0.50, 0.00, 0.50), - ), - 'G' => array( - array('line', 0.50, 0.50, 1.00, 0.50, 0.00, 0.50), - array('line', 1.00, 0.00, 1.00, 0.50, 1.57079632679, 0.50), - array('arc', 0.50, 0.50, 1.00, 1.00, 0, 315), - ), - 'H' => array( - array('line', 0.00, 0.00, 0.00, 1.00, 1.57079632679, 1.00), - array('line', 1.00, 0.00, 1.00, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 0.50, 1.00, 0.50, 0.00, 1.00), - ), - 'I' => array( - array('line', 0.00, 0.00, 1.00, 0.00, 0.00, 1.00), - array('line', 0.00, 1.00, 1.00, 1.00, 0.00, 1.00), - array('line', 0.50, 0.00, 0.50, 1.00, 1.57079632679, 1.00), - ), - 'J' => array( - array('line', 1.00, 1.00, 1.00, 0.25, -1.57079632679, 0.75), - array('arc', 0.50, 0.25, 1.00, 0.50, 0, 180), - ), - 'K' => array( - array('line', 0.00, 0.00, 0.00, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 0.50, 1.00, 1.00, 0.463647609001, 1.11803398875), - array('line', 0.00, 0.50, 1.00, 0.00, -0.463647609001, 1.11803398875), - ), - 'L' => array( - array('line', 0.00, 0.00, 0.00, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 0.00, 1.00, 0.00, 0.00, 1.00), - ), - 'M' => array( - array('line', 0.00, 0.00, 0.00, 1.00, 1.57079632679, 1.00), - array('line', 0.50, 0.50, 0.00, 1.00, 2.35619449019, 0.707106781187), - array('line', 0.50, 0.50, 1.00, 1.00, 0.785398163397, 0.707106781187), - array('line', 1.00, 0.00, 1.00, 1.00, 1.57079632679, 1.00), - ), - 'N' => array( - array('line', 0.00, 0.00, 0.00, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 1.00, 1.00, 0.00, -0.785398163397, 1.41421356237), - array('line', 1.00, 0.00, 1.00, 1.00, 1.57079632679, 1.00), - ), - 'O' => array( - array('arc', 0.50, 0.50, 1.00, 1.00, 0, 360), - ), - 'P' => array( - array('line', 0.00, 0.00, 0.00, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 1.00, 0.70, 1.00, 0.00, 0.70), - array('line', 0.00, 0.50, 0.70, 0.50, 0.00, 0.70), - array('arc', 0.70, 0.75, 0.60, 0.50, 270, 90), - ), - 'Q' => array( - array('line', 0.70, 0.30, 1.00, 0.00, -0.785398163397, 0.424264068712), - array('arc', 0.50, 0.50, 1.00, 1.00, 0, 360), - ), - 'R' => array( - array('line', 0.00, 0.00, 0.00, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 1.00, 0.70, 1.00, 0.00, 0.70), - array('line', 0.00, 0.50, 0.70, 0.50, 0.00, 0.70), - array('line', 0.50, 0.50, 1.00, 0.00, -0.785398163397, 0.707106781187), - array('arc', 0.70, 0.75, 0.60, 0.50, 270, 90), - ), - 'S' => array( - array('arc', 0.50, 0.75, 1.00, 0.50, 90, 360), - array('arc', 0.50, 0.25, 1.00, 0.50, 270, 180), - ), - 'T' => array( - array('line', 0.00, 1.00, 1.00, 1.00, 0.00, 1.00), - array('line', 0.50, 0.00, 0.50, 1.00, 1.57079632679, 1.00), - ), - 'U' => array( - array('line', 0.00, 1.00, 0.00, 0.25, -1.57079632679, 0.75), - array('line', 1.00, 1.00, 1.00, 0.25, -1.57079632679, 0.75), - array('arc', 0.50, 0.25, 1.00, 0.50, 0, 180), - ), - 'V' => array( - array('line', 0.00, 1.00, 0.50, 0.00, -1.10714871779, 1.11803398875), - array('line', 1.00, 1.00, 0.50, 0.00, -2.0344439358, 1.11803398875), - ), - 'W' => array( - array('line', 0.00, 1.00, 0.25, 0.00, -1.32581766367, 1.0307764064), - array('line', 0.50, 0.50, 0.25, 0.00, -2.0344439358, 0.559016994375), - array('line', 0.50, 0.50, 0.75, 0.00, -1.10714871779, 0.559016994375), - array('line', 1.00, 1.00, 0.75, 0.00, -1.81577498992, 1.0307764064), - ), - 'X' => array( - array('line', 0.00, 1.00, 1.00, 0.00, -0.785398163397, 1.41421356237), - array('line', 0.00, 0.00, 1.00, 1.00, 0.785398163397, 1.41421356237), - ), - 'Y' => array( - array('line', 0.00, 1.00, 0.50, 0.50, -0.785398163397, 0.707106781187), - array('line', 1.00, 1.00, 0.50, 0.50, -2.35619449019, 0.707106781187), - array('line', 0.50, 0.50, 0.50, 0.00, -1.57079632679, 0.50), - ), - 'Z' => array( - array('line', 0.00, 1.00, 1.00, 1.00, 0.00, 1.00), - array('line', 0.00, 0.00, 1.00, 1.00, 0.785398163397, 1.41421356237), - array('line', 0.00, 0.00, 1.00, 0.00, 0.00, 1.00), - ), - '1' => array( - array('line', 0.00, 0.75, 0.50, 1.00, 0.463647609001, 0.559016994375), - array('line', 0.50, 0.00, 0.50, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 0.00, 1.00, 0.00, 0.00, 1.00), - ), - '2' => array( - array('line', 0.00, 0.00, 1.00, 0.00, 0.00, 1.00), - array('arc', 0.50, 0.70, 1.00, 0.60, 180, 360), - array('arc', 0.50, 0.70, 1.00, 0.70, 0, 90), - array('arc', 0.50, 0.00, 1.00, 0.70, 180, 270), - ), - '3' => array( - array('arc', 0.50, 0.75, 1.00, 0.50, 180, 90), - array('arc', 0.50, 0.25, 1.00, 0.50, 270, 180), - ), - '4' => array( - array('line', 0.70, 0.00, 0.70, 1.00, 1.57079632679, 1.00), - array('line', 0.00, 0.50, 0.70, 1.00, 0.620249485983, 0.860232526704), - array('line', 0.00, 0.50, 1.00, 0.50, 0.00, 1.00), - ), - '5' => array( - array('line', 0.00, 1.00, 1.00, 1.00, 0.00, 1.00), - array('line', 0.00, 1.00, 0.00, 0.60, -1.57079632679, 0.4), - array('line', 0.00, 0.60, 0.50, 0.60, 0.00, 0.50), - array('arc', 0.50, 0.30, 1.00, 0.60, 270, 180), - ), - '6' => array( - array('arc', 0.50, 0.50, 1.00, 1.00, 90, 315), - array('arc', 0.50, 0.30, 0.80, 0.60, 0, 360), - ), - '7' => array( - array('line', 0.00, 1.00, 1.00, 1.00, 0.00, 1.00), - array('line', 0.50, 0.00, 1.00, 1.00, 1.10714871779, 1.11803398875), - ), - '8' => array( - array('arc', 0.50, 0.75, 1.00, 0.50, 0, 360), - array('arc', 0.50, 0.25, 1.00, 0.50, 0, 360), - ), - '9' => array( - array('arc', 0.50, 0.50, 1.00, 1.00, 270, 135), - array('arc', 0.50, 0.70, 0.80, 0.60, 0, 360), - ) - ); -} - -class color_manager -{ - var $img; - var $mode; - var $colors; - var $named_colors; - var $named_rgb = array( - 'red' => array(0xff, 0x00, 0x00), - 'maroon' => array(0x80, 0x00, 0x00), - 'yellow' => array(0xff, 0xff, 0x00), - 'olive' => array(0x80, 0x80, 0x00), - 'lime' => array(0x00, 0xff, 0x00), - 'green' => array(0x00, 0x80, 0x00), - 'aqua' => array(0x00, 0xff, 0xff), - 'teal' => array(0x00, 0x80, 0x80), - 'blue' => array(0x00, 0x00, 0xff), - 'navy' => array(0x00, 0x00, 0x80), - 'fuchsia' => array(0xff, 0x00, 0xff), - 'purple' => array(0x80, 0x00, 0x80), - 'white' => array(0xff, 0xff, 0xff), - 'silver' => array(0xc0, 0xc0, 0xc0), - 'gray' => array(0x80, 0x80, 0x80), - 'black' => array(0x00, 0x00, 0x00), - ); - - /** - * Create the color manager, link it to - * the image resource - */ - function color_manager($img, $background = false, $mode = 'ahsv') - { - $this->img = $img; - $this->mode = $mode; - $this->colors = array(); - $this->named_colors = array(); - if ($background !== false) - { - $bg = $this->allocate_named('background', $background); - imagefill($this->img, 0, 0, $bg); - } - } + static $fonts = array(); - /** - * Lookup a named color resource - */ - function r($named_color) - { - if (isset($this->named_colors[$named_color])) - { - return $this->named_colors[$named_color]; - } - if (isset($this->named_rgb[$named_color])) + if (!sizeof($fonts)) { - return $this->allocate_named($named_color, $this->named_rgb[$named_color], 'rgb'); - } - return false; - } - - /** - * Assign a name to a color resource - */ - function name_color($name, $resource) - { - $this->named_colors[$name] = $resource; - } + global $phpbb_root_path; - /** - * random color resource - */ - function r_rand($colors) - { - return $colors[array_rand($colors)]; - } - - /** - * names and allocates a color resource - */ - function allocate_named($name, $color, $mode = false) - { - $resource = $this->allocate($color, $mode); - if ($resource !== false) - { - $this->name_color($name, $resource); - } - return $resource; - } - - /** - * allocates a specified color into the image - */ - function allocate($color, $mode = false) - { - if ($mode === false) - { - $mode = $this->mode; - } - if (!is_array($color)) - { - if (isset($this->named_rgb[$color])) + $dr = opendir($phpbb_root_path . 'includes/captcha/fonts'); + while (false !== ($entry = readdir($dr))) { - return $this->allocate_named($color, $this->named_rgb[$color], 'rgb'); - } - if (!is_int($color)) - { - return false; - } - $mode = 'rgb'; - $color = array( - 255 & ($color >> 16), - 255 & ($color >> 8), - 255 & $color, - ); - } - - if (isset($color['mode'])) - { - $mode = $color['mode']; - unset($color['mode']); - } - if (isset($color['random'])) - { - unset($color['random']); - // everything else is params - return $this->random_color($color, $mode); - } - - $rgb = color_manager::model_convert($color, $mode, 'rgb'); - $store = ($this->mode == 'rgb') ? $rgb : color_manager::model_convert($color, $mode, $this->mode); - $resource = imagecolorallocate($this->img, $rgb[0], $rgb[1], $rgb[2]); - - $this->colors[$resource] = $store; - - return $resource; - } - - /** - * randomly generates a color, with optional params - */ - function random_color($params = array(), $mode = false) - { - if ($mode === false) - { - $mode = $this->mode; - } - switch ($mode) - { - case 'rgb': - - // @TODO random rgb generation. do we intend to do this, or is it just too tedious? - - break; - - case 'ahsv': - case 'hsv': - default: - - $default_params = array( - 'hue_bias' => false, // degree / 'r'/'g'/'b'/'c'/'m'/'y' /'o' - 'hue_range' => false, // if hue bias, then difference range +/- from bias - 'min_saturation' => 30, // 0 - 100 - 'max_saturation' => 100, // 0 - 100 - 'min_value' => 30, // 0 - 100 - 'max_value' => 100, // 0 - 100 - ); - - $alt = ($mode == 'ahsv'); - - $params = array_merge($default_params, $params); - - $min_hue = 0; - $max_hue = 359; - $min_saturation = max(0, $params['min_saturation']); - $max_saturation = min(100, $params['max_saturation']); - $min_value = max(0, $params['min_value']); - $max_value = min(100, $params['max_value']); - - if ($params['hue_bias'] !== false) - { - if (is_numeric($params['hue_bias'])) - { - $h = intval($params['hue_bias']) % 360; - } - else - { - switch ($params['hue_bias']) - { - case 'o': - $h = $alt ? 60 : 30; - break; - - case 'y': - $h = $alt ? 120 : 60; - break; - - case 'g': - $h = $alt ? 180 : 120; - break; - - case 'c': - $h = $alt ? 210 : 180; - break; - - case 'b': - $h = 240; - break; - - case 'm': - $h = 300; - break; - - case 'r': - default: - $h = 0; - break; - } - } - - $min_hue = $h + 360; - $max_hue = $h + 360; - - if ($params['hue_range']) - { - $min_hue -= min(180, $params['hue_range']); - $max_hue += min(180, $params['hue_range']); - } - } - - $h = mt_rand($min_hue, $max_hue); - $s = mt_rand($min_saturation, $max_saturation); - $v = mt_rand($min_value, $max_value); - - return $this->allocate(array($h, $s, $v), $mode); - - break; - } - } - - function color_scheme($resource, $scheme, $include_original = true) - { - $mode = (in_array($this->mode, array('hsv', 'ahsv'), true) ? $this->mode : 'hsv'); - if (($pre = $this->r($resource)) !== false) - { - $resource = $pre; - } - $color = color_manager::model_convert($this->colors[$resource], $this->mode, $mode); - $results = $include_original ? array($resource) : array(); - - switch ($scheme) - { - case 'complement': - - $color2 = $color; - $color2[0] += 180; - $results[] = $this->allocate($color2, $mode); - - break; - - case 'triadic': - - $color2 = $color3 = $color; - $color2[0] += 120; - $color3[0] += 240; - $results[] = $this->allocate($color2, $mode); - $results[] = $this->allocate($color3, $mode); - - break; - - case 'tetradic': - - $color2 = $color3 = $color4 = $color; - $color2[0] += 30; - $color3[0] += 180; - $color4[0] += 210; - $results[] = $this->allocate($color2, $mode); - $results[] = $this->allocate($color3, $mode); - $results[] = $this->allocate($color4, $mode); - - break; - - case 'analogous': - - $color2 = $color3 = $color; - $color2[0] += 30; - $color3[0] += 330; - $results[] = $this->allocate($color2, $mode); - $results[] = $this->allocate($color3, $mode); - - break; - } - return $results; - } - - function mono_range($resource, $type = 'both', $count = 5, $include_original = true) - { - if (is_array($resource)) - { - $results = array(); - for ($i = 0, $size = sizeof($resource); $i < $size; ++$i) - { - $results = array_merge($results, $this->mono_range($resource[$i], $type, $count, $include_original)); - } - return $results; - } - $mode = (in_array($this->mode, array('hsv', 'ahsv'), true) ? $this->mode : 'ahsv'); - if (($pre = $this->r($resource)) !== false) - { - $resource = $pre; - } - $color = color_manager::model_convert($this->colors[$resource], $this->mode, $mode); - - $results = array(); - if ($include_original) - { - $results[] = $resource; - $count--; - } - - switch ($type) - { - case 'saturation': - - $pivot = $color[1]; - $num_below = intval(($pivot * $count) / 100); - $num_above = $count - $num_below; - - for ($i = $num_above; $i > 0; --$i) - { - $color[1] = (($i * 100) + (($num_above - $i) * $pivot)) / $num_above; - $results[] = $this->allocate($color, $mode); - } - - ++$num_below; - - for ($i = $num_below - 1; $i > 0; --$i) - { - $color[1] = ($i * $pivot) / $num_below;; - $results[] = $this->allocate($color, $mode); - } - - return $results; - - break; - - case 'value': - - $pivot = $color[2]; - $num_below = intval(($pivot * $count) / 100); - $num_above = $count - $num_below; - - for ($i = $num_above; $i > 0; --$i) - { - $color[2] = (($i * 100) + (($num_above - $i) * $pivot)) / $num_above; - $results[] = $this->allocate($color, $mode); - } - - ++$num_below; - - for ($i = $num_below - 1; $i > 0; --$i) - { - $color[2] = ($i * $pivot) / $num_below;; - $results[] = $this->allocate($color, $mode); - } - - return $results; - - break; - - case 'both': - - // This is a hard problem. I chicken out and do an even triangle - // the problem is that it disregards the original saturation and value, - // and as such a generated result might come arbitrarily close to our original value. - $length = ceil(sqrt($count * 2)); - for ($i = $length; $i > 0; --$i) - { - for ($j = $i; $j > 0; --$j) - { - $color[1] = ($i * 100) / $length; - $color[2] = ($j * 100) / $i; - $results[] = $this->allocate($color, $mode); - --$count; - if (!$count) - { - return $results; - } - } - } - - return $results; - - break; - } - - return false; - } - - function is_dark($resource) - { - $color = (($pre = $this->r($resource)) !== false) ? $this->colors[$pre] : $this->colors[$resource]; - switch($this->mode) - { - case 'ahsv': - case 'hsv': - - return ($color[2] <= 50); - - break; - - case 'rgb': - - return (max($color[0], $color[1], $color[2]) <= 128); - - break; - } - return false; - } - - /** - * Convert from one color model to another - * - * note: properly following coding standards here yields unweildly amounts of whitespace, rendering this less than easily readable - * - */ - function model_convert($color, $from_model, $to_model) - { - if ($from_model == $to_model) - { - return $color; - } - switch ($to_model) - { - case 'hsv': - switch($from_model) - { - case 'ahsv': - return color_manager::ah2h($color); - break; - - case 'rgb': - return color_manager::rgb2hsv($color); - break; - } - break; - - case 'ahsv': - switch($from_model) + if (strtolower(pathinfo($entry, PATHINFO_EXTENSION)) == 'ttf') { - case 'hsv': - return color_manager::h2ah($color); - break; - - case 'rgb': - return color_manager::h2ah(color_manager::rgb2hsv($color)); - break; - } - break; - - case 'rgb': - switch($from_model) - { - case 'hsv': - return color_manager::hsv2rgb($color); - break; - - case 'ahsv': - return color_manager::hsv2rgb(color_manager::ah2h($color)); - break; + $fonts[] = $phpbb_root_path . 'includes/captcha/fonts/' . $entry; } - break; - } - return false; - } - - /** - * Slightly altered from wikipedia's algorithm - */ - function hsv2rgb($hsv) - { - color_manager::normalize_hue($hsv[0]); - $h = $hsv[0]; - $s = min(1, max(0, $hsv[1] / 100)); - $v = min(1, max(0, $hsv[2] / 100)); - - $hi = floor($hsv[0] / 60); // calculate hue sector - - $p = $v * (1 - $s); // calculate opposite color - $f = ($h / 60) - $hi; // calculate distance between hex vertices - if (!($hi & 1)) // coming in or going out? - { - $f = 1 - $f; - } - $q = $v * (1 - ($f * $s)); // calculate adjacent color - - switch ($hi) - { - case 0: - $rgb = array($v, $q, $p); - break; - - case 1: - $rgb = array($q, $v, $p); - break; - - case 2: - $rgb = array($p, $v, $q); - break; - - case 3: - $rgb = array($p, $q, $v); - break; - - case 4: - $rgb = array($q, $p, $v); - break; - - case 5: - $rgb = array($v, $p, $q); - break; - - default: - return array(0, 0, 0); - break; - } - return array(255 * $rgb[0], 255 * $rgb[1], 255 * $rgb[2]); - } - - /** - * (more than) Slightly altered from wikipedia's algorithm - */ - function rgb2hsv($rgb) - { - $r = min(255, max(0, $rgb[0])); - $g = min(255, max(0, $rgb[1])); - $b = min(255, max(0, $rgb[2])); - $max = max($r, $g, $b); - $min = min($r, $g, $b); - - $v = $max / 255; - $s = (!$max) ? 0 : 1 - ($min / $max); - $h = $max - $min; // if max - min is 0, we want hue to be 0 anyway. - if ($h) - { - switch ($max) - { - case $g: - $h = 120 + (60 * ($b - $r) / $h); - break; - - case $b: - $h = 240 + (60 * ($r - $g) / $h); - break; - - case $r: - $h = 360 + (60 * ($g - $b) / $h); - break; } + closedir($dr); } - color_manager::normalize_hue($h); - return array($h, $s * 100, $v * 100); - } - - /** - * Bleh - */ - function normalize_hue(&$hue) - { - $hue %= 360; - if ($hue < 0) - { - $hue += 360; - } - } - - /** - * Alternate hue to hue - */ - function ah2h($ahue) - { - if (is_array($ahue)) - { - $ahue[0] = color_manager::ah2h($ahue[0]); - return $ahue; - } - color_manager::normalize_hue($ahue); - if ($ahue >= 240) // blue through red is already ok - { - return $ahue; - } - if ($ahue >= 180) // ahue green is at 180 - { - // return (240 - (2 * (240 - $ahue))); - return (2 * $ahue) - 240; // equivalent - } - if ($ahue >= 120) // ahue yellow is at 120 (RYB rather than RGB) - { - return $ahue - 60; - } - return $ahue / 2; - } - /** - * hue to Alternate hue - */ - function h2ah($hue) - { - if (is_array($hue)) - { - $hue[0] = color_manager::h2ah($hue[0]); - return $hue; - } - color_manager::normalize_hue($hue); - if ($hue >= 240) // blue through red is already ok - { - return $hue; - } - else if ($hue <= 60) - { - return $hue * 2; - } - else if ($hue <= 120) - { - return $hue + 60; - } - else - { - return ($hue + 240) / 2; - } + return $fonts[array_rand($fonts)]; } } -function vector_distance(&$char, $x, $y, $range = 0.1) -{ - $distance = $range + 1; - foreach ($char AS $vector) - { - $d = $range + 1; - switch ($vector[0]) - { - case 'arc': - - $dx = $x - $vector[1]; - $dy = -($y - $vector[2]); //because our arcs are upside-down.... - if (abs($dx) > abs($dy)) - { - $phi = rad2deg(atan(($dy * $vector[3])/($dx * $vector[4]))); - $phi += ($dx < 0) ? 180 : 360; - $phi %= 360; - } - else - { - $phi = 90 - rad2deg(atan(($dx * $vector[4])/($dy * $vector[3]))); - $phi += ($dy < 0) ? 180 : 360; - $phi %= 360; - } - - $internal = $vector[6] > $vector[5]; //external wraps over the 360 point - $low = $phi >= $vector[5]; //phi is above our low range - $high = $phi <= $vector[6]; //phi is below our high range. - if ($internal ? ($low && $high) : ($low || $high)) //if it wraps, it can only be one or the other - { - $radphi = deg2rad($phi); // i'm awesome. or not. - $px = cos($radphi) * 0.5 * $vector[3]; - $py = sin($radphi) * 0.5 * $vector[4]; - $d = sqrt(pow($px - $dx, 2) + pow($py - $dy, 2)); - } - - break; - - case 'line': - - $bx = $x - $vector[1]; - $by = $y - $vector[2]; - $dx = cos($vector[5]); - $dy = sin($vector[5]); - $r = ($by * $dx) - ($bx * $dy); - if ($r < $range && $r > -$range) - { - if (abs($dx) > abs($dy)) - { - $s = (($bx + ($dy * $r)) / $dx); - } - else - { - $s = (($by + ($dx * $r)) / $dy); - } - if ($s > -$range) - { - if ($s < 0) - { - $d = sqrt(pow($s, 2) + pow($r, 2)); - } - elseif ($s < $vector[6]) - { - $d = $r; - } - elseif ($s < $vector[6] + $range) - { - $d = sqrt(pow($s - $vector[6], 2) + pow($r, 2)); - } - } - } - - break; - } - $distance = min($distance, abs($d)); - } - return $distance; -} ?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/captcha_non_gd.php b/phpBB/includes/captcha/captcha_non_gd.php index e247823a5e..e4ab36f30b 100644 --- a/phpBB/includes/captcha/captcha_non_gd.php +++ b/phpBB/includes/captcha/captcha_non_gd.php @@ -11,6 +11,7 @@ /** * Main non-gd captcha class +* @ignore * @package VC */ class captcha diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index 61016b5b31..652bda40a6 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -27,8 +27,11 @@ define('USER_NORMAL', 0); define('USER_INACTIVE', 1); define('USER_IGNORE', 2); define('USER_FOUNDER', 3); -//define('USER_BOT', 2); -//define('USER_GUEST', 4); + +define('INACTIVE_REGISTER', 1); +define('INACTIVE_PROFILE', 2); +define('INACTIVE_MANUAL', 3); +define('INACTIVE_REMIND', 4); // ACL define('ACL_NEVER', 0); @@ -61,6 +64,19 @@ define('ITEM_UNLOCKED', 0); define('ITEM_LOCKED', 1); define('ITEM_MOVED', 2); +// Forum Flags +define('FORUM_FLAG_LINK_TRACK', 1); +define('FORUM_FLAG_PRUNE_POLL', 2); +define('FORUM_FLAG_PRUNE_ANNOUNCE', 4); +define('FORUM_FLAG_PRUNE_STICKY', 8); +define('FORUM_FLAG_ACTIVE_TOPICS', 16); +define('FORUM_FLAG_POST_REVIEW', 32); + +// Optional text flags +define('OPTION_FLAG_BBCODE', 1); +define('OPTION_FLAG_SMILIES', 2); +define('OPTION_FLAG_LINKS', 4); + // Topic types define('POST_NORMAL', 0); define('POST_STICKY', 1); @@ -114,7 +130,8 @@ define('ATTACHMENT_CATEGORY_IMAGE', 1); // Inline Images define('ATTACHMENT_CATEGORY_WM', 2); // Windows Media Files - Streaming define('ATTACHMENT_CATEGORY_RM', 3); // Real Media Files - Streaming define('ATTACHMENT_CATEGORY_THUMB', 4); // Not used within the database, only while displaying posts -//define('SWF_CAT', 5); // Replaced by [flash]? or an additional possibility? +define('ATTACHMENT_CATEGORY_FLASH', 5); // Flash/SWF files +define('ATTACHMENT_CATEGORY_QUICKTIME', 6); // Quicktime/Mov files // BBCode UID length define('BBCODE_UID_LEN', 5); @@ -130,6 +147,7 @@ define('FIELD_BOOL', 4); define('FIELD_DROPDOWN', 5); define('FIELD_DATE', 6); + // Additional constants @@ -172,7 +190,6 @@ define('PROFILE_FIELDS_DATA_TABLE', $table_prefix . 'profile_fields_data'); define('PROFILE_FIELDS_LANG_TABLE', $table_prefix . 'profile_fields_lang'); define('PROFILE_LANG_TABLE', $table_prefix . 'profile_lang'); define('RANKS_TABLE', $table_prefix . 'ranks'); -define('RATINGS_TABLE', $table_prefix . 'ratings'); define('REPORTS_TABLE', $table_prefix . 'reports'); define('REPORTS_REASONS_TABLE', $table_prefix . 'reports_reasons'); define('SEARCH_RESULTS_TABLE', $table_prefix . 'search_results'); @@ -193,7 +210,6 @@ define('TOPICS_TRACK_TABLE', $table_prefix . 'topics_track'); define('TOPICS_WATCH_TABLE', $table_prefix . 'topics_watch'); define('USER_GROUP_TABLE', $table_prefix . 'user_group'); define('USERS_TABLE', $table_prefix . 'users'); -define('USERS_NOTES_TABLE', $table_prefix . 'users_notes'); define('WARNINGS_TABLE', $table_prefix . 'warnings'); define('WORDS_TABLE', $table_prefix . 'words'); define('ZEBRA_TABLE', $table_prefix . 'zebra'); diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php index f774b5dcc3..d2d3efedaa 100644 --- a/phpBB/includes/db/dbal.php +++ b/phpBB/includes/db/dbal.php @@ -39,6 +39,11 @@ class dbal var $sql_error_sql = ''; /** + * Current sql layer + */ + var $sql_layer = ''; + + /** * Constructor */ function dbal() @@ -48,6 +53,10 @@ class dbal 'normal' => 0, 'total' => 0, ); + + // Fill default sql layer based on the class being called. + // This can be changed by the specified layer itself later if needed. + $this->sql_layer = substr(get_class($this), 5); } /** @@ -110,12 +119,12 @@ class dbal */ function sql_fetchrowset($query_id = false) { - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } - if ($query_id) + if ($query_id !== false) { $result = array(); while ($row = $this->sql_fetchrow($query_id)) @@ -130,8 +139,40 @@ class dbal } /** + * Fetch field + * if rownum is false, the current row is used, else it is pointing to the row (zero-based) + */ + function sql_fetchfield($field, $rownum = false, $query_id = false) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if ($query_id !== false) + { + if ($rownum !== false) + { + $this->sql_rowseek($rownum, $query_id); + } + + if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_fetchfield($query_id, $field); + } + + $row = $this->sql_fetchrow($query_id); + return (isset($row[$field])) ? $row[$field] : false; + } + + return false; + } + + /** * SQL Transaction - * @access: private + * @access private */ function sql_transaction($status = 'begin') { @@ -211,6 +252,12 @@ class dbal $ary = array(); foreach ($assoc_ary as $id => $sql_ary) { + // If by accident the sql array is only one-dimensional we build a normal insert statement + if (!is_array($sql_ary)) + { + return $this->sql_build_array('INSERT', $assoc_ary); + } + $values = array(); foreach ($sql_ary as $key => $var) { @@ -234,27 +281,75 @@ class dbal return $query; } + /** + * Build IN, NOT IN, = and <> sql comparison string. + * @access public + */ function sql_in_set($field, $array, $negate = false) { if (!sizeof($array)) { - trigger_error('No values specified for SQL IN comparison', E_USER_ERROR); + // Not optimal, but at least the backtrace should help in identifying where the problem lies. + $this->sql_error('No values specified for SQL IN comparison'); } - $values = array(); - foreach ($array as $var) + if (!is_array($array)) { - $values[] = $this->_sql_validate_value($var); + $array = array($array); } - if (sizeof($values) == 1) + if (sizeof($array) == 1) { - return $field . ($negate ? ' <> ' : ' = ') . $values[0]; + @reset($array); + $var = current($array); + + return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var); } else { - return $field . ($negate ? ' NOT IN ' : ' IN ' ) . '(' . implode(', ', $values) . ')'; + return $field . ($negate ? ' NOT IN ' : ' IN ' ) . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')'; + } + } + + /** + * Run more than one insert statement. + * + * @param $sql_ary array multi-dimensional array holding the statement data. + * @param $table string table name to run the statements on + * + * @return bool false if no statements were executed. + * @access public + */ + function sql_multi_insert($table, &$sql_ary) + { + if (!sizeof($sql_ary)) + { + return false; } + + switch ($this->sql_layer) + { + case 'mysql': + case 'mysql4': + case 'mysqli': + case 'sqlite': + $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('MULTI_INSERT', $sql_ary)); + break; + + default: + foreach ($sql_ary as $ary) + { + if (!is_array($ary)) + { + return false; + } + + $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); + } + break; + } + + return true; } /** @@ -354,7 +449,7 @@ class dbal if (!$this->return_on_error) { - $message = '<u>SQL ERROR</u> [ ' . SQL_LAYER . ' ]<br /><br />' . $error['message'] . ' [' . $error['code'] . ']'; + $message = '<u>SQL ERROR</u> [ ' . $this->sql_layer . ' ]<br /><br />' . $error['message'] . ' [' . $error['code'] . ']'; // Show complete SQL error and path to administrators only // Additionally show complete error on installation or if extended debug mode is enabled @@ -364,7 +459,7 @@ class dbal // Print out a nice backtrace... $backtrace = get_backtrace(); - $message .= ($sql) ? '<br /><br /><u>SQL</u><br /><br />' . $sql : ''; + $message .= ($sql) ? '<br /><br /><u>SQL</u><br /><br />' . htmlspecialchars($sql) : ''; $message .= ($backtrace) ? '<br /><br /><u>BACKTRACE</u><br />' . $backtrace : ''; $message .= '<br />'; } @@ -409,7 +504,7 @@ class dbal { global $cache, $starttime, $phpbb_root_path, $user; - if (empty($_GET['explain'])) + if (empty($_REQUEST['explain'])) { return false; } @@ -453,7 +548,7 @@ class dbal <br /> <p><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></p> - <p>Time spent on ' . SQL_LAYER . ' queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></p> + <p>Time spent on ' . $this->sql_layer . ' queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></p> <br /><br /> ' . $this->sql_report . ' @@ -504,7 +599,7 @@ class dbal else { $error = $this->sql_error(); - $this->sql_report .= '<b style="color: red">FAILED</b> - ' . SQL_LAYER . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); + $this->sql_report .= '<b style="color: red">FAILED</b> - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']); } $this->sql_report .= '</p><br /><br />'; diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/firebird.php index 7ea5dd3612..7fd034c7dc 100644 --- a/phpBB/includes/db/firebird.php +++ b/phpBB/includes/db/firebird.php @@ -9,24 +9,18 @@ */ /** +* @ignore */ if (!defined('IN_PHPBB')) { exit; } -/** -* @ignore -*/ -if (!defined('SQL_LAYER')) -{ - - define('SQL_LAYER', 'firebird'); - include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); +include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); /** * Firebird/Interbase Database Abstraction Layer -* Minimum Requirement is Firebird 1.5+/Interbase 7.1+ +* Minimum Requirement is Firebird 2.0 * @package dbal */ class dbal_firebird extends dbal @@ -66,7 +60,7 @@ class dbal_firebird extends dbal /** * SQL Transaction - * @access: private + * @access private */ function _sql_transaction($status = 'begin') { @@ -107,7 +101,7 @@ class dbal_firebird extends dbal $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); - if (!$this->query_result) + if ($this->query_result === false) { if (($this->query_result = @ibase_query($this->db_connect_id, $query)) === false) { @@ -122,7 +116,8 @@ class dbal_firebird extends dbal } else { - @ibase_commit(); + // way cooler than ibase_commit_ret :D + @ibase_query('COMMIT RETAIN;'); } } @@ -165,27 +160,6 @@ class dbal_firebird extends dbal } /** - * Return number of rows - * Not used within core code - */ - function sql_numrows($query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_numrows($query_id); - } - - return false; - } - - /** * Return number of affected rows */ function sql_affectedrows() @@ -208,7 +182,7 @@ class dbal_firebird extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -218,6 +192,11 @@ class dbal_firebird extends dbal return $cache->sql_fetchrow($query_id); } + if ($query_id === false) + { + return false; + } + $row = array(); $cur_row = @ibase_fetch_object($query_id, IBASE_TEXT); @@ -228,60 +207,41 @@ class dbal_firebird extends dbal foreach (get_object_vars($cur_row) as $key => $value) { - $row[strtolower($key)] = trim(str_replace("\\0", "\0", str_replace("\\n", "\n", $value))); + $row[strtolower($key)] = trim(str_replace(array("\\0", "\\n"), array("\0", "\n"), $value)); } return (sizeof($row)) ? $row : false; } /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) + * Seek to given row number + * rownum is zero-based */ - function sql_fetchfield($field, $rownum = false, $query_id = false) + function sql_rowseek($rownum, $query_id = false) { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } - if ($query_id) + if (isset($cache->sql_rowset[$query_id])) { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return isset($row[$field]) ? $row[$field] : false; + return $cache->sql_rowseek($rownum, $query_id); } - return false; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, $query_id = false) - { - global $cache; - - if (!$query_id) + if ($query_id === false) { - $query_id = $this->query_result; + return; } - if (isset($cache->sql_rowset[$query_id])) + $this->sql_freeresult($query_id); + $query_id = $this->sql_query($this->last_query_text); + + if ($query_id === false) { - return $cache->sql_rowseek($query_id, $rownum); + return false; } // We do not fetch the row for rownum == 0 because then the next resultset would be the second row @@ -303,7 +263,7 @@ class dbal_firebird extends dbal { $query_id = $this->query_result; - if ($query_id && $this->last_query_text != '') + if ($query_id !== false && $this->last_query_text != '') { if ($this->query_result && preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename)) { @@ -331,7 +291,7 @@ class dbal_firebird extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -355,12 +315,12 @@ class dbal_firebird extends dbal */ function sql_escape($msg) { - return (@ini_get('magic_quotes_sybase') || strtolower(@ini_get('magic_quotes_sybase')) == 'on') ? str_replace('\\\'', '\'', addslashes($msg)) : str_replace('\'', '\'\'', stripslashes($msg)); + return (@ini_get('magic_quotes_sybase') == 1 || strtolower(@ini_get('magic_quotes_sybase')) == 'on') ? str_replace('\\\'', '\'', addslashes($msg)) : str_replace('\'', '\'\'', stripslashes($msg)); } /** * Build db-specific query data - * @access: private + * @access private */ function _sql_custom_build($stage, $data) { @@ -369,7 +329,7 @@ class dbal_firebird extends dbal /** * return sql error array - * @access: private + * @access private */ function _sql_error() { @@ -381,7 +341,7 @@ class dbal_firebird extends dbal /** * Close sql connection - * @access: private + * @access private */ function _sql_close() { @@ -395,7 +355,7 @@ class dbal_firebird extends dbal /** * Build db-specific report - * @access: private + * @access private */ function _sql_report($mode, $query = '') { @@ -423,9 +383,6 @@ class dbal_firebird extends dbal break; } } - } -} // if ... define - ?>
\ No newline at end of file diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/mssql.php index fe6cf75b12..f95f99969c 100644 --- a/phpBB/includes/db/mssql.php +++ b/phpBB/includes/db/mssql.php @@ -9,20 +9,14 @@ */ /** +* @ignore */ if (!defined('IN_PHPBB')) { exit; } -/** -* @ignore -*/ -if (!defined('SQL_LAYER')) -{ - - define('SQL_LAYER', 'mssql'); - include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); +include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); /** * MSSQL Database Abstraction Layer @@ -79,7 +73,7 @@ class dbal_mssql extends dbal /** * SQL Transaction - * @access: private + * @access private */ function _sql_transaction($status = 'begin') { @@ -122,10 +116,13 @@ class dbal_mssql extends dbal $this->sql_report('start', $query); } + // For now, MSSQL has no real UTF-8 support + $query = utf8_decode($query); + $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); - if (!$this->query_result) + if ($this->query_result === false) { if (($this->query_result = @mssql_query($query, $this->db_connect_id)) === false) { @@ -169,30 +166,26 @@ class dbal_mssql extends dbal { $this->query_result = false; - // if $total is set to 0 we do not want to limit the number of rows - if ($total == 0) + // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows) + if ($total) { - $total = -1; - } - - $row_offset = ($total) ? $offset : ''; - $num_rows = ($total) ? $total : $offset; - - if (strpos($query, 'SELECT DISTINCT') === 0) - { - $query = 'SELECT DISTINCT TOP ' . ($row_offset + $num_rows) . ' ' . substr($query, 15); - } - else - { - $query = 'SELECT TOP ' . ($row_offset + $num_rows) . ' ' . substr($query, 6); + // We need to grab the total number of rows + the offset number of rows to get the correct result + if (strpos($query, 'SELECT DISTINCT') === 0) + { + $query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15); + } + else + { + $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6); + } } $result = $this->sql_query($query, $cache_ttl); - // Seek by $row_offset rows - if ($row_offset) + // Seek by $offset rows + if ($offset) { - $this->sql_rowseek($result, $row_offset); + $this->sql_rowseek($offset, $result); } return $result; @@ -204,27 +197,6 @@ class dbal_mssql extends dbal } /** - * Return number of rows - * Not used within core code - */ - function sql_numrows($query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_numrows($query_id); - } - - return ($query_id) ? @mssql_num_rows($query_id) : false; - } - - /** * Return number of affected rows */ function sql_affectedrows() @@ -239,7 +211,7 @@ class dbal_mssql extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -249,6 +221,11 @@ class dbal_mssql extends dbal return $cache->sql_fetchrow($query_id); } + if ($query_id === false) + { + return false; + } + $row = @mssql_fetch_assoc($query_id); // I hope i am able to remove this later... hopefully only a PHP or MSSQL bug @@ -264,38 +241,6 @@ class dbal_mssql extends dbal } /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if ($query_id) - { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return isset($row[$field]) ? $row[$field] : false; - } - - return false; - } - - /** * Seek to given row number * rownum is zero-based */ @@ -303,17 +248,17 @@ class dbal_mssql extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } if (isset($cache->sql_rowset[$query_id])) { - return $cache->sql_rowseek($query_id, $rownum); + return $cache->sql_rowseek($rownum, $query_id); } - return ($query_id) ? @mssql_data_seek($query_id, $rownum) : false; + return ($query_id !== false) ? @mssql_data_seek($query_id, $rownum) : false; } /** @@ -342,7 +287,7 @@ class dbal_mssql extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -371,7 +316,7 @@ class dbal_mssql extends dbal /** * return sql error array - * @access: private + * @access private */ function _sql_error() { @@ -410,7 +355,7 @@ class dbal_mssql extends dbal /** * Build db-specific query data - * @access: private + * @access private */ function _sql_custom_build($stage, $data) { @@ -419,7 +364,7 @@ class dbal_mssql extends dbal /** * Close sql connection - * @access: private + * @access private */ function _sql_close() { @@ -428,7 +373,7 @@ class dbal_mssql extends dbal /** * Build db-specific report - * @access: private + * @access private */ function _sql_report($mode, $query = '') { @@ -486,9 +431,6 @@ class dbal_mssql extends dbal break; } } - } -} // if ... define - ?>
\ No newline at end of file diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php index e1b2675a23..12e3ca686e 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/mssql_odbc.php @@ -9,20 +9,14 @@ */ /** +* @ignore */ if (!defined('IN_PHPBB')) { exit; } -/** -* @ignore -*/ -if (!defined('SQL_LAYER')) -{ - - define('SQL_LAYER', 'mssql_odbc'); - include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); +include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); /** * Unified ODBC functions @@ -73,7 +67,7 @@ class dbal_mssql_odbc extends dbal /** * SQL Transaction - * @access: private + * @access private */ function _sql_transaction($status = 'begin') { @@ -120,11 +114,14 @@ class dbal_mssql_odbc extends dbal $this->sql_report('start', $query); } + // For now, MSSQL has no real UTF-8 support + $query = utf8_decode($query); + $this->last_query_text = $query; $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); - if (!$this->query_result) + if ($this->query_result === false) { if (($this->query_result = @odbc_exec($this->db_connect_id, $query)) === false) { @@ -168,33 +165,26 @@ class dbal_mssql_odbc extends dbal { $this->query_result = false; - // if $total is set to 0 we do not want to limit the number of rows - if ($total == 0) - { - $total = -1; - } - - $row_offset = ($total) ? $offset : 0; - $num_rows = ($total) ? $total : $offset; - - if (strpos($query, 'SELECT DISTINCT') === 0) - { - $query = 'SELECT DISTINCT TOP ' . ($row_offset + $num_rows) . ' ' . substr($query, 15); - } - else + // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows) + if ($total) { - $query = 'SELECT TOP ' . ($row_offset + $num_rows) . ' ' . substr($query, 6); + // We need to grab the total number of rows + the offset number of rows to get the correct result + if (strpos($query, 'SELECT DISTINCT') === 0) + { + $query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15); + } + else + { + $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6); + } } $result = $this->sql_query($query, $cache_ttl); - // Seek by $row_offset rows - if ($row_offset) + // Seek by $offset rows + if ($offset) { - for ($i = 0; $i < $row_offset; $i++) - { - $this->sql_fetchrow($result); - } + $this->sql_rowseek($offset, $result); } return $result; @@ -206,27 +196,6 @@ class dbal_mssql_odbc extends dbal } /** - * Return number of rows - * Not used within core code - */ - function sql_numrows($query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_numrows($query_id); - } - - return ($query_id) ? @odbc_num_rows($query_id) : false; - } - - /** * Return number of affected rows */ function sql_affectedrows() @@ -241,7 +210,7 @@ class dbal_mssql_odbc extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -251,39 +220,7 @@ class dbal_mssql_odbc extends dbal return $cache->sql_fetchrow($query_id); } - return ($query_id) ? @odbc_fetch_array($query_id) : false; - } - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if ($query_id) - { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return isset($row[$field]) ? $row[$field] : false; - } - - return false; + return ($query_id !== false) ? @odbc_fetch_array($query_id) : false; } /** @@ -294,20 +231,25 @@ class dbal_mssql_odbc extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } if (isset($cache->sql_rowset[$query_id])) { - return $cache->sql_rowseek($query_id, $rownum); + return $cache->sql_rowseek($rownum, $query_id); + } + + if ($query_id === false) + { + return false; } $this->sql_freeresult($query_id); $query_id = $this->sql_query($this->last_query_text); - if (!$query_id) + if ($query_id === false) { return false; } @@ -352,7 +294,7 @@ class dbal_mssql_odbc extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -381,7 +323,7 @@ class dbal_mssql_odbc extends dbal /** * Build db-specific query data - * @access: private + * @access private */ function _sql_custom_build($stage, $data) { @@ -390,7 +332,7 @@ class dbal_mssql_odbc extends dbal /** * return sql error array - * @access: private + * @access private */ function _sql_error() { @@ -402,7 +344,7 @@ class dbal_mssql_odbc extends dbal /** * Close sql connection - * @access: private + * @access private */ function _sql_close() { @@ -411,7 +353,7 @@ class dbal_mssql_odbc extends dbal /** * Build db-specific report - * @access: private + * @access private */ function _sql_report($mode, $query = '') { @@ -469,9 +411,6 @@ class dbal_mssql_odbc extends dbal break; } } - } -} // if ... define - ?>
\ No newline at end of file diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index 7e363721a9..89a6e21d70 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -9,31 +9,31 @@ */ /** +* @ignore */ if (!defined('IN_PHPBB')) { exit; } -/** -* @ignore -*/ -if (!defined('SQL_LAYER')) -{ - - define('SQL_LAYER', 'mysql'); - include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); +include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); /** -* MySQL Database Abstraction Layer -* Minimum Requirement is 3.23+/4.0+/4.1+ +* MySQL4 Database Abstraction Layer +* Compatible with: +* MySQL 3.23+ +* MySQL 4.0+ +* MySQL 4.1+ +* MySQL 5.0+ * @package dbal */ class dbal_mysql extends dbal { + var $mysql_version; + /** * Connect to server - * @access: public + * @access public */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false) { @@ -42,12 +42,26 @@ class dbal_mysql extends dbal $this->server = $sqlserver . (($port) ? ':' . $port : ''); $this->dbname = $database; + $this->sql_layer = 'mysql4'; + $this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $sqlpassword) : @mysql_connect($this->server, $this->user, $sqlpassword); if ($this->db_connect_id && $this->dbname != '') { if (@mysql_select_db($this->dbname)) { + // Determine what version we are using and if it natively supports UNICODE + $this->mysql_version = mysql_get_server_info($this->db_connect_id); + + if (version_compare($this->mysql_version, '4.1.3', '>=')) + { + @mysql_query("SET NAMES 'utf8'", $this->db_connect_id); + } + else if (version_compare($this->mysql_version, '4.0.0', '<')) + { + $this->sql_layer = 'mysql'; + } + return $this->db_connect_id; } } @@ -60,12 +74,12 @@ class dbal_mysql extends dbal */ function sql_server_info() { - return 'MySQL ' . @mysql_get_server_info($this->db_connect_id); + return 'MySQL ' . $this->mysql_version; } /** * SQL Transaction - * @access: private + * @access private */ function _sql_transaction($status = 'begin') { @@ -111,7 +125,7 @@ class dbal_mysql extends dbal $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); - if (!$this->query_result) + if ($this->query_result === false) { if (($this->query_result = @mysql_query($query, $this->db_connect_id)) === false) { @@ -158,7 +172,8 @@ class dbal_mysql extends dbal // if $total is set to 0 we do not want to limit the number of rows if ($total == 0) { - $total = -1; + // Having a value of -1 was always a bug + $total = '18446744073709551615'; } $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); @@ -172,27 +187,6 @@ class dbal_mysql extends dbal } /** - * Return number of rows - * Not used within core code - */ - function sql_numrows($query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_numrows($query_id); - } - - return ($query_id) ? @mysql_num_rows($query_id) : false; - } - - /** * Return number of affected rows */ function sql_affectedrows() @@ -207,7 +201,7 @@ class dbal_mysql extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -217,47 +211,7 @@ class dbal_mysql extends dbal return $cache->sql_fetchrow($query_id); } - return ($query_id) ? @mysql_fetch_assoc($query_id) : false; - } - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if ($query_id) - { - if ($rownum === false) - { - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return isset($row[$field]) ? $row[$field] : false; - } - else - { - if (isset($cache->sql_rowset[$query_id])) - { - $cache->sql_rowseek($query_id, $rownum); - return $cache->sql_fetchfield($query_id, $field); - } - - return @mysql_result($query_id, $rownum, $field); - } - } - - return false; + return ($query_id !== false) ? @mysql_fetch_assoc($query_id) : false; } /** @@ -268,17 +222,17 @@ class dbal_mysql extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } if (isset($cache->sql_rowset[$query_id])) { - return $cache->sql_rowseek($query_id, $rownum); + return $cache->sql_rowseek($rownum, $query_id); } - return ($query_id) ? @mysql_data_seek($query_id, $rownum) : false; + return ($query_id !== false) ? @mysql_data_seek($query_id, $rownum) : false; } /** @@ -296,7 +250,7 @@ class dbal_mysql extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -324,13 +278,13 @@ class dbal_mysql extends dbal { return @mysql_real_escape_string($msg); } - + return @mysql_real_escape_string($msg, $this->db_connect_id); } /** * Build db-specific query data - * @access: private + * @access private */ function _sql_custom_build($stage, $data) { @@ -343,10 +297,10 @@ class dbal_mysql extends dbal return $data; } - + /** * return sql error array - * @access: private + * @access private */ function _sql_error() { @@ -366,7 +320,7 @@ class dbal_mysql extends dbal /** * Close sql connection - * @access: private + * @access private */ function _sql_close() { @@ -375,7 +329,7 @@ class dbal_mysql extends dbal /** * Build db-specific report - * @access: private + * @access private */ function _sql_report($mode, $query = '') { @@ -433,9 +387,6 @@ class dbal_mysql extends dbal break; } } - } -} // if ... define - ?>
\ No newline at end of file diff --git a/phpBB/includes/db/mysql4.php b/phpBB/includes/db/mysql4.php deleted file mode 100644 index 071f4c4b55..0000000000 --- a/phpBB/includes/db/mysql4.php +++ /dev/null @@ -1,443 +0,0 @@ -<?php -/** -* -* @package dbal -* @version $Id$ -* @copyright (c) 2005 phpBB Group -* @license http://opensource.org/licenses/gpl-license.php GNU Public License -* -*/ - -/** -*/ -if (!defined('IN_PHPBB')) -{ - exit; -} - -/** -* @ignore -*/ -if (!defined('SQL_LAYER')) -{ - - define('SQL_LAYER', 'mysql4'); - include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - -/** -* MySQL4 Database Abstraction Layer -* Compatible with: -* MySQL 4.0+ -* MySQL 4.1+ -* MySQL 5.0+ -* @package dbal -*/ -class dbal_mysql4 extends dbal -{ - /** - * Connect to server - */ - function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false) - { - $this->persistency = $persistency; - $this->user = $sqluser; - $this->server = $sqlserver . (($port) ? ':' . $port : ''); - $this->dbname = $database; - - $this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $sqlpassword) : @mysql_connect($this->server, $this->user, $sqlpassword); - - if ($this->db_connect_id && $this->dbname != '') - { - if (@mysql_select_db($this->dbname)) - { - return $this->db_connect_id; - } - } - - return $this->sql_error(''); - } - - /** - * Version information about used database - */ - function sql_server_info() - { - return 'MySQL ' . @mysql_get_server_info($this->db_connect_id); - } - - /** - * SQL Transaction - * @access: private - */ - function _sql_transaction($status = 'begin') - { - switch ($status) - { - case 'begin': - return @mysql_query('BEGIN', $this->db_connect_id); - break; - - case 'commit': - return @mysql_query('COMMIT', $this->db_connect_id); - break; - - case 'rollback': - return @mysql_query('ROLLBACK', $this->db_connect_id); - break; - } - - return true; - } - - /** - * Base query method - * - * @param string $query Contains the SQL query which shall be executed - * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache - * @return mixed When casted to bool the returned value returns true on success and false on failure - * - * @access public - */ - function sql_query($query = '', $cache_ttl = 0) - { - if ($query != '') - { - global $cache; - - // EXPLAIN only in extra debug mode - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('start', $query); - } - - $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; - $this->sql_add_num_queries($this->query_result); - - if (!$this->query_result) - { - if (($this->query_result = @mysql_query($query, $this->db_connect_id)) === false) - { - $this->sql_error($query); - } - - if (defined('DEBUG_EXTRA')) - { - $this->sql_report('stop', $query); - } - - if ($cache_ttl && method_exists($cache, 'sql_save')) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - $cache->sql_save($query, $this->query_result, $cache_ttl); - } - else if (strpos($query, 'SELECT') === 0 && $this->query_result) - { - $this->open_queries[(int) $this->query_result] = $this->query_result; - } - } - else if (defined('DEBUG_EXTRA')) - { - $this->sql_report('fromcache', $query); - } - } - else - { - return false; - } - - return ($this->query_result) ? $this->query_result : false; - } - - /** - * Build LIMIT query - */ - function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) - { - if ($query != '') - { - $this->query_result = false; - - // if $total is set to 0 we do not want to limit the number of rows - if ($total == 0) - { - // Because MySQL 4.1+ no longer supports -1 in LIMIT queries we set it to the maximum value - $total = '18446744073709551615'; - } - - $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); - - return $this->sql_query($query, $cache_ttl); - } - else - { - return false; - } - } - - /** - * Return number of rows - * Not used within core code - */ - function sql_numrows($query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_numrows($query_id); - } - - return ($query_id) ? @mysql_num_rows($query_id) : false; - } - - /** - * Return number of affected rows - */ - function sql_affectedrows() - { - return ($this->db_connect_id) ? @mysql_affected_rows($this->db_connect_id) : false; - } - - /** - * Fetch current row - */ - function sql_fetchrow($query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchrow($query_id); - } - - return ($query_id) ? @mysql_fetch_assoc($query_id) : false; - } - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if ($query_id) - { - if ($rownum === false) - { - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return isset($row[$field]) ? $row[$field] : false; - } - else - { - if (isset($cache->sql_rowset[$query_id])) - { - $cache->sql_rowseek($query_id, $rownum); - return $cache->sql_fetchfield($query_id, $field); - } - - return @mysql_result($query_id, $rownum, $field); - } - } - - return false; - } - - /** - * Seek to given row number - * rownum is zero-based - */ - function sql_rowseek($rownum, $query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_rowseek($query_id, $rownum); - } - - return ($query_id) ? @mysql_data_seek($query_id, $rownum) : false; - } - - /** - * Get last inserted id after insert statement - */ - function sql_nextid() - { - return ($this->db_connect_id) ? @mysql_insert_id($this->db_connect_id) : false; - } - - /** - * Free sql result - */ - function sql_freeresult($query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_freeresult($query_id); - } - - if (isset($this->open_queries[(int) $query_id])) - { - unset($this->open_queries[(int) $query_id]); - return @mysql_free_result($query_id); - } - - return false; - } - - /** - * Escape string used in sql query - */ - function sql_escape($msg) - { - if (!$this->db_connect_id) - { - return @mysql_real_escape_string($msg); - } - - return @mysql_real_escape_string($msg, $this->db_connect_id); - } - - /** - * Build db-specific query data - * @access: private - */ - function _sql_custom_build($stage, $data) - { - switch ($stage) - { - case 'FROM': - $data = '(' . $data . ')'; - break; - } - - return $data; - } - - /** - * return sql error array - * @access: private - */ - function _sql_error() - { - if (!$this->db_connect_id) - { - return array( - 'message' => @mysql_error(), - 'code' => @mysql_errno() - ); - } - - return array( - 'message' => @mysql_error($this->db_connect_id), - 'code' => @mysql_errno($this->db_connect_id) - ); - } - - /** - * Close sql connection - * @access: private - */ - function _sql_close() - { - return @mysql_close($this->db_connect_id); - } - - /** - * Build db-specific report - * @access: private - */ - function _sql_report($mode, $query = '') - { - switch ($mode) - { - case 'start': - - $explain_query = $query; - if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) - { - $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; - } - - if (preg_match('/^SELECT/', $explain_query)) - { - $html_table = false; - - if ($result = @mysql_query("EXPLAIN $explain_query", $this->db_connect_id)) - { - while ($row = @mysql_fetch_assoc($result)) - { - $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); - } - } - @mysql_free_result($result); - - if ($html_table) - { - $this->html_hold .= '</table>'; - } - } - - break; - - case 'fromcache': - $endtime = explode(' ', microtime()); - $endtime = $endtime[0] + $endtime[1]; - - $result = @mysql_query($query, $this->db_connect_id); - while ($void = @mysql_fetch_assoc($result)) - { - // Take the time spent on parsing rows into account - } - @mysql_free_result($result); - - $splittime = explode(' ', microtime()); - $splittime = $splittime[0] + $splittime[1]; - - $this->sql_report('record_fromcache', $query, $endtime, $splittime); - - break; - } - } -} - -} // if ... define - -?>
\ No newline at end of file diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php index fa4d3ffdc7..86700744fb 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/mysqli.php @@ -9,20 +9,14 @@ */ /** +* @ignore */ if (!defined('IN_PHPBB')) { exit; } -/** -* @ignore -*/ -if (!defined('SQL_LAYER')) -{ - - define('SQL_LAYER', 'mysqli'); - include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); +include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); /** * MySQLi Database Abstraction Layer @@ -48,10 +42,8 @@ class dbal_mysqli extends dbal if ($this->db_connect_id && $this->dbname != '') { - if (@mysqli_select_db($this->db_connect_id, $this->dbname)) - { - return $this->db_connect_id; - } + @mysqli_query($this->db_connect_id, "SET NAMES 'utf8'"); + return $this->db_connect_id; } return $this->sql_error(''); @@ -67,7 +59,7 @@ class dbal_mysqli extends dbal /** * SQL Transaction - * @access: private + * @access private */ function _sql_transaction($status = 'begin') { @@ -117,7 +109,7 @@ class dbal_mysqli extends dbal $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); - if (!$this->query_result) + if ($this->query_result === false) { if (($this->query_result = @mysqli_query($this->db_connect_id, $query)) === false) { @@ -174,27 +166,6 @@ class dbal_mysqli extends dbal } /** - * Return number of rows - * Not used within core code - */ - function sql_numrows($query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_numrows($query_id); - } - - return ($query_id) ? @mysqli_num_rows($query_id) : false; - } - - /** * Return number of affected rows */ function sql_affectedrows() @@ -209,7 +180,7 @@ class dbal_mysqli extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -219,39 +190,7 @@ class dbal_mysqli extends dbal return $cache->sql_fetchrow($query_id); } - return ($query_id) ? @mysqli_fetch_assoc($query_id) : false; - } - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if ($query_id) - { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return isset($row[$field]) ? $row[$field] : false; - } - - return false; + return ($query_id !== false) ? @mysqli_fetch_assoc($query_id) : false; } /** @@ -262,17 +201,17 @@ class dbal_mysqli extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) { - return $cache->sql_rowseek($query_id, $rownum); + return $cache->sql_rowseek($rownum, $query_id); } - return ($query_id) ? @mysqli_data_seek($query_id, $rownum) : false; + return ($query_id !== false) ? @mysqli_data_seek($query_id, $rownum) : false; } /** @@ -290,7 +229,7 @@ class dbal_mysqli extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -313,7 +252,7 @@ class dbal_mysqli extends dbal /** * Build db-specific query data - * @access: private + * @access private */ function _sql_custom_build($stage, $data) { @@ -329,7 +268,7 @@ class dbal_mysqli extends dbal /** * return sql error array - * @access: private + * @access private */ function _sql_error() { @@ -349,7 +288,7 @@ class dbal_mysqli extends dbal /** * Close sql connection - * @access: private + * @access private */ function _sql_close() { @@ -358,7 +297,7 @@ class dbal_mysqli extends dbal /** * Build db-specific report - * @access: private + * @access private */ function _sql_report($mode, $query = '') { @@ -418,6 +357,4 @@ class dbal_mysqli extends dbal } } -} // if ... define - ?>
\ No newline at end of file diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php index fc5bf6f78e..e8a0ce3605 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/oracle.php @@ -9,20 +9,14 @@ */ /** +* @ignore */ if (!defined('IN_PHPBB')) { exit; } -/** -* @ignore -*/ -if(!defined('SQL_LAYER')) -{ - - define('SQL_LAYER', 'oracle'); - include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); +include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); /** * Oracle Database Abstraction Layer @@ -42,7 +36,7 @@ class dbal_oracle extends dbal $this->server = $sqlserver . (($port) ? ':' . $port : ''); $this->dbname = $database; - $this->db_connect_id = ($this->persistency) ? @ociplogon($this->user, $sqlpassword, $this->server) : @ocinlogon($this->user, $sqlpassword, $this->server); + $this->db_connect_id = ($this->persistency) ? @ociplogon($this->user, $sqlpassword, $this->server, 'UTF8') : @ocinlogon($this->user, $sqlpassword, $this->server, 'UTF8'); return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } @@ -57,7 +51,7 @@ class dbal_oracle extends dbal /** * SQL Transaction - * @access: private + * @access private */ function _sql_transaction($status = 'begin') { @@ -104,7 +98,7 @@ class dbal_oracle extends dbal $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); - if (!$this->query_result) + if ($this->query_result === false) { $in_transaction = false; if (!$this->transaction) @@ -116,7 +110,63 @@ class dbal_oracle extends dbal $in_transaction = true; } + $array = array(); + + // We overcome Oracle's 4000 char limit by binding vars + if (preg_match('/^(INSERT INTO[^(]+)\\(([^()]+)\\) VALUES[^(]+\\(([^()]+)\\)$/', $query, $regs)) + { + if (strlen($regs[3]) > 4000) + { + $cols = explode(', ', $regs[2]); + $vals = explode(', ', $regs[3]); + foreach ($vals as $key => $value) + { + if (strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2 + { + $vals[$key] = ':' . strtoupper($cols[$key]); + $array[$vals[$key]] = substr($value, 1, -1); + } + } + $query = $regs[1] . '(' . implode(', ', $cols) . ') VALUES (' . implode(', ', $vals) . ')'; + } + } + else if (preg_match('/^(UPDATE.*?)SET (.*)(\\sWHERE.*)$/s', $query, $regs)) + { + if (strlen($regs[2]) > 4000) + { + $args = explode(', ', $regs[2]); + $cols = array(); + foreach ($args as $value) + { + $temp_array = explode('=', $value); + $cols[$temp_array[0]] = $temp_array[1]; + } + + foreach ($cols as $col => $val) + { + if (strlen($val) > 4003) // check to see if this thing is greater than the max + 'x2 + a space + { + $cols[$col] = ' :' . strtoupper(rtrim($col)); + $array[ltrim($cols[$col])] = substr(trim($val), 2, -1); + } + } + + $art = array(); + foreach ($cols as $col => $val) + { + $art[] = $col . '=' . $val; + } + $query = $regs[1] . 'SET ' . implode(', ', $art) . $regs[3]; + } + } + $this->query_result = @ociparse($this->db_connect_id, $query); + + foreach ($array as $key => $value) + { + @ocibindbyname($this->query_result, $key, $array[$key], -1); + } + $success = @ociexecute($this->query_result, OCI_DEFAULT); if (!$success) @@ -226,33 +276,6 @@ class dbal_oracle extends dbal } /** - * Return number of rows - * Not used within core code - */ - function sql_numrows($query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_numrows($query_id); - } - - $result = @ocifetchstatement($query_id, $this->rowset); - - // OCIFetchStatment kills our query result so we have to execute the statment again - // if we ever want to use the query_id again. - @ociexecute($query_id, OCI_DEFAULT); - - return $result; - } - - /** * Return number of affected rows */ function sql_affectedrows() @@ -267,7 +290,7 @@ class dbal_oracle extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -277,56 +300,29 @@ class dbal_oracle extends dbal return $cache->sql_fetchrow($query_id); } - $row = array(); - $result = @ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS); - - if (!$result || !$row) - { - return false; - } - - $result_row = array(); - foreach ($row as $key => $value) - { - // OCI->CLOB? - if (is_object($value)) - { - $value = $value->load(); - } - - $result_row[strtolower($key)] = $value; - } - - return ($query_id) ? $result_row : false; - } - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if (!$query_id) + if ($query_id !== false) { - $query_id = $this->query_result; - } + $row = array(); + $result = @ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS); - if ($query_id) - { - if ($rownum !== false) + if (!$result || !$row) { - $this->sql_rowseek($rownum, $query_id); + return false; } - if (isset($cache->sql_rowset[$query_id])) + $result_row = array(); + foreach ($row as $key => $value) { - return $cache->sql_fetchfield($query_id, $field); + // OCI->CLOB? + if (is_object($value)) + { + $value = $value->load(); + } + + $result_row[strtolower($key)] = $value; } - $row = $this->sql_fetchrow($query_id); - return isset($row[$field]) ? $row[$field] : false; + return $result_row; } return false; @@ -340,17 +336,17 @@ class dbal_oracle extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } if (isset($cache->sql_rowset[$query_id])) { - return $cache->sql_rowseek($query_id, $rownum); + return $cache->sql_rowseek($rownum, $query_id); } - if (!$query_id) + if ($query_id === false) { return false; } @@ -377,13 +373,13 @@ class dbal_oracle extends dbal { $query_id = $this->query_result; - if ($query_id && $this->last_query_text != '') + if ($query_id !== false && $this->last_query_text != '') { if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename)) { $query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL'; $stmt = @ociparse($this->db_connect_id, $query); - @ociexecute($stmt, OCI_DEFAULT ); + @ociexecute($stmt, OCI_DEFAULT); $temp_result = @ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS); @ocifreestatement($stmt); @@ -409,7 +405,7 @@ class dbal_oracle extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -443,7 +439,7 @@ class dbal_oracle extends dbal /** * return sql error array - * @access: private + * @access private */ function _sql_error() { @@ -465,7 +461,7 @@ class dbal_oracle extends dbal /** * Close sql connection - * @access: private + * @access private */ function _sql_close() { @@ -474,7 +470,7 @@ class dbal_oracle extends dbal /** * Build db-specific report - * @access: private + * @access private */ function _sql_report($mode, $query = '') { @@ -505,10 +501,6 @@ class dbal_oracle extends dbal break; } } - - } -} // if ... define - ?>
\ No newline at end of file diff --git a/phpBB/includes/db/postgres.php b/phpBB/includes/db/postgres.php index 1836952346..c06786a795 100644 --- a/phpBB/includes/db/postgres.php +++ b/phpBB/includes/db/postgres.php @@ -9,20 +9,14 @@ */ /** +* @ignore */ if (!defined('IN_PHPBB')) { exit; } -/** -* @ignore -*/ -if (!defined('SQL_LAYER')) -{ - - define('SQL_LAYER', 'postgres'); - include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); +include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); /** * PostgreSQL Database Abstraction Layer @@ -38,48 +32,45 @@ class dbal_postgres extends dbal */ function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false) { - $this->connect_string = ''; + $connect_string = ''; if ($sqluser) { - $this->connect_string .= "user=$sqluser "; + $connect_string .= "user=$sqluser "; } if ($sqlpassword) { - $this->connect_string .= "password=$sqlpassword "; + $connect_string .= "password=$sqlpassword "; } if ($sqlserver) { if (strpos($sqlserver, ':') !== false) { - list($sqlserver, $sqlport) = explode(':', $sqlserver); - $this->connect_string .= "host=$sqlserver port=$sqlport "; + list($sqlserver, $port) = explode(':', $sqlserver); } - else + + if ($sqlserver !== 'localhost') { - if ($sqlserver != "localhost") - { - $this->connect_string .= "host=$sqlserver "; - } - - if ($port) - { - $this->connect_string .= "port=$port "; - } + $connect_string .= "host=$sqlserver "; + } + + if ($port) + { + $connect_string .= "port=$port "; } } if ($database) { $this->dbname = $database; - $this->connect_string .= "dbname=$database"; + $connect_string .= "dbname=$database"; } $this->persistency = $persistency; - $this->db_connect_id = ($this->persistency) ? @pg_pconnect($this->connect_string) : @pg_connect($this->connect_string); + $this->db_connect_id = ($this->persistency) ? @pg_pconnect($connect_string) : @pg_connect($connect_string); return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); } @@ -98,6 +89,8 @@ class dbal_postgres extends dbal { $query_id = @pg_query($this->db_connect_id, 'select version()'); $row = @pg_fetch_assoc($query_id, null); + @pg_free_result($query_id); + $version = $row['version']; return ((!empty($version)) ? ' ' . $version : ''); } @@ -105,7 +98,7 @@ class dbal_postgres extends dbal /** * SQL Transaction - * @access: private + * @access private */ function _sql_transaction($status = 'begin') { @@ -152,7 +145,7 @@ class dbal_postgres extends dbal $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); - if (!$this->query_result) + if ($this->query_result === false) { if (($this->query_result = @pg_query($this->db_connect_id, $query)) === false) { @@ -189,7 +182,7 @@ class dbal_postgres extends dbal /** * Build db-specific query data - * @access: private + * @access private */ function _sql_custom_build($stage, $data) { @@ -222,27 +215,6 @@ class dbal_postgres extends dbal } /** - * Return number of rows - * Not used within core code - */ - function sql_numrows($query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_numrows($query_id); - } - - return ($query_id) ? @pg_num_rows($query_id) : false; - } - - /** * Return number of affected rows */ function sql_affectedrows() @@ -257,7 +229,7 @@ class dbal_postgres extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -267,48 +239,7 @@ class dbal_postgres extends dbal return $cache->sql_fetchrow($query_id); } - $row = @pg_fetch_assoc($query_id, null); - if ($row) - { - foreach ($row as $key => $value) - { - $row[$key] = (strpos($key, 'bitfield') === false) ? $value : pg_unescape_bytea($value); - } - } - - return ($query_id) ? $row : false; - } - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if ($query_id) - { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchfield($query_id, $field); - } - - $row = $this->sql_fetchrow($query_id); - return isset($row[$field]) ? $row[$field] : false; - } - - return false; + return ($query_id !== false) ? @pg_fetch_assoc($query_id, null) : false; } /** @@ -319,17 +250,17 @@ class dbal_postgres extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } if (isset($cache->sql_rowset[$query_id])) { - return $cache->sql_rowseek($query_id, $rownum); + return $cache->sql_rowseek($rownum, $query_id); } - return ($query_id) ? @pg_result_seek($query_id, $rownum) : false; + return ($query_id !== false) ? @pg_result_seek($query_id, $rownum) : false; } /** @@ -339,7 +270,7 @@ class dbal_postgres extends dbal { $query_id = $this->query_result; - if ($query_id && $this->last_query_text != '') + if ($query_id !== false && $this->last_query_text != '') { if (preg_match("/^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)/is", $this->last_query_text, $tablename)) { @@ -368,7 +299,7 @@ class dbal_postgres extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -398,7 +329,7 @@ class dbal_postgres extends dbal /** * return sql error array - * @access: private + * @access private */ function _sql_error() { @@ -410,7 +341,7 @@ class dbal_postgres extends dbal /** * Close sql connection - * @access: private + * @access private */ function _sql_close() { @@ -419,7 +350,7 @@ class dbal_postgres extends dbal /** * Build db-specific report - * @access: private + * @access private */ function _sql_report($mode, $query = '') { @@ -477,9 +408,6 @@ class dbal_postgres extends dbal break; } } - } -} // if ... defined - ?>
\ No newline at end of file diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php index cd6d40e3c7..708376881c 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/sqlite.php @@ -9,20 +9,14 @@ */ /** +* @ignore */ if (!defined('IN_PHPBB')) { exit; } -/** -* @ignore -*/ -if (!defined('SQL_LAYER')) -{ - - define('SQL_LAYER', 'sqlite'); - include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); +include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); /** * Sqlite Database Abstraction Layer @@ -63,7 +57,7 @@ class dbal_sqlite extends dbal /** * SQL Transaction - * @access: private + * @access private */ function _sql_transaction($status = 'begin') { @@ -109,7 +103,7 @@ class dbal_sqlite extends dbal $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; $this->sql_add_num_queries($this->query_result); - if (!$this->query_result) + if ($this->query_result === false) { if (($this->query_result = @sqlite_query($query, $this->db_connect_id)) === false) { @@ -170,27 +164,6 @@ class dbal_sqlite extends dbal } /** - * Return number of rows - * Not used within core code - */ - function sql_numrows($query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_numrows($query_id); - } - - return ($query_id) ? @sqlite_num_rows($query_id) : false; - } - - /** * Return number of affected rows */ function sql_affectedrows() @@ -205,7 +178,7 @@ class dbal_sqlite extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -215,40 +188,7 @@ class dbal_sqlite extends dbal return $cache->sql_fetchrow($query_id); } - $row = @sqlite_fetch_array($query_id, SQLITE_ASSOC); - - return $row; - } - - /** - * Fetch field - * if rownum is false, the current row is used, else it is pointing to the row (zero-based) - */ - function sql_fetchfield($field, $rownum = false, $query_id = false) - { - global $cache; - - if (!$query_id) - { - $query_id = $this->query_result; - } - - if ($query_id) - { - if ($rownum !== false) - { - $this->sql_rowseek($rownum, $query_id); - } - - if (isset($cache->sql_rowset[$query_id])) - { - return $cache->sql_fetchfield($query_id, $field); - } - - return @sqlite_column($query_id, $field); - } - - return false; + return ($query_id !== false) ? @sqlite_fetch_array($query_id, SQLITE_ASSOC) : false; } /** @@ -259,17 +199,17 @@ class dbal_sqlite extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } if (isset($cache->sql_rowset[$query_id])) { - return $cache->sql_rowseek($query_id, $rownum); + return $cache->sql_rowseek($rownum, $query_id); } - return ($query_id) ? @sqlite_seek($query_id, $rownum) : false; + return ($query_id !== false) ? @sqlite_seek($query_id, $rownum) : false; } /** @@ -287,7 +227,7 @@ class dbal_sqlite extends dbal { global $cache; - if (!$query_id) + if ($query_id === false) { $query_id = $this->query_result; } @@ -310,7 +250,7 @@ class dbal_sqlite extends dbal /** * return sql error array - * @access: private + * @access private */ function _sql_error() { @@ -322,7 +262,7 @@ class dbal_sqlite extends dbal /** * Build db-specific query data - * @access: private + * @access private */ function _sql_custom_build($stage, $data) { @@ -331,7 +271,7 @@ class dbal_sqlite extends dbal /** * Close sql connection - * @access: private + * @access private */ function _sql_close() { @@ -340,7 +280,7 @@ class dbal_sqlite extends dbal /** * Build db-specific report - * @access: private + * @access private */ function _sql_report($mode, $query = '') { @@ -367,9 +307,6 @@ class dbal_sqlite extends dbal break; } } - } -} // if ... define - ?>
\ No newline at end of file diff --git a/phpBB/includes/diff/diff.php b/phpBB/includes/diff/diff.php new file mode 100644 index 0000000000..fd2d557a19 --- /dev/null +++ b/phpBB/includes/diff/diff.php @@ -0,0 +1,781 @@ +<?php +/** +* +* @package phpBB3 +* @version $Id$ +* @copyright (c) 2006 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +// Include renderer and engine +include_once($phpbb_root_path . 'includes/diff/engine.' . $phpEx); +include_once($phpbb_root_path . 'includes/diff/renderer.' . $phpEx); + +/** +* Code from pear.php.net, Text_Diff-0.2.1 (beta) package +* http://pear.php.net/package/Text_Diff/ +* +* Modified by Acyd Burn to meet our coding standards +* and being able to integrate into phpBB +*/ + +/** +* General API for generating and formatting diffs - the differences between +* two sequences of strings. +* +* The PHP diff code used in this package was originally written by Geoffrey +* T. Dairiki and is used with his permission. +* +* @package phpBB3 +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +*/ +class diff +{ + /** + * Array of changes. + * @var array + */ + var $_edits; + + /** + * Computes diffs between sequences of strings. + * + * @param array $from_lines An array of strings. Typically these are lines from a file. + * @param array $to_lines An array of strings. + */ + function diff($from_lines, $to_lines) + { + $diff_engine = &new diff_engine(); + $this->_edits = call_user_func_array(array($diff_engine, 'diff'), array($from_lines, $to_lines)); + } + + /** + * Returns the array of differences. + */ + function get_diff() + { + return $this->_edits; + } + + /** + * Computes a reversed diff. + * + * Example: + * <code> + * $diff = &new diff($lines1, $lines2); + * $rev = $diff->reverse(); + * </code> + * + * @return diff A Diff object representing the inverse of the original diff. + * Note that we purposely don't return a reference here, since + * this essentially is a clone() method. + */ + function reverse() + { + if (version_compare(zend_version(), '2', '>')) + { + $rev = clone($this); + } + else + { + $rev = $this; + } + + $rev->_edits = array(); + + foreach ($this->_edits as $edit) + { + $rev->_edits[] = $edit->reverse(); + } + + return $rev; + } + + /** + * Checks for an empty diff. + * + * @return boolean True if two sequences were identical. + */ + function is_empty() + { + foreach ($this->_edits as $edit) + { + if (!is_a($edit, 'diff_op_copy')) + { + return false; + } + } + return true; + } + + /** + * Computes the length of the Longest Common Subsequence (LCS). + * + * This is mostly for diagnostic purposes. + * + * @return integer The length of the LCS. + */ + function lcs() + { + $lcs = 0; + + foreach ($this->_edits as $edit) + { + if (is_a($edit, 'diff_op_copy')) + { + $lcs += sizeof($edit->orig); + } + } + return $lcs; + } + + /** + * Gets the original set of lines. + * + * This reconstructs the $from_lines parameter passed to the constructor. + * + * @return array The original sequence of strings. + */ + function get_original() + { + $lines = array(); + + foreach ($this->_edits as $edit) + { + if ($edit->orig) + { + array_splice($lines, sizeof($lines), 0, $edit->orig); + } + } + return $lines; + } + + /** + * Gets the final set of lines. + * + * This reconstructs the $to_lines parameter passed to the constructor. + * + * @return array The sequence of strings. + */ + function get_final() + { + $lines = array(); + + foreach ($this->_edits as $edit) + { + if ($edit->final) + { + array_splice($lines, sizeof($lines), 0, $edit->final); + } + } + return $lines; + } + + /** + * Removes trailing newlines from a line of text. This is meant to be used with array_walk(). + * + * @param string $line The line to trim. + * @param integer $key The index of the line in the array. Not used. + */ + function trim_newlines(&$line, $key) + { + $line = str_replace(array("\n", "\r"), '', $line); + } + + /** + * Checks a diff for validity. + * + * This is here only for debugging purposes. + */ + function _check($from_lines, $to_lines) + { + if (serialize($from_lines) != serialize($this->get_original())) + { + trigger_error("[diff] Reconstructed original doesn't match", E_USER_ERROR); + } + + if (serialize($to_lines) != serialize($this->get_final())) + { + trigger_error("[diff] Reconstructed final doesn't match", E_USER_ERROR); + } + + $rev = $this->reverse(); + + if (serialize($to_lines) != serialize($rev->get_original())) + { + trigger_error("[diff] Reversed original doesn't match", E_USER_ERROR); + } + + if (serialize($from_lines) != serialize($rev->get_final())) + { + trigger_error("[diff] Reversed final doesn't match", E_USER_ERROR); + } + + $prevtype = null; + + foreach ($this->_edits as $edit) + { + if ($prevtype == get_class($edit)) + { + trigger_error("[diff] Edit sequence is non-optimal", E_USER_ERROR); + } + $prevtype = get_class($edit); + } + + return true; + } +} + +/** +* @package phpBB3 +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +*/ +class mapped_diff extends diff +{ + /** + * Computes a diff between sequences of strings. + * + * This can be used to compute things like case-insensitve diffs, or diffs + * which ignore changes in white-space. + * + * @param array $from_lines An array of strings. + * @param array $to_lines An array of strings. + * @param array $mapped_from_lines This array should have the same size number of elements as $from_lines. + * The elements in $mapped_from_lines and $mapped_to_lines are what is actually + * compared when computing the diff. + * @param array $mapped_to_lines This array should have the same number of elements as $to_lines. + */ + function mapped_diff($from_lines, $to_lines, $mapped_from_lines, $mapped_to_lines) + { + if (sizeof($from_lines) != sizeof($mapped_from_lines) || sizeof($to_lines) != sizeof($mapped_to_lines)) + { + return false; + } + + parent::diff($mapped_from_lines, $mapped_to_lines); + + $xi = $yi = 0; + for ($i = 0; $i < sizeof($this->_edits); $i++) + { + $orig = &$this->_edits[$i]->orig; + if (is_array($orig)) + { + $orig = array_slice($from_lines, $xi, sizeof($orig)); + $xi += sizeof($orig); + } + + $final = &$this->_edits[$i]->final; + if (is_array($final)) + { + $final = array_slice($to_lines, $yi, sizeof($final)); + $yi += sizeof($final); + } + } + } +} + +/** +* @package phpBB3 +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +* +* @access private +*/ +class diff_op +{ + var $orig; + var $final; + + function reverse() + { + trigger_error('[diff] Abstract method', E_USER_ERROR); + } + + function norig() + { + return ($this->orig) ? sizeof($this->orig) : 0; + } + + function nfinal() + { + return ($this->final) ? sizeof($this->final) : 0; + } +} + +/** +* @package phpBB3 +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +* +* @access private +*/ +class diff_op_copy extends diff_op +{ + function diff_op_copy($orig, $final = false) + { + if (!is_array($final)) + { + $final = $orig; + } + $this->orig = $orig; + $this->final = $final; + } + + function &reverse() + { + $reverse = &new diff_op_copy($this->final, $this->orig); + return $reverse; + } +} + +/** +* @package phpBB3 +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +* +* @access private +*/ +class diff_op_delete extends diff_op +{ + function diff_op_delete($lines) + { + $this->orig = $lines; + $this->final = false; + } + + function &reverse() + { + $reverse = &new diff_op_add($this->orig); + return $reverse; + } +} + +/** +* @package phpBB3 +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +* +* @access private +*/ +class diff_op_add extends diff_op +{ + function diff_op_add($lines) + { + $this->final = $lines; + $this->orig = false; + } + + function &reverse() + { + $reverse = &new diff_op_delete($this->final); + return $reverse; + } +} + +/** +* @package phpBB3 +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +* +* @access private +*/ +class diff_op_change extends diff_op +{ + function diff_op_change($orig, $final) + { + $this->orig = $orig; + $this->final = $final; + } + + function &reverse() + { + $reverse = &new diff_op_change($this->final, $this->orig); + return $reverse; + } +} + + +/** +* A class for computing three way diffs. +* +* @package phpBB3 +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +*/ +class diff3 extends diff +{ + /** + * Conflict counter. + * @var integer + */ + var $_conflicting_blocks = 0; + + /** + * Computes diff between 3 sequences of strings. + * + * @param array $orig The original lines to use. + * @param array $final1 The first version to compare to. + * @param array $final2 The second version to compare to. + */ + function diff3($orig, $final1, $final2) + { + $engine = new diff_engine(); + $this->_edits = $this->_diff3($engine->diff($orig, $final1), $engine->diff($orig, $final2)); + } + + /** + * Return merged output + * + * @param string $label1 the cvs file version/label from the original set of lines + * @param string $label2 the cvs file version/label from the new set of lines + * @param string $label_sep the explanation between label1 and label2 - more of a helper for the user + * @param bool $get_conflicts if set to true only the number of conflicts is returned + * @param bool $merge_new if set to true the merged output will have the new file contents on a conflicting merge + * + * @return mixed the merged output + */ + function merged_output($label1 = 'CURRENT_FILE', $label2 = 'NEW_FILE', $label_sep = 'DIFF_SEP_EXPLAIN', $get_conflicts = false, $merge_new = false) + { + global $user; + + if ($get_conflicts) + { + foreach ($this->_edits as $edit) + { + if ($edit->is_conflict()) + { + $this->_conflicting_blocks++; + } + } + + return $this->_conflicting_blocks; + } + + $label1 = (!empty($user->lang[$label1])) ? $user->lang[$label1] : $label1; + $label2 = (!empty($user->lang[$label2])) ? $user->lang[$label2] : $label2; + $label_sep = (!empty($user->lang[$label_sep])) ? $user->lang[$label_sep] : $label_sep; + + $lines = array(); + + foreach ($this->_edits as $edit) + { + if ($edit->is_conflict()) + { + if (!$merge_new) + { + $lines = array_merge($lines, array('<<<<<<<' . ($label1 ? ' ' . $label1 : '')), $edit->final1, array('=======' . ($label_sep ? ' ' . $label_sep : '')), $edit->final2, array('>>>>>>>' . ($label2 ? ' ' . $label2 : ''))); + } + else + { + $lines = array_merge($lines, $edit->final1); + } + $this->_conflicting_blocks++; + } + else + { + $lines = array_merge($lines, $edit->merged()); + } + } + + return $lines; + } + + /** + * Merge the output and use the new file code for conflicts + */ + function merged_new_output() + { + $lines = array(); + + foreach ($this->_edits as $edit) + { + if ($edit->is_conflict()) + { + $lines = array_merge($lines, $edit->final2); + } + else + { + $lines = array_merge($lines, $edit->merged()); + } + } + + return $lines; + } + + /** + * Merge the output and use the original file code for conflicts + */ + function merged_orig_output() + { + $lines = array(); + + foreach ($this->_edits as $edit) + { + if ($edit->is_conflict()) + { + $lines = array_merge($lines, $edit->final1); + } + else + { + $lines = array_merge($lines, $edit->merged()); + } + } + + return $lines; + } + + /** + * Get conflicting block(s) + */ + function get_conflicts() + { + $conflicts = array(); + + foreach ($this->_edits as $edit) + { + if ($edit->is_conflict()) + { + $conflicts[] = array($edit->final1, $edit->final2); + } + } + + return $conflicts; + } + + /** + * @access private + */ + function _diff3($edits1, $edits2) + { + $edits = array(); + $bb = &new diff3_block_builder(); + + $e1 = current($edits1); + $e2 = current($edits2); + + while ($e1 || $e2) + { + if ($e1 && $e2 && is_a($e1, 'diff_op_copy') && is_a($e2, 'diff_op_copy')) + { + // We have copy blocks from both diffs. This is the (only) time we want to emit a diff3 copy block. + // Flush current diff3 diff block, if any. + if ($edit = $bb->finish()) + { + $edits[] = $edit; + } + + $ncopy = min($e1->norig(), $e2->norig()); + $edits[] = &new diff3_op_copy(array_slice($e1->orig, 0, $ncopy)); + + if ($e1->norig() > $ncopy) + { + array_splice($e1->orig, 0, $ncopy); + array_splice($e1->final, 0, $ncopy); + } + else + { + $e1 = next($edits1); + } + + if ($e2->norig() > $ncopy) + { + array_splice($e2->orig, 0, $ncopy); + array_splice($e2->final, 0, $ncopy); + } + else + { + $e2 = next($edits2); + } + } + else + { + if ($e1 && $e2) + { + if ($e1->orig && $e2->orig) + { + $norig = min($e1->norig(), $e2->norig()); + $orig = array_splice($e1->orig, 0, $norig); + array_splice($e2->orig, 0, $norig); + $bb->input($orig); + } + else + { + $norig = 0; + } + + if (is_a($e1, 'diff_op_copy')) + { + $bb->out1(array_splice($e1->final, 0, $norig)); + } + + if (is_a($e2, 'diff_op_copy')) + { + $bb->out2(array_splice($e2->final, 0, $norig)); + } + } + + if ($e1 && ! $e1->orig) + { + $bb->out1($e1->final); + $e1 = next($edits1); + } + + if ($e2 && ! $e2->orig) + { + $bb->out2($e2->final); + $e2 = next($edits2); + } + } + } + + if ($edit = $bb->finish()) + { + $edits[] = $edit; + } + + return $edits; + } +} + +/** +* @package phpBB3 +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +* +* @access private +*/ +class diff3_op +{ + function diff3_op($orig = false, $final1 = false, $final2 = false) + { + $this->orig = $orig ? $orig : array(); + $this->final1 = $final1 ? $final1 : array(); + $this->final2 = $final2 ? $final2 : array(); + } + + function merged() + { + if (!isset($this->_merged)) + { + if ($this->final1 === $this->final2) + { + $this->_merged = &$this->final1; + } + else if ($this->final1 === $this->orig) + { + $this->_merged = &$this->final2; + } + else if ($this->final2 === $this->orig) + { + $this->_merged = &$this->final1; + } + else + { + $this->_merged = false; + } + } + + return $this->_merged; + } + + function is_conflict() + { + return ($this->merged() === false) ? true : false; + } +} + +/** +* @package phpBB3 +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +* +* @access private +*/ +class diff3_op_copy extends diff3_op +{ + function diff3_op_copy($lines = false) + { + $this->orig = $lines ? $lines : array(); + $this->final1 = &$this->orig; + $this->final2 = &$this->orig; + } + + function merged() + { + return $this->orig; + } + + function is_conflict() + { + return false; + } +} + +/** +* @package phpBB3 +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +* +* @access private +*/ +class diff3_block_builder +{ + function diff3_block_builder() + { + $this->_init(); + } + + function input($lines) + { + if ($lines) + { + $this->_append($this->orig, $lines); + } + } + + function out1($lines) + { + if ($lines) + { + $this->_append($this->final1, $lines); + } + } + + function out2($lines) + { + if ($lines) + { + $this->_append($this->final2, $lines); + } + } + + function is_empty() + { + return !$this->orig && !$this->final1 && !$this->final2; + } + + function finish() + { + if ($this->is_empty()) + { + return false; + } + else + { + $edit = &new diff3_op($this->orig, $this->final1, $this->final2); + $this->_init(); + return $edit; + } + } + + function _init() + { + $this->orig = $this->final1 = $this->final2 = array(); + } + + function _append(&$array, $lines) + { + array_splice($array, sizeof($array), 0, $lines); + } +} + +?>
\ No newline at end of file diff --git a/phpBB/includes/diff/engine.php b/phpBB/includes/diff/engine.php new file mode 100644 index 0000000000..c230d865cd --- /dev/null +++ b/phpBB/includes/diff/engine.php @@ -0,0 +1,512 @@ +<?php +/** +* +* @package phpBB3 +* @version $Id$ +* @copyright (c) 2006 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* Code from pear.php.net, Text_Diff-0.2.1 (beta) package +* http://pear.php.net/package/Text_Diff/ +* +* Modified by Acyd Burn to meet our coding standards +* and being able to integrate into phpBB +*/ + +/** +* Class used internally by Diff to actually compute the diffs. This class is +* implemented using native PHP code. +* +* The algorithm used here is mostly lifted from the perl module +* Algorithm::Diff (version 1.06) by Ned Konz, which is available at: +* http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip +* +* More ideas are taken from: +* http://www.ics.uci.edu/~eppstein/161/960229.html +* +* Some ideas (and a bit of code) are taken from analyze.c, of GNU +* diffutils-2.7, which can be found at: +* ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz +* +* Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from +* Geoffrey T. Dairiki <dairiki@dairiki.org>. The original PHP version of this +* code was written by him, and is used/adapted with his permission. +* +* @author Geoffrey T. Dairiki <dairiki@dairiki.org> +* @package phpBB3 +* +* @access private +*/ +class diff_engine +{ + function diff($from_lines, $to_lines) + { + array_walk($from_lines, array('diff', 'trim_newlines')); + array_walk($to_lines, array('diff', 'trim_newlines')); + + $n_from = sizeof($from_lines); + $n_to = sizeof($to_lines); + + $this->xchanged = $this->ychanged = $this->xv = $this->yv = $this->xind = $this->yind = array(); + unset($this->seq, $this->in_seq, $this->lcs); + + // Skip leading common lines. + for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) + { + if ($from_lines[$skip] !== $to_lines[$skip]) + { + break; + } + $this->xchanged[$skip] = $this->ychanged[$skip] = false; + } + + // Skip trailing common lines. + $xi = $n_from; + $yi = $n_to; + + for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) + { + if ($from_lines[$xi] !== $to_lines[$yi]) + { + break; + } + $this->xchanged[$xi] = $this->ychanged[$yi] = false; + } + + // Ignore lines which do not exist in both files. + for ($xi = $skip; $xi < $n_from - $endskip; $xi++) + { + $xhash[$from_lines[$xi]] = 1; + } + + for ($yi = $skip; $yi < $n_to - $endskip; $yi++) + { + $line = $to_lines[$yi]; + + if (($this->ychanged[$yi] = empty($xhash[$line]))) + { + continue; + } + $yhash[$line] = 1; + $this->yv[] = $line; + $this->yind[] = $yi; + } + + for ($xi = $skip; $xi < $n_from - $endskip; $xi++) + { + $line = $from_lines[$xi]; + + if (($this->xchanged[$xi] = empty($yhash[$line]))) + { + continue; + } + $this->xv[] = $line; + $this->xind[] = $xi; + } + + // Find the LCS. + $this->_compareseq(0, sizeof($this->xv), 0, sizeof($this->yv)); + + // Merge edits when possible. + $this->_shift_boundaries($from_lines, $this->xchanged, $this->ychanged); + $this->_shift_boundaries($to_lines, $this->ychanged, $this->xchanged); + + // Compute the edit operations. + $edits = array(); + $xi = $yi = 0; + + while ($xi < $n_from || $yi < $n_to) + { + // Skip matching "snake". + $copy = array(); + + while ($xi < $n_from && $yi < $n_to && !$this->xchanged[$xi] && !$this->ychanged[$yi]) + { + $copy[] = $from_lines[$xi++]; + $yi++; + } + + if ($copy) + { + $edits[] = &new diff_op_copy($copy); + } + + // Find deletes & adds. + $delete = array(); + while ($xi < $n_from && $this->xchanged[$xi]) + { + $delete[] = $from_lines[$xi++]; + } + + $add = array(); + while ($yi < $n_to && $this->ychanged[$yi]) + { + $add[] = $to_lines[$yi++]; + } + + if ($delete && $add) + { + $edits[] = &new diff_op_change($delete, $add); + } + else if ($delete) + { + $edits[] = &new diff_op_delete($delete); + } + else if ($add) + { + $edits[] = &new diff_op_add($add); + } + } + + return $edits; + } + + /** + * Divides the Largest Common Subsequence (LCS) of the sequences (XOFF, + * XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized segments. + * + * Returns (LCS, PTS). LCS is the length of the LCS. PTS is an array of + * NCHUNKS+1 (X, Y) indexes giving the diving points between sub + * sequences. The first sub-sequence is contained in (X0, X1), (Y0, Y1), + * the second in (X1, X2), (Y1, Y2) and so on. Note that (X0, Y0) == + * (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM). + * + * This function assumes that the first lines of the specified portions of + * the two files do not match, and likewise that the last lines do not + * match. The caller must trim matching lines from the beginning and end + * of the portions it is going to specify. + */ + function _diag($xoff, $xlim, $yoff, $ylim, $nchunks) + { + $flip = false; + + if ($xlim - $xoff > $ylim - $yoff) + { + // Things seems faster (I'm not sure I understand why) when the shortest sequence is in X. + $flip = true; + list($xoff, $xlim, $yoff, $ylim) = array($yoff, $ylim, $xoff, $xlim); + } + + if ($flip) + { + for ($i = $ylim - 1; $i >= $yoff; $i--) + { + $ymatches[$this->xv[$i]][] = $i; + } + } + else + { + for ($i = $ylim - 1; $i >= $yoff; $i--) + { + $ymatches[$this->yv[$i]][] = $i; + } + } + + $this->lcs = 0; + $this->seq[0]= $yoff - 1; + $this->in_seq = array(); + $ymids[0] = array(); + + $numer = $xlim - $xoff + $nchunks - 1; + $x = $xoff; + + for ($chunk = 0; $chunk < $nchunks; $chunk++) + { + if ($chunk > 0) + { + for ($i = 0; $i <= $this->lcs; $i++) + { + $ymids[$i][$chunk - 1] = $this->seq[$i]; + } + } + + $x1 = $xoff + (int)(($numer + ($xlim-$xoff)*$chunk) / $nchunks); + + for (; $x < $x1; $x++) + { + $line = $flip ? $this->yv[$x] : $this->xv[$x]; + if (empty($ymatches[$line])) + { + continue; + } + $matches = $ymatches[$line]; + + foreach ($matches as $y) + { + if (empty($this->in_seq[$y])) + { + $k = $this->_lcs_pos($y); + $ymids[$k] = $ymids[$k - 1]; + break; + } + } + + while (list($junk, $y) = each($matches)) + { + if ($y > $this->seq[$k - 1]) + { + // Optimization: this is a common case: next match is just replacing previous match. + $this->in_seq[$this->seq[$k]] = false; + $this->seq[$k] = $y; + $this->in_seq[$y] = 1; + } + else if (empty($this->in_seq[$y])) + { + $k = $this->_lcs_pos($y); + $ymids[$k] = $ymids[$k - 1]; + } + } + } + } + + $seps[] = $flip ? array($yoff, $xoff) : array($xoff, $yoff); + $ymid = $ymids[$this->lcs]; + + for ($n = 0; $n < $nchunks - 1; $n++) + { + $x1 = $xoff + (int)(($numer + ($xlim - $xoff) * $n) / $nchunks); + $y1 = $ymid[$n] + 1; + $seps[] = $flip ? array($y1, $x1) : array($x1, $y1); + } + $seps[] = $flip ? array($ylim, $xlim) : array($xlim, $ylim); + + return array($this->lcs, $seps); + } + + function _lcs_pos($ypos) + { + $end = $this->lcs; + + if ($end == 0 || $ypos > $this->seq[$end]) + { + $this->seq[++$this->lcs] = $ypos; + $this->in_seq[$ypos] = 1; + return $this->lcs; + } + + $beg = 1; + while ($beg < $end) + { + $mid = (int)(($beg + $end) / 2); + if ($ypos > $this->seq[$mid]) + { + $beg = $mid + 1; + } + else + { + $end = $mid; + } + } + + $this->in_seq[$this->seq[$end]] = false; + $this->seq[$end] = $ypos; + $this->in_seq[$ypos] = 1; + + return $end; + } + + /** + * Finds LCS of two sequences. + * + * The results are recorded in the vectors $this->{x,y}changed[], by + * storing a 1 in the element for each line that is an insertion or + * deletion (ie. is not in the LCS). + * + * The subsequence of file 0 is (XOFF, XLIM) and likewise for file 1. + * + * Note that XLIM, YLIM are exclusive bounds. All line numbers are + * origin-0 and discarded lines are not counted. + */ + function _compareseq($xoff, $xlim, $yoff, $ylim) + { + // Slide down the bottom initial diagonal. + while ($xoff < $xlim && $yoff < $ylim && $this->xv[$xoff] == $this->yv[$yoff]) + { + ++$xoff; + ++$yoff; + } + + // Slide up the top initial diagonal. + while ($xlim > $xoff && $ylim > $yoff && $this->xv[$xlim - 1] == $this->yv[$ylim - 1]) + { + --$xlim; + --$ylim; + } + + if ($xoff == $xlim || $yoff == $ylim) + { + $lcs = 0; + } + else + { + // This is ad hoc but seems to work well. + // $nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); + // $nchunks = max(2,min(8,(int)$nchunks)); + $nchunks = min(7, $xlim - $xoff, $ylim - $yoff) + 1; + list($lcs, $seps) = $this->_diag($xoff, $xlim, $yoff, $ylim, $nchunks); + } + + if ($lcs == 0) + { + // X and Y sequences have no common subsequence: mark all changed. + while ($yoff < $ylim) + { + $this->ychanged[$this->yind[$yoff++]] = 1; + } + + while ($xoff < $xlim) + { + $this->xchanged[$this->xind[$xoff++]] = 1; + } + } + else + { + // Use the partitions to split this problem into subproblems. + reset($seps); + $pt1 = $seps[0]; + + while ($pt2 = next($seps)) + { + $this->_compareseq($pt1[0], $pt2[0], $pt1[1], $pt2[1]); + $pt1 = $pt2; + } + } + } + + /** + * Adjusts inserts/deletes of identical lines to join changes as much as possible. + * + * We do something when a run of changed lines include a line at one end + * and has an excluded, identical line at the other. We are free to + * choose which identical line is included. 'compareseq' usually chooses + * the one at the beginning, but usually it is cleaner to consider the + * following identical line to be the "change". + * + * This is extracted verbatim from analyze.c (GNU diffutils-2.7). + */ + function _shift_boundaries($lines, &$changed, $other_changed) + { + $i = 0; + $j = 0; + + $len = sizeof($lines); + $other_len = sizeof($other_changed); + + while (1) + { + // Scan forward to find the beginning of another run of + // changes. Also keep track of the corresponding point in the other file. + // + // Throughout this code, $i and $j are adjusted together so that + // the first $i elements of $changed and the first $j elements of + // $other_changed both contain the same number of zeros (unchanged lines). + // + // Furthermore, $j is always kept so that $j == $other_len or $other_changed[$j] == false. + while ($j < $other_len && $other_changed[$j]) + { + $j++; + } + + while ($i < $len && ! $changed[$i]) + { + $i++; + $j++; + + while ($j < $other_len && $other_changed[$j]) + { + $j++; + } + } + + if ($i == $len) + { + break; + } + + $start = $i; + + // Find the end of this run of changes. + while (++$i < $len && $changed[$i]) + { + continue; + } + + do + { + // Record the length of this run of changes, so that we can later determine whether the run has grown. + $runlength = $i - $start; + + // Move the changed region back, so long as the previous unchanged line matches the last changed one. + // This merges with previous changed regions. + while ($start > 0 && $lines[$start - 1] == $lines[$i - 1]) + { + $changed[--$start] = 1; + $changed[--$i] = false; + + while ($start > 0 && $changed[$start - 1]) + { + $start--; + } + + while ($other_changed[--$j]) + { + continue; + } + } + + // Set CORRESPONDING to the end of the changed run, at the last point where it corresponds to a changed run in the + // other file. CORRESPONDING == LEN means no such point has been found. + $corresponding = $j < $other_len ? $i : $len; + + // Move the changed region forward, so long as the first changed line matches the following unchanged one. + // This merges with following changed regions. + // Do this second, so that if there are no merges, the changed region is moved forward as far as possible. + while ($i < $len && $lines[$start] == $lines[$i]) + { + $changed[$start++] = false; + $changed[$i++] = 1; + + while ($i < $len && $changed[$i]) + { + $i++; + } + + $j++; + if ($j < $other_len && $other_changed[$j]) + { + $corresponding = $i; + while ($j < $other_len && $other_changed[$j]) + { + $j++; + } + } + } + } + while ($runlength != $i - $start); + + // If possible, move the fully-merged run of changes back to a corresponding run in the other file. + while ($corresponding < $i) + { + $changed[--$start] = 1; + $changed[--$i] = 0; + + while ($other_changed[--$j]) + { + continue; + } + } + } + } +} + +?>
\ No newline at end of file diff --git a/phpBB/includes/diff/renderer.php b/phpBB/includes/diff/renderer.php new file mode 100644 index 0000000000..408addb858 --- /dev/null +++ b/phpBB/includes/diff/renderer.php @@ -0,0 +1,832 @@ +<?php +/** +* +* @package phpBB3 +* @version $Id$ +* @copyright (c) 2006 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +*/ + +/** +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** +* Code from pear.php.net, Text_Diff-0.2.1 (beta) package +* http://pear.php.net/package/Text_Diff/ +* +* Modified by Acyd Burn to meet our coding standards +* and being able to integrate into phpBB +*/ + +/** +* A class to render Diffs in different formats. +* +* This class renders the diff in classic diff format. It is intended that +* this class be customized via inheritance, to obtain fancier outputs. +* +* @package phpBB3 +*/ +class diff_renderer +{ + /** + * Number of leading context "lines" to preserve. + * + * This should be left at zero for this class, but subclasses may want to + * set this to other values. + */ + var $_leading_context_lines = 0; + + /** + * Number of trailing context "lines" to preserve. + * + * This should be left at zero for this class, but subclasses may want to + * set this to other values. + */ + var $_trailing_context_lines = 0; + + /** + * Constructor. + */ + function diff_renderer($params = array()) + { + foreach ($params as $param => $value) + { + $v = '_' . $param; + if (isset($this->$v)) + { + $this->$v = $value; + } + } + } + + /** + * Get any renderer parameters. + * + * @return array All parameters of this renderer object. + */ + function get_params() + { + $params = array(); + foreach (get_object_vars($this) as $k => $v) + { + if ($k[0] == '_') + { + $params[substr($k, 1)] = $v; + } + } + + return $params; + } + + /** + * Renders a diff. + * + * @param diff $diff A diff object. + * + * @return string The formatted output. + */ + function render(&$diff) + { + $xi = $yi = 1; + $block = false; + $context = array(); + + // Create a new diff object if it is a 3-way diff + if (is_a($diff, 'diff3')) + { + $diff3 = &$diff; + $diff = &new diff($diff3->get_original(), $diff3->merged_output()); + unset($diff3); + } + + $nlead = $this->_leading_context_lines; + $ntrail = $this->_trailing_context_lines; + + $output = $this->_start_diff(); + $diffs = $diff->get_diff(); + + foreach ($diffs as $i => $edit) + { + if (is_a($edit, 'diff_op_copy')) + { + if (is_array($block)) + { + $keep = ($i == sizeof($diffs) - 1) ? $ntrail : $nlead + $ntrail; + if (sizeof($edit->orig) <= $keep) + { + $block[] = $edit; + } + else + { + if ($ntrail) + { + $context = array_slice($edit->orig, 0, $ntrail); + $block[] = &new diff_op_copy($context); + } + + $output .= $this->_block($x0, $ntrail + $xi - $x0, $y0, $ntrail + $yi - $y0, $block); + $block = false; + } + } + $context = $edit->orig; + } + else + { + if (!is_array($block)) + { + $context = array_slice($context, sizeof($context) - $nlead); + $x0 = $xi - sizeof($context); + $y0 = $yi - sizeof($context); + $block = array(); + + if ($context) + { + $block[] = &new diff_op_copy($context); + } + } + $block[] = $edit; + } + + $xi += ($edit->orig) ? sizeof($edit->orig) : 0; + $yi += ($edit->final) ? sizeof($edit->final) : 0; + } + + if (is_array($block)) + { + $output .= $this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block); + } + + return $output . $this->_end_diff(); + } + + function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) + { + $output = $this->_start_block($this->_block_header($xbeg, $xlen, $ybeg, $ylen)); + + foreach ($edits as $edit) + { + switch (get_class($edit)) + { + case 'diff_op_copy': + $output .= $this->_context($edit->orig); + break; + + case 'diff_op_add': + $output .= $this->_added($edit->final); + break; + + case 'diff_op_delete': + $output .= $this->_deleted($edit->orig); + break; + + case 'diff_op_change': + $output .= $this->_changed($edit->orig, $edit->final); + break; + } + } + + return $output . $this->_end_block(); + } + + function _start_diff() + { + return ''; + } + + function _end_diff() + { + return ''; + } + + function _block_header($xbeg, $xlen, $ybeg, $ylen) + { + if ($xlen > 1) + { + $xbeg .= ',' . ($xbeg + $xlen - 1); + } + + if ($ylen > 1) + { + $ybeg .= ',' . ($ybeg + $ylen - 1); + } + + return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg; + } + + function _start_block($header) + { + return $header . "\n"; + } + + function _end_block() + { + return ''; + } + + function _lines($lines, $prefix = ' ') + { + return $prefix . implode("\n$prefix", $lines) . "\n"; + } + + function _context($lines) + { + return $this->_lines($lines, ' '); + } + + function _added($lines) + { + return $this->_lines($lines, '> '); + } + + function _deleted($lines) + { + return $this->_lines($lines, '< '); + } + + function _changed($orig, $final) + { + return $this->_deleted($orig) . "---\n" . $this->_added($final); + } + + /** + * Our function to get the diff + */ + function get_diff_content($diff) + { + return $this->render($diff); + } +} + +/** +* Renders a unified diff +* @package phpBB3 +*/ +class diff_renderer_unified extends diff_renderer +{ + var $_leading_context_lines = 4; + var $_trailing_context_lines = 4; + + /** + * Our function to get the diff + */ + function get_diff_content($diff) + { + return nl2br($this->render($diff)); + } + + function _block_header($xbeg, $xlen, $ybeg, $ylen) + { + if ($xlen != 1) + { + $xbeg .= ',' . $xlen; + } + + if ($ylen != 1) + { + $ybeg .= ',' . $ylen; + } + return '<div class="diff"><big class="info">@@ -' . $xbeg . ' +' . $ybeg . ' @@</big></div>'; + } + + function _context($lines) + { + return '<pre class="diff context">' . htmlspecialchars($this->_lines($lines, ' ')) . '</pre>'; + } + + function _added($lines) + { + return '<pre class="diff added">' . htmlspecialchars($this->_lines($lines, '+')) . '</pre>'; + } + + function _deleted($lines) + { + return '<pre class="diff removed">' . htmlspecialchars($this->_lines($lines, '-')) . '</pre>'; + } + + function _changed($orig, $final) + { + return $this->_deleted($orig) . $this->_added($final); + } + + function _start_diff() + { + $start = '<div class="file">'; + + return $start; + } + + function _end_diff() + { + return '</div>'; + } + + function _end_block() + { + return ''; + } +} + +/** +* "Inline" diff renderer. +* +* This class renders diffs in the Wiki-style "inline" format. +* +* @author Ciprian Popovici +* @package phpBB3 +*/ +class diff_renderer_inline extends diff_renderer +{ + var $_leading_context_lines = 10000; + var $_trailing_context_lines = 10000; + + // Prefix and suffix for inserted text + var $_ins_prefix = '<span class="ins">'; + var $_ins_suffix = '</span>'; + + // Prefix and suffix for deleted text + var $_del_prefix = '<span class="del">'; + var $_del_suffix = '</span>'; + + var $_block_head = ''; + + // What are we currently splitting on? Used to recurse to show word-level + var $_split_level = 'lines'; + + /** + * Our function to get the diff + */ + function get_diff_content($diff) + { + return '<pre>' . nl2br($this->render($diff)) . '</pre>'; + } + + function _start_diff() + { + return ''; + } + + function _end_diff() + { + return ''; + } + + function _block_header($xbeg, $xlen, $ybeg, $ylen) + { + return $this->_block_head; + } + + function _start_block($header) + { + return $header; + } + + function _lines($lines, $prefix = ' ', $encode = true) + { + if ($encode) + { + array_walk($lines, array(&$this, '_encode')); + } + + if ($this->_split_level == 'words') + { + return implode('', $lines); + } + else + { + return implode("\n", $lines) . "\n"; + } + } + + function _added($lines) + { + array_walk($lines, array(&$this, '_encode')); + $lines[0] = $this->_ins_prefix . $lines[0]; + $lines[sizeof($lines) - 1] .= $this->_ins_suffix; + return $this->_lines($lines, ' ', false); + } + + function _deleted($lines, $words = false) + { + array_walk($lines, array(&$this, '_encode')); + $lines[0] = $this->_del_prefix . $lines[0]; + $lines[sizeof($lines) - 1] .= $this->_del_suffix; + return $this->_lines($lines, ' ', false); + } + + function _changed($orig, $final) + { + // If we've already split on words, don't try to do so again - just display. + if ($this->_split_level == 'words') + { + $prefix = ''; + while ($orig[0] !== false && $final[0] !== false && substr($orig[0], 0, 1) == ' ' && substr($final[0], 0, 1) == ' ') + { + $prefix .= substr($orig[0], 0, 1); + $orig[0] = substr($orig[0], 1); + $final[0] = substr($final[0], 1); + } + + return $prefix . $this->_deleted($orig) . $this->_added($final); + } + + $text1 = implode("\n", $orig); + $text2 = implode("\n", $final); + + // Non-printing newline marker. + $nl = "\0"; + + // We want to split on word boundaries, but we need to preserve whitespace as well. + // Therefore we split on words, but include all blocks of whitespace in the wordlist. + $diff = &new diff($this->_split_on_words($text1, $nl), $this->_split_on_words($text2, $nl)); + + // Get the diff in inline format. + $renderer = &new diff_renderer_inline(array_merge($this->get_params(), array('split_level' => 'words'))); + + // Run the diff and get the output. + return str_replace($nl, "\n", $renderer->render($diff)) . "\n"; + } + + function _split_on_words($string, $newline_escape = "\n") + { + // Ignore \0; otherwise the while loop will never finish. + $string = str_replace("\0", '', $string); + + $words = array(); + $length = strlen($string); + $pos = 0; + + $tab_there = true; + while ($pos < $length) + { + // Check for tabs... do not include them + if ($tab_there && substr($string, $pos, 1) === "\t") + { + $words[] = "\t"; + $pos++; + + continue; + } + else + { + $tab_there = false; + } + + // Eat a word with any preceding whitespace. + $spaces = strspn(substr($string, $pos), " \n"); + $nextpos = strcspn(substr($string, $pos + $spaces), " \n"); + $words[] = str_replace("\n", $newline_escape, substr($string, $pos, $spaces + $nextpos)); + $pos += $spaces + $nextpos; + } + + return $words; + } + + function _encode(&$string) + { + $string = htmlspecialchars($string); + } +} + +/** +* "raw" diff renderer. +* This class could be used to output a raw unified patch file +* +* @package phpBB3 +*/ +class diff_renderer_raw extends diff_renderer +{ + var $_leading_context_lines = 4; + var $_trailing_context_lines = 4; + + /** + * Our function to get the diff + */ + function get_diff_content($diff) + { + return '<textarea style="height: 400px;" class="full">' . htmlspecialchars($this->render($diff)) . '</textarea>'; + } + + function _block_header($xbeg, $xlen, $ybeg, $ylen) + { + if ($xlen != 1) + { + $xbeg .= ',' . $xlen; + } + + if ($ylen != 1) + { + $ybeg .= ',' . $ylen; + } + return '@@ -' . $xbeg . ' +' . $ybeg . ' @@'; + } + + function _context($lines) + { + return $this->_lines($lines, ' '); + } + + function _added($lines) + { + return $this->_lines($lines, '+'); + } + + function _deleted($lines) + { + return $this->_lines($lines, '-'); + } + + function _changed($orig, $final) + { + return $this->_deleted($orig) . $this->_added($final); + } +} + +/** +* "chora (Horde)" diff renderer - similar style. +* This renderer class is a modified human_readable function from the Horde Framework. +* +* @package phpBB3 +*/ +class diff_renderer_side_by_side extends diff_renderer +{ + var $_leading_context_lines = 3; + var $_trailing_context_lines = 3; + + var $lines = array(); + + // Hold the left and right columns of lines for change blocks. + var $cols; + var $state; + + var $data = false; + + /** + * Our function to get the diff + */ + function get_diff_content($diff) + { + global $user; + + $output = ''; + $output .= '<table cellspacing="0" class="hrdiff"> +<caption> + <span class="unmodified"> </span> ' . $user->lang['LINE_UNMODIFIED'] . ' + <span class="added"> </span> ' . $user->lang['LINE_ADDED'] . ' + <span class="modified"> </span> ' . $user->lang['LINE_MODIFIED'] . ' + <span class="removed"> </span> ' . $user->lang['LINE_REMOVED'] . ' +</caption> +<tbody> +'; + + $this->render($diff); + + // Is the diff empty? + if (!sizeof($this->lines)) + { + $output .= '<tr><th colspan="2">' . $user->lang['NO_VISIBLE_CHANGES'] . '</th></tr>'; + } + else + { + // Iterate through every header block of changes + foreach ($this->lines as $header) + { + $output .= '<tr><th>Line ' . $header['oldline'] . '</th><th>' . $user->lang['LINE'] . ' ' . $header['newline'] . '</th></tr>'; + + // Each header block consists of a number of changes (add, remove, change). + $current_context = ''; + + foreach ($header['contents'] as $change) + { + if (!empty($current_context) && $change['type'] != 'empty') + { + $line = $current_context; + $current_context = ''; + + $output .= '<tr class="unmodified"><td><pre>' . ((strlen($line)) ? $line : ' ') . '</pre></td> + <td><pre>' . ((strlen($line)) ? $line : ' ') . '</pre></td></tr>'; + } + + switch ($change['type']) + { + case 'add': + $line = ''; + + foreach ($change['lines'] as $_line) + { + $line .= htmlspecialchars($_line) . '<br />'; + } + + $output .= '<tr><td class="added_empty"> </td><td class="added"><pre>' . ((strlen($line)) ? $line : ' ') . '</pre></td></tr>'; + break; + + case 'remove': + $line = ''; + + foreach ($change['lines'] as $_line) + { + $line .= htmlspecialchars($_line) . '<br />'; + } + + $output .= '<tr><td class="removed"><pre>' . ((strlen($line)) ? $line : ' ') . '</pre></td><td class="removed_empty"> </td></tr>'; + break; + + case 'empty': + $current_context .= htmlspecialchars($change['line']) . '<br />'; + break; + + case 'change': + // Pop the old/new stacks one by one, until both are empty. + $oldsize = sizeof($change['old']); + $newsize = sizeof($change['new']); + $left = $right = ''; + + for ($row = 0, $row_max = max($oldsize, $newsize); $row < $row_max; ++$row) + { + $left .= isset($change['old'][$row]) ? htmlspecialchars($change['old'][$row]) : ''; + $left .= '<br />'; + $right .= isset($change['new'][$row]) ? htmlspecialchars($change['new'][$row]) : ''; + $right .= '<br />'; + } + + $output .= '<tr>'; + + if (!empty($left)) + { + $output .= '<td class="modified"><pre>' . $left . '</pre></td>'; + } + else if ($row < $oldsize) + { + $output .= '<td class="modified"> </td>'; + } + else + { + $output .= '<td class="unmodified"> </td>'; + } + + if (!empty($right)) + { + $output .= '<td class="modified"><pre>' . $right . '</pre></td>'; + } + else if ($row < $newsize) + { + $output .= '<td class="modified"> </td>'; + } + else + { + $output .= '<td class="unmodified"> </td>'; + } + + $output .= '</tr>'; + break; + } + } + + if (!empty($current_context)) + { + $line = $current_context; + $current_context = ''; + + $output .= '<tr class="unmodified"><td><pre>' . ((strlen($line)) ? $line : ' ') . '</pre></td>'; + $output .= '<td><pre>' . ((strlen($line)) ? $line : ' ') . '</pre></td></tr>'; + } + } + } + + $output .= '</tbody></table>'; + + return $output; + } + + function _start_diff() + { + $this->lines = array(); + + $this->data = false; + $this->cols = array(array(), array()); + $this->state = 'empty'; + + return ''; + } + + function _end_diff() + { + // Just flush any remaining entries in the columns stack. + switch ($this->state) + { + case 'add': + $this->data['contents'][] = array('type' => 'add', 'lines' => $this->cols[0]); + break; + + case 'remove': + // We have some removal lines pending in our stack, so flush them. + $this->data['contents'][] = array('type' => 'remove', 'lines' => $this->cols[0]); + break; + + case 'change': + // We have both remove and addition lines, so this is a change block. + $this->data['contents'][] = array('type' => 'change', 'old' => $this->cols[0], 'new' => $this->cols[1]); + break; + } + + if ($this->data !== false) + { + $this->lines[] = $this->data; + } + + return ''; + } + + function _block_header($xbeg, $xlen, $ybeg, $ylen) + { + // Push any previous header information to the return stack. + if ($this->data !== false) + { + $this->lines[] = $this->data; + } + + $this->data = array('type' => 'header', 'oldline' => $xbeg, 'newline' => $ybeg, 'contents' => array()); + $this->state = 'dump'; + } + + function _added($lines) + { + array_walk($lines, array(&$this, '_perform_add')); + } + + function _perform_add($line) + { + if ($this->state == 'empty') + { + return ''; + } + + // This is just an addition line. + if ($this->state == 'dump' || $this->state == 'add') + { + // Start adding to the addition stack. + $this->cols[0][] = $line; + $this->state = 'add'; + } + else + { + // This is inside a change block, so start accumulating lines. + $this->state = 'change'; + $this->cols[1][] = $line; + } + } + + function _deleted($lines) + { + array_walk($lines, array(&$this, '_perform_delete')); + } + + function _perform_delete($line) + { + // This is a removal line. + $this->state = 'remove'; + $this->cols[0][] = $line; + } + + function _context($lines) + { + array_walk($lines, array(&$this, '_perform_context')); + } + + function _perform_context($line) + { + // An empty block with no action. + switch ($this->state) + { + case 'add': + $this->data['contents'][] = array('type' => 'add', 'lines' => $this->cols[0]); + break; + + case 'remove': + // We have some removal lines pending in our stack, so flush them. + $this->data['contents'][] = array('type' => 'remove', 'lines' => $this->cols[0]); + break; + + case 'change': + // We have both remove and addition lines, so this is a change block. + $this->data['contents'][] = array('type' => 'change', 'old' => $this->cols[0], 'new' => $this->cols[1]); + break; + } + + $this->cols = array(array(), array()); + $this->data['contents'][] = array('type' => 'empty', 'line' => $line); + $this->state = 'dump'; + } + + function _changed($orig, $final) + { + return $this->_deleted($orig) . $this->_added($final); + } + +} + +?>
\ No newline at end of file diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 48fec2d795..91a818d454 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -15,7 +15,7 @@ * * Set variable, used by {@link request_var the request_var function} * -* @access: private +* @access private */ function set_var(&$result, $var, $type, $multibyte = false) { @@ -24,14 +24,26 @@ function set_var(&$result, $var, $type, $multibyte = false) if ($type == 'string') { - $result = trim(htmlspecialchars(str_replace(array("\r\n", "\r"), array("\n", "\n"), $result))); - $result = (STRIP) ? stripslashes($result) : $result; + $result = trim(htmlspecialchars(str_replace(array("\r\n", "\r"), array("\n", "\n"), $result), ENT_COMPAT, 'UTF-8')); - // Check for possible multibyte characters to save a preg_replace call if nothing is in there... - if ($multibyte && strpos($result, '&#') !== false) + if (!empty($result)) { - $result = preg_replace('#&(\#[0-9]+;)#', '&\1', $result); + // Make sure multibyte characters are wellformed + if ($multibyte) + { + if (!preg_match('/^./u', $result)) + { + $result = ''; + } + } + else + { + // no multibyte, allow only ASCII (0-127) + $result = preg_replace('/[\x80-\xFF]/', '?', $result); + } } + + $result = (STRIP) ? stripslashes($result) : $result; } } @@ -40,8 +52,17 @@ function set_var(&$result, $var, $type, $multibyte = false) * * Used to get passed variable */ -function request_var($var_name, $default, $multibyte = false) +function request_var($var_name, $default, $multibyte = false, $cookie = false) { + if (!$cookie && isset($_COOKIE[$var_name])) + { + if (!isset($_GET[$var_name]) && !isset($_POST[$var_name])) + { + return (is_array($default)) ? array() : $default; + } + $_REQUEST[$var_name] = isset($_POST[$var_name]) ? $_POST[$var_name] : $_GET[$var_name]; + } + if (!isset($_REQUEST[$var_name]) || (is_array($_REQUEST[$var_name]) && !is_array($default)) || (is_array($default) && !is_array($_REQUEST[$var_name]))) { return (is_array($default)) ? array() : $default; @@ -136,16 +157,17 @@ function gen_rand_string($num_chars = 8) */ function unique_id($extra = 'c') { + static $dss_seeded = false; global $config; - static $dss_seeded; $val = $config['rand_seed'] . microtime(); $val = md5($val); $config['rand_seed'] = md5($config['rand_seed'] . $val . $extra); - if ($dss_seeded !== true) + if ($dss_seeded !== true && ($config['rand_seed_last_update'] < time() - rand(1,10))) { set_config('rand_seed', $config['rand_seed'], true); + set_config('rand_seed_last_update', time(), true); $dss_seeded = true; } @@ -161,6 +183,26 @@ function gen_sort_selects(&$limit_days, &$sort_by_text, &$sort_days, &$sort_key, $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']); + // Check if the key is selectable. If not, we reset to the first key found. + // This ensures the values are always valid. + if (!isset($limit_days[$sort_days])) + { + @reset($limit_days); + $sort_days = key($limit_days); + } + + if (!isset($sort_by_text[$sort_key])) + { + @reset($sort_by_text); + $sort_key = key($sort_by_text); + } + + if (!isset($sort_dir_text[$sort_dir])) + { + @reset($sort_dir_text); + $sort_dir = key($sort_dir_text); + } + $s_limit_days = '<select name="st">'; foreach ($limit_days as $day => $text) { @@ -378,62 +420,191 @@ if (!function_exists('stripos')) if (!function_exists('realpath')) { - /** - * Replacement for realpath if it is disabled - * This function is from the php manual by nospam at savvior dot com - */ - function phpbb_realpath($path) + if (substr(PHP_OS, 0, 3) != 'WIN' && !(bool) ini_get('safe_mode') && function_exists('shell_exec') && trim(`realpath .`)) + { + /** + * @author Chris Smith <chris@project-minerva.org> + * @copyright 2006 Project Minerva Team + * @param string $path The path which we should attempt to resolve. + * @return mixed + * @ignore + */ + function phpbb_realpath($path) + { + $arg = escapeshellarg($path); + return trim(`realpath '$arg'`); + } + } + else { - $translated_path = getenv('PATH_TRANSLATED'); + /** + * Checks if a path ($path) is absolute or relative + * + * @param string $path Path to check absoluteness of + * @return boolean + */ + function is_absolute($path) + { + return ($path[0] == '/' || (substr(PHP_OS, 0, 3) == 'WIN' && preg_match('#^[a-z]:/#i', $path))) ? true : false; + } - $translated_path = str_replace('\\', '/', $translated_path); - $translated_path = str_replace(basename(getenv('PATH_INFO')), '', $translated_path); + /** + * @author Chris Smith <chris@project-minerva.org> + * @copyright 2006 Project Minerva Team + * @param string $path The path which we should attempt to resolve. + * @return mixed + */ + function phpbb_realpath($path) + { + // Now to perform funky shizzle - $translated_path .= '/'; + // Switch to use UNIX slashes + $path = str_replace(DIRECTORY_SEPARATOR, '/', $path); + $path_prefix = ''; - if ($path == '.' || $path == './') - { - return $translated_path; - } + // Determine what sort of path we have + if (is_absolute($path)) + { + $absolute = true; + + if ($path[0] == '/') + { + // Absolute path, *NIX style + $path_prefix = ''; + } + else + { + // Absolute path, Windows style + // Remove the drive letter and colon + $path_prefix = $path[0] . ':'; + $path = substr($path, 2); + } + } + else + { + // Relative Path + // Prepend the current working directory + if (function_exists('getcwd')) + { + // This is the best method, hopefully it is enabled! + $path = str_replace(DIRECTORY_SEPARATOR, '/', getcwd()) . '/' . $path; + $absolute = true; + if (preg_match('#^[a-z]:#i', $path)) + { + $path_prefix = $path[0] . ':'; + $path = substr($path, 2); + } + else + { + $path_prefix = ''; + } + } + else if (isset($_SERVER['SCRIPT_FILENAME']) && !empty($_SERVER['SCRIPT_FILENAME'])) + { + // Warning: If chdir() has been used this will lie! + // @todo This has some problems sometime (CLI can create them easily) + $path = str_replace(DIRECTORY_SEPARATOR, '/', dirname($_SERVER['SCRIPT_FILENAME'])) . '/' . $path; + $absolute = true; + $path_prefix = ''; + } + else + { + // We have no way of getting the absolute path, just run on using relative ones. + $absolute = false; + $path_prefix = '.'; + } + } - // now check for back directory - $translated_path .= $path; + // Remove any repeated slashes + $path = preg_replace('#/{2,}#', '/', $path); - $dirs = explode('/', $translated_path); + // Remove the slashes from the start and end of the path + $path = trim($path, '/'); - foreach ($dirs as $key => $value) - { - if ($value == '..') + // Break the string into little bits for us to nibble on + $bits = explode('/', $path); + + // Remove any . in the path + $bits = array_diff($bits, array('.')); + + // Lets get looping, run over and resolve any .. (up directory) + for ($i = 0, $max = sizeof($bits); $i < $max; $i++) { - $dirs[$key] = ''; - $dirs[$key - 2] = ''; + // @todo Optimise + if ($bits[$i] == '..' ) + { + if (isset($bits[$i - 1])) + { + if ($bits[$i - 1] != '..') + { + // We found a .. and we are able to traverse upwards, lets do it! + unset($bits[$i]); + unset($bits[$i - 1]); + $i -= 2; + $max -= 2; + $bits = array_values($bits); + } + } + else if ($absolute) // ie. !isset($bits[$i - 1]) && $absolute + { + // We have an absolute path trying to descend above the root of the filesystem + // ... Error! + return false; + } + } } - } - $translated_path = ''; + // Prepend the path prefix + array_unshift($bits, $path_prefix); - foreach ($dirs as $key => $value) - { - if (strlen($value) > 0) + $resolved = ''; + + $max = sizeof($bits) - 1; + + // Check if we are able to resolve symlinks, Windows cannot. + $symlink_resolve = (function_exists('readlink')) ? true : false; + + foreach ($bits as $i => $bit) + { + if (@is_dir("$resolved/$bit") || ($i == $max && @is_file("$resolved/$bit"))) + { + // Path Exists + if ($symlink_resolve && is_link("$resolved/$bit") && ($link = readlink("$resolved/$bit"))) + { + // Resolved a symlink. + $resolved = $link . (($i == $max) ? '' : '/'); + continue; + } + } + else + { + // Something doesn't exist here! + // This is correct realpath() behaviour but sadly open_basedir and safe_mode make this problematic + // return false; + } + $resolved .= $bit . (($i == $max) ? '' : '/'); + } + + // @todo If the file exists fine and open_basedir only has one path we should be able to prepend it + // because we must be inside that basedir, the question is where... + // @internal The slash in is_dir() gets around an open_basedir restriction + if (!@file_exists($resolved) || (!is_dir($resolved . '/') && !is_file($resolved))) { - $translated_path .= $value . '/'; + return false; } - } - $translated_path = substr($translated_path, 0, strlen($translated_path) - 1); + // Put the slashes back to the native operating systems slashes + $resolved = str_replace('/', DIRECTORY_SEPARATOR, $resolved); - if (is_dir($translated_path) || is_file($translated_path)) - { - return $translated_path; + return $resolved; // We got here, in the end! } - - return false; } } else { /** * A wrapper for realpath + * @ignore */ function phpbb_realpath($path) { @@ -441,6 +612,14 @@ else } } +if (!function_exists('htmlspecialchars_decode')) +{ + function htmlspecialchars_decode($string, $quote_style = ENT_COMPAT) + { + return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style))); + } +} + // functions used for building option fields /** @@ -503,7 +682,7 @@ function tz_select($default = '', $truncate = false) { if ($truncate) { - $zone = (strlen($zone) > 70) ? substr($zone, 0, 70) . '...' : $zone; + $zone = (utf8_strlen($zone) > 70) ? utf8_substr($zone, 0, 70) . '...' : $zone; } if (is_numeric($offset)) @@ -613,24 +792,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ ); } - if (sizeof($sql_ary)) - { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query('INSERT INTO ' . FORUMS_TRACK_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $sql_ary)); - break; - - default: - foreach ($sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . FORUMS_TRACK_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } - } + $db->sql_multi_insert(FORUMS_TRACK_TABLE, $sql_ary); } } else if ($config['load_anon_lastread'] || $user->data['is_registered']) @@ -1004,6 +1166,7 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis * @param int $f_mark_time the forums last mark time if user is registered and load_db_lastread enabled * @param int $mark_time_forum false if the mark time needs to be obtained, else the last users forum mark time * +* @return true if complete forum got marked read, else false. */ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time = false, $mark_time_forum = false) { @@ -1098,7 +1261,10 @@ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_ti if (!$row) { markread('topics', $forum_id); + return true; } + + return false; } // Pagination functions @@ -1304,16 +1470,19 @@ function generate_board_url($without_script_path = false) /** * Redirects the user to another page then exits the script nicely */ -function redirect($url) +function redirect($url, $return = false) { - global $db, $cache, $config, $user; + global $db, $cache, $config, $user, $phpbb_root_path; if (empty($user->lang)) { $user->add_lang('common'); } - garbage_collection(); + if (!$return) + { + garbage_collection(); + } // Make sure no &'s are in, this will break the redirect $url = str_replace('&', '&', $url); @@ -1336,7 +1505,7 @@ function redirect($url) { // Full URL } - else if ($url{0} == '/') + else if ($url[0] == '/') { // Absolute uri, prepend direct url... $url = generate_board_url(true) . $url; @@ -1360,8 +1529,8 @@ function redirect($url) } else { - // Get the realpath of dirname - $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath('./'))); + // Used ./ before, but $phpbb_root_path is working better with urls within another root path + $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($phpbb_root_path))); $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($pathinfo['dirname']))); $intersection = array_intersect_assoc($root_dirs, $page_dirs); @@ -1380,6 +1549,17 @@ function redirect($url) } } + // Make sure no linebreaks are there... to prevent http response splitting for PHP < 4.4.2 + if (strpos(urldecode($url), "\n") !== false || strpos(urldecode($url), "\r") !== false || strpos($url, ';') !== false) + { + trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR); + } + + if ($return) + { + return $url; + } + // Redirect via an HTML form for PITA webservers if (@preg_match('#Microsoft|WebSTAR|Xitami#', getenv('SERVER_SOFTWARE'))) { @@ -1453,9 +1633,20 @@ function build_url($strip_vars = false) } $query = $_query = array(); - parse_str(substr($redirect, strpos($redirect, '?') + 1), $query); + + $args = substr($redirect, strpos($redirect, '?') + 1); + $args = ($args) ? explode('&', $args) : array(); $redirect = substr($redirect, 0, strpos($redirect, '?')); + foreach ($args as $argument) + { + $arguments = explode('=', $argument); + $key = $arguments[0]; + unset($arguments[0]); + + $query[$key] = implode('=', $arguments); + } + // Strip the vars off foreach ($strip_vars as $strip) { @@ -1465,7 +1656,7 @@ function build_url($strip_vars = false) } } - // + // Glue the remaining parts together... already urlencoded foreach ($query as $key => $value) { $_query[] = $key . '=' . $value; @@ -1485,6 +1676,8 @@ function meta_refresh($time, $url) { global $template; + $url = redirect($url, true); + $template->assign_vars(array( 'META' => '<meta http-equiv="refresh" content="' . $time . ';url=' . $url . '" />') ); @@ -1632,14 +1825,14 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa if (isset($_POST['login'])) { - $username = request_var('username', ''); - $password = request_var('password', ''); + $username = request_var('username', '', true); + $password = request_var('password', '', true); $autologin = (!empty($_POST['autologin'])) ? true : false; $viewonline = (!empty($_POST['viewonline'])) ? 0 : 1; $admin = ($admin) ? 1 : 0; // Check if the supplied username is equal to the one stored within the database if re-authenticating - if ($admin && strtolower($username) != strtolower($user->data['username'])) + if ($admin && utf8_clean_string($username) != utf8_clean_string($user->data['username'])) { // We log the attempt to use a different username... add_log('admin', 'LOG_ADMIN_AUTH_FAIL'); @@ -1715,7 +1908,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa 'S_CONFIRM_CODE' => true, 'CONFIRM_ID' => $confirm_id, 'CONFIRM_IMAGE' => '<img src="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=confirm&id=' . $confirm_id . '&type=' . CONFIRM_LOGIN) . '" alt="" title="" />', - 'L_LOGIN_CONFIRM_EXPLAIN' => sprintf($user->lang['LOGIN_CONFIRM_EXPLAIN'], '<a href="mailto:' . htmlentities($config['board_contact']) . '">', '</a>'), + 'L_LOGIN_CONFIRM_EXPLAIN' => sprintf($user->lang['LOGIN_CONFIRM_EXPLAIN'], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'), )); $err = $user->lang[$result['error_msg']]; @@ -1729,7 +1922,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa // Assign admin contact to some error messages if ($result['error_msg'] == 'LOGIN_ERROR_USERNAME' || $result['error_msg'] == 'LOGIN_ERROR_PASSWORD') { - $err = (!$config['board_contact']) ? sprintf($user->lang[$result['error_msg']], '', '') : sprintf($user->lang[$result['error_msg']], '<a href="mailto:' . htmlentities($config['board_contact']) . '">', '</a>'); + $err = (!$config['board_contact']) ? sprintf($user->lang[$result['error_msg']], '', '') : sprintf($user->lang[$result['error_msg']], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'); } break; } @@ -1738,7 +1931,15 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa if (!$redirect) { // We just use what the session code determined... - $redirect = $user->page['page_name'] . (($user->page['query_string']) ? '?' . $user->page['query_string'] : ''); + // If we are not within the admin directory we use the page dir... + $redirect = ''; + + if (!$admin) + { + $redirect .= ($user->page['page_dir']) ? $user->page['page_dir'] . '/' : ''; + } + + $redirect .= $user->page['page_name'] . (($user->page['query_string']) ? '?' . $user->page['query_string'] : ''); } $s_hidden_fields = build_hidden_fields(array('redirect' => $redirect, 'sid' => $user->session_id)); @@ -1753,7 +1954,8 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa 'U_PRIVACY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'), 'S_DISPLAY_FULL_LOGIN' => ($s_display) ? true : false, - 'S_LOGIN_ACTION' => (!$admin) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') : append_sid("index.$phpEx"), // Needs to stay index.$phpEx because we are within the admin directory + 'S_AUTOLOGIN_ENABLED' => ($config['allow_autologin']) ? true : false, + 'S_LOGIN_ACTION' => (!$admin) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') : append_sid("index.$phpEx", false, true, $user->session_id), // Needs to stay index.$phpEx because we are within the admin directory 'S_HIDDEN_FIELDS' => $s_hidden_fields, 'S_ADMIN_AUTH' => $admin, @@ -1777,7 +1979,7 @@ function login_forum_box($forum_data) { global $db, $config, $user, $template, $phpEx; - $password = request_var('password', ''); + $password = request_var('password', '', true); $sql = 'SELECT forum_id FROM ' . FORUMS_ACCESS_TABLE . ' @@ -1832,7 +2034,11 @@ function login_forum_box($forum_data) $template->assign_var('LOGIN_ERROR', $user->lang['WRONG_PASSWORD']); } - page_header(); + page_header($user->lang['LOGIN']); + + $template->assign_vars(array( + 'S_HIDDEN_FIELDS' => build_hidden_fields(array('f' => $forum_data['forum_id']))) + ); $template->set_filenames(array( 'body' => 'login_forum.html') @@ -1876,6 +2082,117 @@ function bump_topic_allowed($forum_id, $topic_bumped, $last_post_time, $topic_po } /** +* Generates a text with approx. the specified length which contains the specified words and their context +* +* @param string $text The full text from which context shall be extracted +* @param string $words An array of words which should be contained in the result, has to be a valid part of a PCRE pattern (escape with preg_quote!) +* @param int $length The desired length of the resulting text, however the result might be shorter or longer than this value +* +* @return string Context of the specified words seperated by "..." +*/ +function get_context($text, $words, $length = 400) +{ + // first replace all whitespaces with single spaces + $text = preg_replace('/\s+/', ' ', $text); + + $word_indizes = array(); + if (sizeof($words)) + { + $match = ''; + // find the starting indizes of all words + foreach ($words as $word) + { + if (preg_match('#(?:[^\w]|^)(' . $word . ')(?:[^\w]|$)#i', $text, $match)) + { + $pos = strpos($text, $match[1]); + if ($pos !== false) + { + $word_indizes[] = $pos; + } + } + } + unset($match); + + if (sizeof($word_indizes)) + { + $word_indizes = array_unique($word_indizes); + sort($word_indizes); + + $wordnum = sizeof($word_indizes); + // number of characters on the right and left side of each word + $sequence_length = (int) ($length / (2 * $wordnum)) - 2; + $final_text = ''; + $word = $j = 0; + $final_text_index = -1; + + // cycle through every character in the original text + for ($i = $word_indizes[$word], $n = strlen($text); $i < $n; $i++) + { + // if the current position is the start of one of the words then append $sequence_length characters to the final text + if (isset($word_indizes[$word]) && ($i == $word_indizes[$word])) + { + if ($final_text_index < $i - $sequence_length - 1) + { + $final_text .= '... ' . preg_replace('#^([^ ]*)#', '', substr($text, $i - $sequence_length, $sequence_length)); + } + else + { + // if the final text is already nearer to the current word than $sequence_length we only append the text + // from its current index on and distribute the unused length to all other sequenes + $sequence_length += (int) (($final_text_index - $i + $sequence_length + 1) / (2 * $wordnum)); + $final_text .= substr($text, $final_text_index + 1, $i - $final_text_index - 1); + } + $final_text_index = $i - 1; + + // add the following characters to the final text (see below) + $word++; + $j = 1; + } + + if ($j > 0) + { + // add the character to the final text and increment the sequence counter + $final_text .= $text[$i]; + $final_text_index++; + $j++; + + // if this is a whitespace then check whether we are done with this sequence + if ($text[$i] == ' ') + { + // only check whether we have to exit the context generation completely if we haven't already reached the end anyway + if ($i + 4 < $n) + { + if (($j > $sequence_length && $word >= $wordnum) || strlen($final_text) > $length) + { + $final_text .= ' ...'; + break; + } + } + else + { + // make sure the text really reaches the end + $j -= 4; + } + + // stop context generation and wait for the next word + if ($j > $sequence_length) + { + $j = 0; + } + } + } + } + return $final_text; + } + } + + if (!sizeof($words) || !sizeof($word_indizes)) + { + return (strlen($text) >= $length + 3) ? substr($text, 0, $length) . '...' : $text; + } +} + +/** * Decode text whereby text is coming from the db and expected to be pre-parsed content * We are placing this outside of the message parser because we are often in need of it... */ @@ -1896,21 +2213,28 @@ function decode_message(&$message, $bbcode_uid = '') $message = str_replace($match, $replace, $message); - $match = array( - '#<!\-\- e \-\-><a href="mailto:(.*?)">.*?</a><!\-\- e \-\->#', - '#<!\-\- m \-\-><a href="(.*?)" target="_blank">.*?</a><!\-\- m \-\->#', - '#<!\-\- w \-\-><a href="http:\/\/(.*?)" target="_blank">.*?</a><!\-\- w \-\->#', - '#<!\-\- l \-\-><a href="(.*?)">.*?</a><!\-\- l \-\->#', - '#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#', - '#<!\-\- .*? \-\->#s', - '#<.*?>#s' - ); - - $replace = array('\1', '\1', '\1', '\1', '\1', '', ''); - + $match = get_preg_expression('bbcode_htm'); + $replace = array('\1', '\2', '\1', '', ''); + $message = preg_replace($match, $replace, $message); +} - return; +/** +* Strips all bbcode from a text and returns the plain content +*/ +function strip_bbcode(&$text, $uid = '') +{ + if (!$uid) + { + $uid = '[0-9a-z]{5,}'; + } + + $text = preg_replace("#\[\/?[a-z0-9\*\+\-]+(?:=.*?)?(?::[a-z])?(\:?$uid)\]#", ' ', $text); + + $match = get_preg_expression('bbcode_htm'); + $replace = array('\1', '\2', '\1', '', ''); + + $text = preg_replace($match, $replace, $text); } /** @@ -1919,36 +2243,37 @@ function decode_message(&$message, $bbcode_uid = '') */ function generate_text_for_display($text, $uid, $bitfield, $flags) { - global $__bbcode; + static $bbcode; if (!$text) { return ''; } + $text = str_replace("\n", '<br />', censor_text($text)); + // Parse bbcode if bbcode uid stored and bbcode enabled - if ($uid && ($flags & 1)) + if ($uid && ($flags & OPTION_FLAG_BBCODE)) { if (!class_exists('bbcode')) { global $phpbb_root_path, $phpEx; - include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); + include($phpbb_root_path . 'includes/bbcode.' . $phpEx); } - if (empty($__bbcode)) + if (empty($bbcode)) { - $__bbcode = new bbcode($bitfield); + $bbcode = new bbcode($bitfield); } else { - $__bbcode->bbcode($bitfield); + $bbcode->bbcode($bitfield); } - $__bbcode->bbcode_second_pass($text, $uid); + $bbcode->bbcode_second_pass($text, $uid); } - $text = smiley_text($text, !($flags & 2)); - $text = str_replace("\n", '<br />', censor_text($text)); + $text = smiley_text($text, !($flags & OPTION_FLAG_SMILIES)); return $text; } @@ -1962,8 +2287,7 @@ function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bb { global $phpbb_root_path, $phpEx; - $uid = ''; - $bitfield = ''; + $uid = $bitfield = ''; if (!$text) { @@ -1972,7 +2296,7 @@ function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bb if (!class_exists('parse_message')) { - include_once($phpbb_root_path . 'includes/message_parser.' . $phpEx); + include($phpbb_root_path . 'includes/message_parser.' . $phpEx); } $message_parser = new parse_message($text); @@ -2004,9 +2328,9 @@ function generate_text_for_edit($text, $uid, $flags) decode_message($text, $uid); return array( - 'allow_bbcode' => ($flags & 1) ? 1 : 0, - 'allow_smilies' => ($flags & 2) ? 1 : 0, - 'allow_urls' => ($flags & 4) ? 1 : 0, + 'allow_bbcode' => ($flags & OPTION_FLAG_BBCODE) ? 1 : 0, + 'allow_smilies' => ($flags & OPTION_FLAG_SMILIES) ? 1 : 0, + 'allow_urls' => ($flags & OPTION_FLAG_LINKS) ? 1 : 0, 'text' => $text ); } @@ -2039,11 +2363,11 @@ function make_clickable($text, $server_url = false) // matches a xxxx://aaaaa.bbb.cccc. ... $magic_url_match[] = '#(^|[\n ]|\()([\w]+:/{2}.*?([^[ \t\n\r<"\'\)&]+|&(?!lt;|quot;))*)#ie'; - $magic_url_replace[] = "'\$1<!-- m --><a href=\"\$2\" target=\"_blank\">' . ((strlen('\$2') > 55) ? substr(str_replace('&', '&', '\$2'), 0, 39) . ' ... ' . substr(str_replace('&', '&', '\$2'), -10) : '\$2') . '</a><!-- m -->'"; + $magic_url_replace[] = "'\$1<!-- m --><a href=\"\$2\">' . ((strlen('\$2') > 55) ? substr(str_replace('&', '&', '\$2'), 0, 39) . ' ... ' . substr(str_replace('&', '&', '\$2'), -10) : '\$2') . '</a><!-- m -->'"; // matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing $magic_url_match[] = '#(^|[\n ]|\()(w{3}\.[\w\-]+\.[\w\-.\~]+(?:[^[ \t\n\r<"\'\)&]+|&(?!lt;|quot;))*)#ie'; - $magic_url_replace[] = "'\$1<!-- w --><a href=\"http://\$2\" target=\"_blank\">' . ((strlen('\$2') > 55) ? substr(str_replace('&', '&', '\$2'), 0, 39) . ' ... ' . substr(str_replace('&', '&', '\$2'), -10) : '\$2') . '</a><!-- w -->'"; + $magic_url_replace[] = "'\$1<!-- w --><a href=\"http://\$2\">' . ((strlen('\$2') > 55) ? substr(str_replace('&', '&', '\$2'), 0, 39) . ' ... ' . substr(str_replace('&', '&', '\$2'), -10) : '\$2') . '</a><!-- w -->'"; // matches an email@domain type address at the start of a line, or after a space or after what might be a BBCode. $magic_url_match[] = '/(^|[\n ]|\()(' . get_preg_expression('email') . ')/ie'; @@ -2058,19 +2382,16 @@ function make_clickable($text, $server_url = false) */ function censor_text($text) { - global $censors, $user, $cache; + static $censors; + global $cache; - if (!isset($censors)) + if (!isset($censors) || !is_array($censors)) { - $censors = array(); - - if ($user->optionget('viewcensors')) - { - $cache->obtain_word_list($censors); - } + // obtain_word_list is taking care of the users censor option and the board-wide option + $censors = $cache->obtain_word_list(); } - if (sizeof($censors) && $user->optionget('viewcensors')) + if (sizeof($censors)) { return preg_replace($censors['match'], $censors['replace'], $text); } @@ -2102,6 +2423,12 @@ function parse_inline_attachments(&$text, &$attachments, &$update_count, $forum_ { global $config, $user; + if (!function_exists('display_attachments')) + { + global $phpbb_root_path, $phpEx; + include("{$phpbb_root_path}includes/functions_display.$phpEx"); + } + $attachments = display_attachments($forum_id, NULL, $attachments, $update_count, false, true); $tpl_size = sizeof($attachments); @@ -2137,9 +2464,7 @@ function extension_allowed($forum_id, $extension, &$extensions) if (!sizeof($extensions)) { global $cache; - - $extensions = array(); - $cache->obtain_attach_extensions($extensions); + $extensions = $cache->obtain_attach_extensions(); } if (!isset($extensions['_allowed_'][$extension])) @@ -2221,7 +2546,7 @@ function parse_cfg_file($filename, $lines = false) { $line = trim($line); - if (!$line || $line{0} == '#' || ($delim_pos = strpos($line, '=')) === false) + if (!$line || $line[0] == '#' || ($delim_pos = strpos($line, '=')) === false) { continue; } @@ -2242,7 +2567,7 @@ function parse_cfg_file($filename, $lines = false) { $value = ''; } - else if (($value{0} == "'" && $value{sizeof($value)-1} == "'") || ($value{0} == '"' && $value{sizeof($value)-1} == '"')) + else if (($value[0] == "'" && $value[sizeof($value) - 1] == "'") || ($value[0] == '"' && $value[sizeof($value) - 1] == '"')) { $value = substr($value, 1, sizeof($value)-2); } @@ -2367,15 +2692,25 @@ function get_backtrace() /** * This function returns a regular expression pattern for commonly used expressions -* Use with / as delimiter -* mode can be: email| +* Use with / as delimiter for email mode +* mode can be: email|bbcode_htm */ function get_preg_expression($mode) { switch ($mode) { case 'email': - return '[a-z0-9&\'\.\-_\+]+@[a-z0-9\-]+\.([a-z0-9\-]+\.)*?[a-z]+'; + return '[a-z0-9&\'\.\-_\+]+@[a-z0-9\-]+\.([a-z0-9\-]+\.)*[a-z]+'; + break; + + case 'bbcode_htm': + return array( + '#<!\-\- e \-\-><a href="mailto:(.*?)">.*?</a><!\-\- e \-\->#', + '#<!\-\- (l|m|w) \-\-><a href="(.*?)">.*?</a><!\-\- \1 \-\->#', + '#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#', + '#<!\-\- .*? \-\->#s', + '#<.*?>#s', + ); break; } @@ -2386,35 +2721,80 @@ function get_preg_expression($mode) * Truncates string while retaining special characters if going over the max length * The default max length is 60 at the moment */ -function truncate_string($string, $max_length = 60) +function truncate_string($string, $max_length = 60, $allow_reply = true) { $chars = array(); - // split the multibyte characters first - $string_ary = preg_split('#(&\#[0-9]+;)#', $string, -1, PREG_SPLIT_DELIM_CAPTURE); + $strip_reply = false; + if ($allow_reply && strpos($string, 'Re: ') === 0) + { + $strip_reply = true; + $string = substr($string, 4); + } + + $_chars = utf8_str_split(htmlspecialchars_decode($string)); + $chars = array_map('htmlspecialchars', $_chars); - // Now go through the array and split the other characters - foreach ($string_ary as $key => $value) + // Now check the length ;) + if (sizeof($chars) > $max_length) + { + // Cut off the last elements from the array + $string = implode('', array_slice($chars, 0, $max_length)); + } + + if ($strip_reply) + { + $string = 'Re: ' . $string; + } + + return $string; +} + + +/** +* 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. +* +* @return true if entry found, false if not, NULL if this function is not supported by this environment +*/ +function phpbb_checkdnsrr($host, $type = '') +{ + $type = (!$type) ? 'MX' : $type; + + if (strpos(PHP_OS, 'WIN') !== false) { - if (strpos($value, '&#') === 0) + if (!function_exists('exec')) { - $chars[] = $value; - continue; + return NULL; } - // decode html entities and put them back later - $_chars = str_split(html_entity_decode($value)); - $chars = array_merge($chars, array_map('htmlspecialchars', $_chars)); - } + @exec('nslookup -type=' . escapeshellarg($type) . ' ' . escapeshellarg($host), $output); - // Now check the length ;) - if (sizeof($chars) <= $max_length) + foreach ($output as $line) + { + if (!trim($line)) + { + continue; + } + + // Valid records begin with host name: + if (strpos($line, $host) === 0) + { + return true; + } + } + + return false; + } + else if (function_exists('checkdnsrr')) { - return $string; + return (checkdnsrr($host, $type)) ? true : false; } - // Cut off the last elements from the array - return implode('', array_slice($chars, 0, $max_length)); + return NULL; } // Handler, header and footer @@ -2489,7 +2869,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) if (!empty($config['board_contact'])) { - echo ' <p>Please notify the board administrator or webmaster : <a href="mailto:' . $config['board_contact'] . '">' . $config['board_contact'] . '</a></p>'; + echo ' <p>Please notify the board administrator or webmaster: <a href="mailto:' . $config['board_contact'] . '">' . $config['board_contact'] . '</a></p>'; } echo ' </div>'; @@ -2510,7 +2890,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) case E_USER_NOTICE: define('IN_ERROR_HANDLER', true); - + if (empty($user->data)) { $user->session_begin(); @@ -2544,8 +2924,10 @@ function msg_handler($errno, $msg_text, $errfile, $errline) ); $template->assign_vars(array( - 'MESSAGE_TITLE' => $msg_title, - 'MESSAGE_TEXT' => $msg_text) + 'MESSAGE_TITLE' => $msg_title, + 'MESSAGE_TEXT' => $msg_text, + 'S_USER_WARNING' => ($errno == E_USER_WARNING) ? true : false, + 'S_USER_NOTICE' => ($errno == E_USER_NOTICE) ? true : false) ); // We do not want the cron script to be called on error messages @@ -2620,7 +3002,7 @@ function page_header($page_title = '', $display_online_list = true) $reading_sql = " AND s.session_page LIKE '%\_f\_={$f}x%'"; // Specify escape character for MSSQL - if (SQL_LAYER == 'mssql' || SQL_LAYER == 'mssql_odbc') + if ($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') { $reading_sql .= " ESCAPE '\\'"; } @@ -2629,11 +3011,25 @@ function page_header($page_title = '', $display_online_list = true) // Get number of online guests if (!$config['load_online_guests']) { - $sql = 'SELECT COUNT(DISTINCT s.session_ip) as num_guests - FROM ' . SESSIONS_TABLE . ' s - WHERE s.session_user_id = ' . ANONYMOUS . ' - AND s.session_time >= ' . (time() - ($config['load_online_time'] * 60)) . - $reading_sql; + if ($db->sql_layer === 'sqlite') + { + $sql = 'SELECT COUNT(session_ip) as num_guests + FROM ( + SELECT DISTINCT s.session_ip + FROM ' . SESSIONS_TABLE . ' s + WHERE s.session_user_id = ' . ANONYMOUS . ' + AND s.session_time >= ' . (time() - ($config['load_online_time'] * 60)) . + $reading_sql . + ')'; + } + else + { + $sql = 'SELECT COUNT(DISTINCT s.session_ip) as num_guests + FROM ' . SESSIONS_TABLE . ' s + WHERE s.session_user_id = ' . ANONYMOUS . ' + AND s.session_time >= ' . (time() - ($config['load_online_time'] * 60)) . + $reading_sql; + } $result = $db->sql_query($sql); $guests_online = (int) $db->sql_fetchfield('num_guests'); $db->sql_freeresult($result); @@ -2658,7 +3054,12 @@ function page_header($page_title = '', $display_online_list = true) { if ($row['user_colour']) { - $row['username'] = '<b style="color:#' . $row['user_colour'] . '">' . $row['username'] . '</b>'; + $user_colour = ' style="color:#' . $row['user_colour'] . '"'; + $row['username'] = '<strong>' . $row['username'] . '</strong>'; + } + else + { + $user_colour = ''; } if ($row['user_allow_viewonline'] && $row['session_viewonline']) @@ -2668,13 +3069,21 @@ function page_header($page_title = '', $display_online_list = true) } else { - $user_online_link = '<i>' . $row['username'] . '</i>'; + $user_online_link = '<em>' . $row['username'] . '</em>'; $logged_hidden_online++; } if (($row['user_allow_viewonline'] && $row['session_viewonline']) || $auth->acl_get('u_viewonline')) { - $user_online_link = ($row['user_type'] <> USER_IGNORE) ? '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['user_id']) . '">' . $user_online_link . '</a>' : $user_online_link; + if ($row['user_type'] <> USER_IGNORE) + { + $user_online_link = '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['user_id']) . '"' . $user_colour . '>' . $user_online_link . '</a>'; + } + else + { + $user_online_link = ($user_colour) ? '<span' . $user_colour . '>' . $user_online_link . '</span>' : $user_online_link; + } + $online_userlist .= ($online_userlist != '') ? ', ' . $user_online_link : $user_online_link; } } @@ -2849,18 +3258,19 @@ function page_header($page_title = '', $display_online_list = true) 'U_RESTORE_PERMISSIONS' => ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm') : '', 'S_USER_LOGGED_IN' => ($user->data['user_id'] != ANONYMOUS) ? true : false, - 'S_BOARD_DISABLED' => ($config['board_disable'] && !defined('IN_LOGIN') && $auth->acl_gets('a_', 'm_')) ? true : false, + 'S_BOARD_DISABLED' => ($config['board_disable'] && !defined('IN_LOGIN') && !$auth->acl_gets('a_', 'm_')) ? true : false, 'S_REGISTERED_USER' => $user->data['is_registered'], 'S_IS_BOT' => $user->data['is_bot'], 'S_USER_PM_POPUP' => $user->optionget('popuppm'), - 'S_USER_LANG' => $user->data['user_lang'], + 'S_USER_LANG' => $user->lang['USER_LANG'], 'S_USER_BROWSER' => (isset($user->data['session_browser'])) ? $user->data['session_browser'] : $user->lang['UNKNOWN_BROWSER'], + 'S_USERNAME' => $user->data['username'], 'S_CONTENT_DIRECTION' => $user->lang['DIRECTION'], - 'S_CONTENT_ENCODING' => $user->lang['ENCODING'], + 'S_CONTENT_ENCODING' => 'UTF-8', 'S_CONTENT_DIR_LEFT' => $user->lang['LEFT'], 'S_CONTENT_DIR_RIGHT' => $user->lang['RIGHT'], 'S_TIMEZONE' => ($user->data['user_dst'] || ($user->data['user_id'] == ANONYMOUS && $config['board_dst'])) ? sprintf($user->lang['ALL_TIMES'], $user->lang['tz'][$tz], $user->lang['tz']['dst']) : sprintf($user->lang['ALL_TIMES'], $user->lang['tz'][$tz], ''), - 'S_DISPLAY_ONLINE_LIST' => ($config['load_online']) ? 1 : 0, + 'S_DISPLAY_ONLINE_LIST' => ($l_online_time) ? 1 : 0, 'S_DISPLAY_SEARCH' => (!$config['load_search']) ? 0 : (isset($auth) ? ($auth->acl_get('u_search') && $auth->acl_getf_global('f_search')) : 1), 'S_DISPLAY_PM' => ($config['allow_privmsg'] && $user->data['is_registered']) ? 1 : 0, 'S_DISPLAY_MEMBERLIST' => (isset($auth)) ? $auth->acl_get('u_viewprofile') : 0, @@ -2877,7 +3287,7 @@ function page_header($page_title = '', $display_online_list = true) 'T_ICONS_PATH' => "{$phpbb_root_path}{$config['icons_path']}/", 'T_RANKS_PATH' => "{$phpbb_root_path}{$config['ranks_path']}/", 'T_UPLOAD_PATH' => "{$phpbb_root_path}{$config['upload_path']}/", - 'T_STYLESHEET_LINK' => (!$user->theme['theme_storedb']) ? "{$phpbb_root_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : "{$phpbb_root_path}style.$phpEx?sid=$user->session_id&id=" . $user->theme['style_id'], + 'T_STYLESHEET_LINK' => (!$user->theme['theme_storedb']) ? "{$phpbb_root_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : "{$phpbb_root_path}style.$phpEx?sid=$user->session_id&id=" . $user->theme['style_id'] . '&lang=' . $user->data['user_lang'], 'T_STYLESHEET_NAME' => $user->theme['theme_name'], 'T_THEME_DATA' => (!$user->theme['theme_storedb']) ? '' : $user->theme['theme_data'], @@ -2886,7 +3296,7 @@ function page_header($page_title = '', $display_online_list = true) if ($config['send_encoding']) { - header('Content-type: text/html; charset=' . $user->lang['ENCODING']); + header('Content-type: text/html; charset=UTF-8'); } header('Cache-Control: private, no-cache="set-cookie"'); header('Expires: 0'); @@ -2898,7 +3308,7 @@ function page_header($page_title = '', $display_online_list = true) /** * Generate page footer */ -function page_footer() +function page_footer($run_cron = true) { global $db, $config, $template, $user, $auth, $cache, $messenger, $starttime, $phpbb_root_path, $phpEx; @@ -2936,11 +3346,11 @@ function page_footer() $template->assign_vars(array( 'DEBUG_OUTPUT' => (defined('DEBUG')) ? $debug_output : '', - 'U_ACP' => ($auth->acl_get('a_') && $user->data['is_registered']) ? "{$phpbb_root_path}adm/index.$phpEx?sid=" . $user->session_id : '') + 'U_ACP' => ($auth->acl_get('a_') && $user->data['is_registered']) ? append_sid("{$phpbb_root_path}adm/index.$phpEx", '', true, $user->session_id) : '') ); // Call cron-type script - if (!defined('IN_CRON')) + if (!defined('IN_CRON') && $run_cron) { $cron_type = ''; @@ -2975,7 +3385,7 @@ function page_footer() if ($cron_type) { - $template->assign_var('RUN_CRON_TASK', '<img src="' . $phpbb_root_path . 'cron.' . $phpEx . '?cron_type=' . $cron_type . '" width="1" height="1" />'); + $template->assign_var('RUN_CRON_TASK', '<img src="' . $phpbb_root_path . 'cron.' . $phpEx . '?cron_type=' . $cron_type . '" width="1" height="1" alt="cron" />'); } } @@ -3001,10 +3411,14 @@ function garbage_collection() } // Close our DB connection. - $db->sql_close(); + if (!empty($db)) + { + $db->sql_close(); + } } /** +* @package phpBB3 */ class bitfield { diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index 307044b9a0..c85802dafb 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -207,7 +207,7 @@ function group_select_options($group_id, $exclude_ids = false) global $db, $user, $config; $exclude_sql = ($exclude_ids !== false && sizeof($exclude_ids)) ? 'WHERE ' . $db->sql_in_set('group_id', array_map('intval', $exclude_ids), true) : ''; - $sql_and = (!$config['coppa_enable']) ? (($exclude_sql) ? ' AND ' : ' WHERE ') . "group_name NOT IN ('INACTIVE_COPPA', 'REGISTERED_COPPA')" : ''; + $sql_and = (!$config['coppa_enable']) ? (($exclude_sql) ? ' AND ' : ' WHERE ') . "group_name <> 'REGISTERED_COPPA'" : ''; $sql = 'SELECT group_id, group_name, group_type FROM ' . GROUPS_TABLE . " @@ -245,6 +245,7 @@ function get_forum_list($acl_list = 'f_list', $id_only = true, $postable_only = ORDER BY left_id ASC'; $result = $db->sql_query($sql, $expire_time); + $forum_rows = array(); while ($row = $db->sql_fetchrow($result)) { $forum_rows[] = $row; @@ -346,7 +347,7 @@ function filelist($rootdir, $dir = '', $type = 'gif|jpg|jpeg|png') $matches[$dir][] = $fname; } } - else if ($fname{0} != '.' && is_dir("$rootdir$dir$fname")) + else if ($fname[0] != '.' && is_dir("$rootdir$dir$fname")) { $matches += filelist($rootdir, "$dir$fname", $type); } @@ -511,7 +512,7 @@ function delete_topics($where_type, $where_ids, $auto_sync = true) $forum_ids[] = $row['forum_id']; $topic_ids[] = $row['topic_id']; } - $db->sql_freeresult(); + $db->sql_freeresult($result); $return['topics'] = sizeof($topic_ids); @@ -628,7 +629,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = trigger_error('NO_SUCH_SEARCH_MODULE'); } - require("{$phpbb_root_path}includes/search/$search_type.$phpEx"); + include_once("{$phpbb_root_path}includes/search/$search_type.$phpEx"); $error = false; $search = new $search_type($error); @@ -879,7 +880,7 @@ function delete_topic_shadows($max_age, $forum_id = '', $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 : ''); - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'mysql4': case 'mysqli': @@ -970,24 +971,7 @@ function update_posted_info(&$topic_ids) } unset($posted); - if (sizeof($sql_ary)) - { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $sql_ary)); - break; - - default: - foreach ($sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . TOPICS_POSTED_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } - } + $db->sql_multi_insert(TOPICS_POSTED_TABLE, $sql_ary); } /** @@ -1036,7 +1020,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $where_ids = ($where_ids) ? array((int) $where_ids) : array(); } - if ($mode == 'forum' || $mode == 'topic') + if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_approved') { if (!$where_type) { @@ -1046,7 +1030,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, else if ($where_type == 'range') { // Only check a range of topics/forums. For instance: 'topic_id BETWEEN 1 AND 60' - $where_sql = 'WHERE (' . $mode{0} . ".$where_ids)"; + $where_sql = 'WHERE (' . $mode[0] . ".$where_ids)"; $where_sql_and = $where_sql . "\n\tAND"; } else @@ -1062,7 +1046,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, // Limit the topics/forums we are syncing, use specific topic/forum IDs. // $where_type contains the field for the where clause (forum_id, topic_id) - $where_sql = 'WHERE ' . $db->sql_in_set($mode{0} . '.' . $where_type, $where_ids); + $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids); $where_sql_and = $where_sql . "\n\tAND"; } } @@ -1074,14 +1058,14 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, } // $where_type contains the field for the where clause (forum_id, topic_id) - $where_sql = 'WHERE ' . $db->sql_in_set($mode{0} . '.' . $where_type, $where_ids); + $where_sql = 'WHERE ' . $db->sql_in_set($mode[0] . '.' . $where_type, $where_ids); $where_sql_and = $where_sql . "\n\tAND"; } switch ($mode) { case 'topic_moved': - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'mysql4': case 'mysqli': @@ -1120,7 +1104,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, break; case 'topic_approved': - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'mysql4': case 'mysqli': @@ -1129,7 +1113,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $where_sql_and t.topic_first_post_id = p.post_id"; $db->sql_query($sql); break; - + default: $sql = 'SELECT t.topic_id, p.post_approved FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p @@ -1142,7 +1126,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, { $topic_ids[] = $row['topic_id']; } - $db->sql_freeresult(); + $db->sql_freeresult($result); if (!sizeof($topic_ids)) { @@ -1375,9 +1359,11 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $forum_data[$forum_id]['topics'] = 0; $forum_data[$forum_id]['topics_real'] = 0; $forum_data[$forum_id]['last_post_id'] = 0; + $forum_data[$forum_id]['last_post_subject'] = ''; $forum_data[$forum_id]['last_post_time'] = 0; $forum_data[$forum_id]['last_poster_id'] = 0; $forum_data[$forum_id]['last_poster_name'] = ''; + $forum_data[$forum_id]['last_poster_colour'] = ''; } $db->sql_freeresult($result); @@ -1386,6 +1372,8 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, break; } + $forum_ids = array_values($forum_ids); + // 2: Get topic counts for each forum $sql = 'SELECT forum_id, topic_approved, COUNT(topic_id) AS forum_topics FROM ' . TOPICS_TABLE . ' @@ -1406,16 +1394,27 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $db->sql_freeresult($result); // 3: Get post count and last_post_id for each forum - $sql = 'SELECT forum_id, COUNT(post_id) AS forum_posts, MAX(post_id) AS last_post_id - FROM ' . POSTS_TABLE . ' - WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . ' - AND post_approved = 1 - GROUP BY forum_id'; + if (sizeof($forum_ids) == 1) + { + $sql = 'SELECT COUNT(post_id) AS forum_posts, MAX(post_id) AS last_post_id + FROM ' . POSTS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . ' + AND post_approved = 1'; + } + else + { + $sql = 'SELECT forum_id, COUNT(post_id) AS forum_posts, MAX(post_id) AS last_post_id + FROM ' . POSTS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . ' + AND post_approved = 1 + GROUP BY forum_id'; + } + $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { - $forum_id = (int) $row['forum_id']; + $forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id']; $forum_data[$forum_id]['posts'] = (int) $row['forum_posts']; $forum_data[$forum_id]['last_post_id'] = (int) $row['last_post_id']; @@ -1427,7 +1426,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, // 4: Retrieve last_post infos if (sizeof($post_ids)) { - $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username + $sql = 'SELECT p.post_id, p.poster_id, p.post_subject, p.post_time, p.post_username, u.username, u.user_colour FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' AND p.poster_id = u.user_id'; @@ -1445,17 +1444,21 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, { if (isset($post_info[$data['last_post_id']])) { + $forum_data[$forum_id]['last_post_subject'] = $post_info[$data['last_post_id']]['post_subject']; $forum_data[$forum_id]['last_post_time'] = $post_info[$data['last_post_id']]['post_time']; $forum_data[$forum_id]['last_poster_id'] = $post_info[$data['last_post_id']]['poster_id']; $forum_data[$forum_id]['last_poster_name'] = ($post_info[$data['last_post_id']]['poster_id'] != ANONYMOUS) ? $post_info[$data['last_post_id']]['username'] : $post_info[$data['last_post_id']]['post_username']; + $forum_data[$forum_id]['last_poster_colour'] = $post_info[$data['last_post_id']]['user_colour']; } else { // For some reason we did not find the post in the db $forum_data[$forum_id]['last_post_id'] = 0; + $forum_data[$forum_id]['last_post_subject'] = ''; $forum_data[$forum_id]['last_post_time'] = 0; $forum_data[$forum_id]['last_poster_id'] = 0; $forum_data[$forum_id]['last_poster_name'] = ''; + $forum_data[$forum_id]['last_poster_colour'] = ''; } } } @@ -1463,7 +1466,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, } // 5: Now do that thing - $fieldnames = array('posts', 'topics', 'topics_real', 'last_post_id', 'last_post_time', 'last_poster_id', 'last_poster_name'); + $fieldnames = array('posts', 'topics', 'topics_real', 'last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour'); foreach ($forum_data as $forum_id => $row) { @@ -1473,7 +1476,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, { if ($row['forum_' . $fieldname] != $row[$fieldname]) { - if (preg_match('#name$#', $fieldname)) + if (preg_match('#(name|colour|subject)$#', $fieldname)) { $sql_ary['forum_' . $fieldname] = (string) $row[$fieldname]; } @@ -1497,7 +1500,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, case 'topic': $topic_data = $post_ids = $approved_unapproved_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array(); - $sql = 'SELECT t.topic_id, t.forum_id, t.topic_moved_id, t.topic_approved, ' . (($sync_extra) ? 't.topic_attachment, t.topic_reported, ' : '') . 't.topic_poster, t.topic_time, t.topic_replies, t.topic_replies_real, t.topic_first_post_id, t.topic_first_poster_name, t.topic_last_post_id, t.topic_last_poster_id, t.topic_last_poster_name, t.topic_last_post_time + $sql = 'SELECT t.topic_id, t.forum_id, t.topic_moved_id, t.topic_approved, ' . (($sync_extra) ? 't.topic_attachment, t.topic_reported, ' : '') . 't.topic_poster, t.topic_time, t.topic_replies, t.topic_replies_real, t.topic_first_post_id, t.topic_first_poster_name, t.topic_first_poster_colour, t.topic_last_post_id, t.topic_last_post_subject, t.topic_last_poster_id, t.topic_last_poster_name, t.topic_last_poster_colour, t.topic_last_post_time FROM ' . TOPICS_TABLE . " t $where_sql"; $result = $db->sql_query($sql); @@ -1513,6 +1516,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $topic_id = (int) $row['topic_id']; $topic_data[$topic_id] = $row; $topic_data[$topic_id]['replies_real'] = -1; + $topic_data[$topic_id]['replies'] = 0; $topic_data[$topic_id]['first_post_id'] = 0; $topic_data[$topic_id]['last_post_id'] = 0; unset($topic_data[$topic_id]['topic_id']); @@ -1532,19 +1536,8 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, // NOTE: 't.post_approved' in the GROUP BY is causing a major slowdown. $sql = 'SELECT t.topic_id, t.post_approved, COUNT(t.post_id) AS total_posts, MIN(t.post_id) AS first_post_id, MAX(t.post_id) AS last_post_id FROM ' . POSTS_TABLE . " t - $where_sql"; - - switch (SQL_LAYER) - { - case 'mssql': - case 'mssql_odbc': - $sql .= ' GROUP BY t.topic_id, t.post_approved'; - break; - - default: - $sql .= ' GROUP BY t.topic_id'; - break; - } + $where_sql + GROUP BY t.topic_id, t.post_approved"; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -1638,7 +1631,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, unset($delete_topics); } - $sql = 'SELECT p.post_id, p.topic_id, p.post_approved, p.poster_id, p.post_username, p.post_time, u.username + $sql = 'SELECT p.post_id, p.topic_id, p.post_approved, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . ' AND u.user_id = p.poster_id'; @@ -1658,13 +1651,16 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $topic_data[$topic_id]['time'] = $row['post_time']; $topic_data[$topic_id]['poster'] = $row['poster_id']; $topic_data[$topic_id]['first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; + $topic_data[$topic_id]['first_poster_colour'] = $row['user_colour']; } if ($row['post_id'] == $topic_data[$topic_id]['last_post_id']) { $topic_data[$topic_id]['last_poster_id'] = $row['poster_id']; + $topic_data[$topic_id]['last_post_subject'] = $row['post_subject']; $topic_data[$topic_id]['last_post_time'] = $row['post_time']; $topic_data[$topic_id]['last_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']; + $topic_data[$topic_id]['last_poster_colour'] = $row['user_colour']; } } $db->sql_freeresult($result); @@ -1680,7 +1676,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, unset($approved_unapproved_ids); // These are fields that will be synchronised - $fieldnames = array('time', 'replies', 'replies_real', 'poster', 'first_post_id', 'first_poster_name', 'last_post_id', 'last_post_time', 'last_poster_id', 'last_poster_name'); + $fieldnames = array('time', 'replies', 'replies_real', 'poster', 'first_post_id', 'first_poster_name', 'first_poster_colour', 'last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour'); if ($sync_extra) { @@ -1723,7 +1719,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, foreach ($fieldnames as $fieldname) { - if ($row['topic_' . $fieldname] != $row[$fieldname]) + if (isset($row[$fieldname]) && isset($row['topic_' . $fieldname]) && $row['topic_' . $fieldname] != $row[$fieldname]) { $sql_ary['topic_' . $fieldname] = $row[$fieldname]; } @@ -1746,7 +1742,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, // batch processing. if ($resync_parents && sizeof($resync_forums) && $where_type != 'range') { - sync('forum', 'forum_id', $resync_forums, true); + sync('forum', 'forum_id', array_values($resync_forums), true); } break; } @@ -1773,12 +1769,12 @@ function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync $sql_and = ''; - if (!($prune_flags & 4)) + if (!($prune_flags & FORUM_FLAG_PRUNE_ANNOUNCE)) { $sql_and .= ' AND topic_type <> ' . POST_ANNOUNCE; } - if (!($prune_flags & 8)) + if (!($prune_flags & FORUM_FLAG_PRUNE_STICKY)) { $sql_and .= ' AND topic_type <> ' . POST_STICKY; } @@ -1807,7 +1803,7 @@ function prune($forum_id, $prune_mode, $prune_date, $prune_flags = 0, $auto_sync } $db->sql_freeresult($result); - if ($prune_flags & 2) + if ($prune_flags & FORUM_FLAG_PRUNE_POLL) { $sql = 'SELECT topic_id FROM ' . TOPICS_TABLE . ' @@ -1943,7 +1939,7 @@ function cache_moderators() $cache->destroy('sql', MODERATOR_CACHE_TABLE); // Clear table - $db->sql_query(((SQL_LAYER != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . MODERATOR_CACHE_TABLE); + $db->sql_query((($db->sql_layer != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . MODERATOR_CACHE_TABLE); // We add moderators who have forum moderator permissions without an explicit ACL_NEVER setting $hold_ary = $ug_id_ary = $sql_ary = array(); @@ -1981,7 +1977,7 @@ function cache_moderators() AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . " AND ug.user_pending = 0 AND o.auth_option LIKE 'm\_%'" . - ((SQL_LAYER == 'mssql' || SQL_LAYER == 'mssql_odbc') ? " ESCAPE '\\'" : ''), + (($db->sql_layer == 'mssql' || $db->sql_layer == 'mssql_odbc') ? " ESCAPE '\\'" : ''), )); $result = $db->sql_query($sql); @@ -2010,6 +2006,12 @@ function cache_moderators() foreach ($hold_ary as $user_id => $forum_id_ary) { + // Do not continue if user does not exist + if (!isset($usernames_ary[$user_id])) + { + continue; + } + foreach ($forum_id_ary as $forum_id => $auth_ary) { $sql_ary[] = array( @@ -2051,6 +2053,12 @@ function cache_moderators() foreach ($hold_ary as $group_id => $forum_id_ary) { + // If there is no group, we do not assign it... + if (!isset($groupnames_ary[$group_id])) + { + continue; + } + foreach ($forum_id_ary as $forum_id => $auth_ary) { $flag = false; @@ -2080,24 +2088,7 @@ function cache_moderators() } } - if (sizeof($sql_ary)) - { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query('INSERT INTO ' . MODERATOR_CACHE_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $sql_ary)); - break; - - default: - foreach ($sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . MODERATOR_CACHE_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } - } + $db->sql_multi_insert(MODERATOR_CACHE_TABLE, $sql_ary); } /** @@ -2296,6 +2287,82 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id } /** +* Update foes - remove moderators and administrators from foe lists... +*/ +function update_foes() +{ + global $db, $auth; + + $perms = array(); + foreach ($auth->acl_get_list(false, array('a_', 'm_'), false) as $forum_id => $forum_ary) + { + foreach ($forum_ary as $auth_option => $user_ary) + { + $perms = array_merge($perms, $user_ary); + } + } + + if (sizeof($perms)) + { + $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' + WHERE ' . $db->sql_in_set('zebra_id', array_unique($perms)) . ' + AND foe = 1'; + $db->sql_query($sql); + } + unset($perms); +} + +/** +* Lists inactive users +*/ +function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_inactive_time DESC') +{ + global $db, $user; + + $sql = 'SELECT user_id, username, user_regdate, user_lastvisit, user_inactive_time, user_inactive_reason + FROM ' . USERS_TABLE . ' + WHERE user_type = ' . USER_INACTIVE . + (($limit_days) ? " AND user_inactive_time >= $limit_days" : '') . " + ORDER BY $sort_by"; + $result = $db->sql_query_limit($sql, $limit, $offset); + + while ($row = $db->sql_fetchrow($result)) + { + $row['inactive_reason'] = $user->lang['INACTIVE_REASON_UNKNOWN']; + switch ($row['user_inactive_reason']) + { + case INACTIVE_REGISTER: + $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REGISTER']; + break; + + case INACTIVE_PROFILE: + $row['inactive_reason'] = $user->lang['INACTIVE_REASON_PROFILE']; + break; + + case INACTIVE_MANUAL: + $row['inactive_reason'] = $user->lang['INACTIVE_REASON_MANUAL']; + break; + + case INACTIVE_REMIND: + $row['inactive_reason'] = $user->lang['INACTIVE_REASON_REMIND']; + break; + } + + $users[] = $row; + } + + $sql = 'SELECT COUNT(user_id) AS user_count + FROM ' . USERS_TABLE . ' + WHERE user_type = ' . USER_INACTIVE . + (($limit_days) ? " AND user_inactive_time >= $limit_days" : ''); + $result = $db->sql_query($sql); + $user_count = (int) $db->sql_fetchfield('user_count'); + $db->sql_freeresult($result); + + return; +} + +/** * Lists warned users */ function view_warned_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_warnings DESC') @@ -2333,7 +2400,7 @@ function get_database_size() $database_size = false; // This code is heavily influenced by a similar routine in phpMyAdmin 2.2.0 - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'mysql': case 'mysql4': @@ -2363,7 +2430,7 @@ function get_database_size() { if ($table_prefix != '') { - if (strstr($row['Name'], $table_prefix)) + if (strpos($row['Name'], $table_prefix) !== false) { $database_size += $row['Data_length'] + $row['Index_length']; } @@ -2465,7 +2532,7 @@ function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port } else if (strpos($line, '404 Not Found') !== false) { - $errstr = $user->lang['FILE_NOT_FOUND']; + $errstr = $user->lang['FILE_NOT_FOUND'] . ': ' . $filename; return false; } } @@ -2509,7 +2576,7 @@ function tidy_warnings() while ($row = $db->sql_fetchrow($result)) { $warning_list[] = $row['warning_id']; - $user_list[$row['user_id']] = isset($user_list[$row['user_id']]) ? $user_list[$row['user_id']]++ : 0; + $user_list[$row['user_id']] = isset($user_list[$row['user_id']]) ? $user_list[$row['user_id']]++ : 1; } $db->sql_freeresult($result); @@ -2541,9 +2608,46 @@ function tidy_database() { global $db; + set_config('database_last_gc', time(), true); +} + +/** +* Add permission language - this will make sure custom files will be included +*/ +function add_permission_language() +{ + global $user, $phpEx; + // First of all, our own file. + $user->add_lang('acp/permissions_phpbb'); - set_config('database_last_gc', time(), true); + $files_to_add = array(); + + // Now search in acp and mods folder for permissions_ files. + foreach (array('acp/', 'mods/') as $path) + { + $dh = opendir($user->lang_path . $path); + + if ($dh !== false) + { + while (($file = readdir($dh)) !== false) + { + if (strpos($file, 'permissions_') === 0 && strpos($file, 'permissions_phpbb') === false && substr($file, -(strlen($phpEx) + 1)) === '.' . $phpEx) + { + $files_to_add[] = $path . substr($file, 0, -(strlen($phpEx) + 1)); + } + } + closedir($dh); + } + } + + if (!sizeof($files_to_add)) + { + return false; + } + + $user->add_lang($files_to_add); + return true; } ?>
\ No newline at end of file diff --git a/phpBB/includes/functions_compress.php b/phpBB/includes/functions_compress.php index 09ad1f4e8f..93a3547e21 100644 --- a/phpBB/includes/functions_compress.php +++ b/phpBB/includes/functions_compress.php @@ -322,8 +322,7 @@ class compress_zip extends compress { $name = str_replace('\\', '/', $name); - $dtime = dechex($this->unix_to_dos_time($stat[9])); - $hexdtime = pack('H8', $dtime[6] . $dtime[7] . $dtime[4] . $dtime[5] . $dtime[2] . $dtime[3] . $dtime[0] . $dtime[1]); + $hexdtime = pack('V', $this->unix_to_dos_time($stat[9])); if ($is_dir) { @@ -479,17 +478,17 @@ class compress_tar extends compress // Run through the file and grab directory entries while ($buffer = $fzread($this->fp, 512)) { - $tmp = unpack("A6magic", substr($buffer, 257, 6)); + $tmp = unpack('A6magic', substr($buffer, 257, 6)); if (trim($tmp['magic']) == 'ustar') { - $tmp = unpack("A100name", $buffer); + $tmp = unpack('A100name', $buffer); $filename = trim($tmp['name']); - $tmp = unpack("Atype", substr($buffer, 156, 1)); + $tmp = unpack('Atype', substr($buffer, 156, 1)); $filetype = (int) trim($tmp['type']); - $tmp = unpack("A12size", substr($buffer, 124, 12)); + $tmp = unpack('A12size', substr($buffer, 124, 12)); $filesize = octdec((int) trim($tmp['size'])); if ($filetype == 5) @@ -509,12 +508,12 @@ class compress_tar extends compress { trigger_error("Could not create directory $folder"); } - @chmod("$str", 0777); + @chmod($str, 0777); } } } } - else if($filesize != 0 && ($filetype == 0 || $filetype == "\0")) + else if ($filesize != 0 && ($filetype == 0 || $filetype == "\0")) { // Write out the files if (!($fp = fopen("$dst$filename", 'wb'))) @@ -524,7 +523,7 @@ class compress_tar extends compress @chmod("$dst$filename", 0777); // Grab the file contents - fwrite($fp, $fzread($this->fp, $filesize + 512 - $filesize % 512), $filesize); + fwrite($fp, $fzread($this->fp, ($filesize + 511) &~ 511), $filesize); fclose($fp); } } @@ -543,7 +542,7 @@ class compress_tar extends compress $fzwrite = ($this->isbz && function_exists('bzwrite')) ? 'bzwrite' : (($this->isgz && @extension_loaded('zlib')) ? 'gzwrite' : 'fwrite'); // Symbolizes that there are no more files - $fzwrite($this->fp, pack("a512", "")); + $fzwrite($this->fp, str_repeat("\0", 512)); } $fzclose($this->fp); @@ -561,37 +560,37 @@ class compress_tar extends compress // This is the header data, it contains all the info we know about the file or folder that we are about to archive $header = ''; - $header .= pack("a100", $name); // file name - $header .= pack("a8", sprintf("%07o", $stat[2])); // file mode - $header .= pack("a8", sprintf("%07o", $stat[4])); // owner id - $header .= pack("a8", sprintf("%07o", $stat[5])); // group id - $header .= pack("a12", sprintf("%011o", $stat[7])); // file size - $header .= pack("a12", sprintf("%011o", $stat[9])); // last mod time + $header .= pack('a100', $name); // file name + $header .= pack('a8', sprintf("%07o", $stat[2])); // file mode + $header .= pack('a8', sprintf("%07o", $stat[4])); // owner id + $header .= pack('a8', sprintf("%07o", $stat[5])); // group id + $header .= pack('a12', sprintf("%011o", $stat[7])); // file size + $header .= pack('a12', sprintf("%011o", $stat[9])); // last mod time // Checksum $checksum = 0; for ($i = 0; $i < 148; $i++) { - $checksum += ord(substr($header, $i, 1)); + $checksum += ord($header[$i]); } // We precompute the rest of the hash, this saves us time in the loop and allows us to insert our hash without resorting to string functions $checksum += 2415 + (($is_dir) ? 53 : 0); - $header .= pack("a8", sprintf("%07o", $checksum)); // checksum - $header .= pack("a1", $typeflag); // link indicator - $header .= pack("a100", ''); // name of linked file - $header .= pack("a6", 'ustar'); // ustar indicator - $header .= pack("a2", '00'); // ustar version - $header .= pack("a32", 'Unknown'); // owner name - $header .= pack("a32", 'Unknown'); // group name - $header .= pack("a8", ''); // device major number - $header .= pack("a8", ''); // device minor number - $header .= pack("a155", ''); // filename prefix - $header .= pack("a12", ''); // end + $header .= pack('a8', sprintf("%07o", $checksum)); // checksum + $header .= pack('a1', $typeflag); // link indicator + $header .= pack('a100', ''); // name of linked file + $header .= pack('a6', 'ustar'); // ustar indicator + $header .= pack('a2', '00'); // ustar version + $header .= pack('a32', 'Unknown'); // owner name + $header .= pack('a32', 'Unknown'); // group name + $header .= pack('a8', ''); // device major number + $header .= pack('a8', ''); // device minor number + $header .= pack('a155', ''); // filename prefix + $header .= pack('a12', ''); // end // This writes the entire file in one shot. Header, followed by data and then null padded to a multiple of 512 - $fzwrite($this->fp, $header . (($stat[7] !== 0 && !$is_dir) ? $data . (($stat[7] % 512 > 0) ? str_repeat("\0", 512 - $stat[7] % 512) : '') : '')); + $fzwrite($this->fp, $header . (($stat[7] !== 0 && !$is_dir) ? $data . str_repeat("\0", (($stat[7] + 511) &~ 511) - $stat[7]) : '')); unset($data); } diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php index f6b73afa0e..cb8f963528 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -44,7 +44,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod } // Display list of active topics for this category? - $show_active = (isset($root_data['forum_flags']) && $root_data['forum_flags'] & 16) ? true : false; + $show_active = (isset($root_data['forum_flags']) && ($root_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS)) ? true : false; $sql_from = FORUMS_TABLE . ' f '; $lastread_select = $sql_lastread = ''; @@ -126,7 +126,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod } // Display active topics from this forum? - if ($show_active && $row['forum_type'] == FORUM_POST && $auth->acl_get('f_read', $forum_id) && ($row['forum_flags'] & 16)) + if ($show_active && $row['forum_type'] == FORUM_POST && $auth->acl_get('f_read', $forum_id) && ($row['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS)) { if (!isset($active_forum_ary['forum_topics'])) { @@ -180,9 +180,11 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod if ($row['forum_last_post_time'] > $forum_rows[$parent_id]['forum_last_post_time']) { $forum_rows[$parent_id]['forum_last_post_id'] = $row['forum_last_post_id']; + $forum_rows[$parent_id]['forum_last_post_subject'] = $row['forum_last_post_subject']; $forum_rows[$parent_id]['forum_last_post_time'] = $row['forum_last_post_time']; $forum_rows[$parent_id]['forum_last_poster_id'] = $row['forum_last_poster_id']; $forum_rows[$parent_id]['forum_last_poster_name'] = $row['forum_last_poster_name']; + $forum_rows[$parent_id]['forum_last_poster_colour'] = $row['forum_last_poster_colour']; $forum_rows[$parent_id]['forum_id_last_post'] = $forum_id; } else @@ -235,8 +237,10 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'FORUM_ID' => $row['forum_id'], 'FORUM_NAME' => $row['forum_name'], 'FORUM_DESC' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']), - 'FORUM_FOLDER_IMG' => ($row['forum_image']) ? '<img src="' . $phpbb_root_path . $row['forum_image'] . '" alt="' . $user->lang['FORUM_CAT'] . '" />' : '', - 'FORUM_FOLDER_IMG_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', + 'FORUM_FOLDER_IMG' => '', + 'FORUM_FOLDER_IMG_SRC' => '', + 'FORUM_IMAGE' => ($row['forum_image']) ? '<img src="' . $phpbb_root_path . $row['forum_image'] . '" alt="' . $user->lang['FORUM_CAT'] . '" />' : '', + 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', 'U_VIEWFORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id'])) ); @@ -303,16 +307,18 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod // Create last post link information, if appropriate if ($row['forum_last_post_id']) { + $last_post_subject = $row['forum_last_post_subject']; $last_post_time = $user->format_date($row['forum_last_post_time']); $last_poster = ($row['forum_last_poster_name'] != '') ? $row['forum_last_poster_name'] : $user->lang['GUEST']; + $last_poster_colour = ($row['forum_last_poster_colour']) ? '#' . $row['forum_last_poster_colour'] : ''; $last_poster_url = ($row['forum_last_poster_id'] == ANONYMOUS) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['forum_last_poster_id']); $last_post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $row['forum_id_last_post'] . '&p=' . $row['forum_last_post_id']) . '#p' . $row['forum_last_post_id']; } else { - $last_post_time = $last_poster = $last_poster_url = $last_post_url = ''; + $last_post_subject = $last_post_time = $last_poster = $last_poster_colour = $last_poster_url = $last_post_url = ''; } // Output moderator listing ... if applicable @@ -324,7 +330,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod } $l_post_click_count = ($row['forum_type'] == FORUM_LINK) ? 'CLICKS' : 'POSTS'; - $post_click_count = ($row['forum_type'] != FORUM_LINK || $row['forum_flags'] & 1) ? $row['forum_posts'] : ''; + $post_click_count = ($row['forum_type'] != FORUM_LINK || $row['forum_flags'] & FORUM_FLAG_LINK_TRACK) ? $row['forum_posts'] : ''; $template->assign_block_vars('forumrow', array( 'S_IS_CAT' => false, @@ -337,18 +343,22 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'FORUM_DESC' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']), 'TOPICS' => $row['forum_topics'], $l_post_click_count => $post_click_count, - 'FORUM_FOLDER_IMG' => ($row['forum_image']) ? '<img src="' . $phpbb_root_path . $row['forum_image'] . '" alt="' . $user->lang[$folder_alt] . '" />' : $user->img($folder_image, $folder_alt), - 'FORUM_FOLDER_IMG_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : $user->img($folder_image, $folder_alt, false, '', 'src'), + 'FORUM_FOLDER_IMG' => $user->img($folder_image, $folder_alt), + 'FORUM_FOLDER_IMG_SRC' => $user->img($folder_image, $folder_alt, false, '', 'src'), + 'FORUM_IMAGE' => ($row['forum_image']) ? '<img src="' . $phpbb_root_path . $row['forum_image'] . '" alt="' . $user->lang[$folder_alt] . '" />' : '', + 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', 'SUBFORUMS' => $subforums_list, + 'LAST_POST_SUBJECT' => censor_text($last_post_subject), 'LAST_POST_TIME' => $last_post_time, 'LAST_POSTER' => $last_poster, + 'LAST_POSTER_COLOUR' => $last_poster_colour, 'MODERATORS' => $moderators_list, 'L_SUBFORUM_STR' => $l_subforums, 'L_FORUM_FOLDER_ALT' => $folder_alt, 'L_MODERATOR_STR' => $l_moderator, - 'U_VIEWFORUM' => ($row['forum_type'] != FORUM_LINK || $row['forum_flags'] & 1) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : $row['forum_link'], + 'U_VIEWFORUM' => ($row['forum_type'] != FORUM_LINK || ($row['forum_flags'] & FORUM_FLAG_LINK_TRACK)) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : $row['forum_link'], 'U_LAST_POSTER' => $last_poster_url, 'U_LAST_POST' => $last_post_url) ); @@ -492,20 +502,6 @@ function get_forum_parents(&$forum_data) } /** -* Get topic author -*/ -function topic_topic_author(&$topic_row) -{ - global $phpEx, $phpbb_root_path, $user; - - $topic_author = ($topic_row['topic_poster'] != ANONYMOUS) ? '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $topic_row['topic_poster']) . '">' : ''; - $topic_author .= ($topic_row['topic_poster'] != ANONYMOUS) ? $topic_row['topic_first_poster_name'] : (($topic_row['topic_first_poster_name'] != '') ? $topic_row['topic_first_poster_name'] : $user->lang['GUEST']); - $topic_author .= ($topic_row['topic_poster'] != ANONYMOUS) ? '</a>' : ''; - - return $topic_author; -} - -/** * Generate topic pagination */ function topic_generate_pagination($replies, $url) @@ -660,7 +656,7 @@ function topic_status(&$topic_row, $replies, $unread_topic, &$folder_img, &$fold $folder = 'topic_read'; $folder_new = 'topic_unread'; - if ($config['hot_threshold'] && $replies >= $config['hot_threshold']) + if ($config['hot_threshold'] && $replies >= $config['hot_threshold'] && $topic_row['topic_status'] != ITEM_LOCKED) { $folder .= '_hot'; $folder_new .= '_hot'; @@ -706,14 +702,59 @@ function display_attachments($forum_id, $blockname, &$attachment_data, &$update_ 'attachment_tpl' => 'attachment.html') ); + if (!sizeof($attachment_data)) + { + return array(); + } + if (empty($extensions) || !is_array($extensions)) { - $extensions = array(); - $cache->obtain_attach_extensions($extensions); + $extensions = $cache->obtain_attach_extensions(); + } + + // Look for missing attachment informations... + $attach_ids = array(); + foreach ($attachment_data as $pos => $attachment) + { + // If is_orphan is set, we need to retrieve the attachments again... + if (!isset($attachment['extension']) && !isset($attachment['physical_filename'])) + { + $attach_ids[(int) $attachment['attach_id']] = $pos; + } + } + + if (sizeof($attach_ids)) + { + global $db; + + $attachment_data = array(); + + $sql = 'SELECT * + FROM ' . ATTACHMENTS_TABLE . ' + WHERE ' . $db->sql_in_set('attach_id', array_keys($attach_ids)); + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + if (!isset($attach_ids[$row['attach_id']])) + { + continue; + } + + $attachment_data[$attach_ids[$row['attach_id']]] = $row; + } + $db->sql_freeresult($result); + + ksort($attachment_data); } foreach ($attachment_data as $attachment) { + if (!sizeof($attachment)) + { + continue; + } + // We need to reset/empty the _file block var, because this function might be called more than once $template->destroy_block_vars('_file'); @@ -795,6 +836,8 @@ function display_attachments($forum_id, $blockname, &$attachment_data, &$update_ $download_link = (!$force_physical && $attachment['attach_id']) ? append_sid("{$phpbb_root_path}download.$phpEx", 'id=' . $attachment['attach_id'] . '&f=' . $forum_id) : $filename; + $download_link_full = (!$force_physical && $attachment['attach_id']) ? generate_board_url() . append_sid("/download.$phpEx", 'id=' . $attachment['attach_id'] . '&f=' . $forum_id) : generate_board_url() . $filename; + switch ($display_cat) { // Images @@ -823,53 +866,51 @@ function display_attachments($forum_id, $blockname, &$attachment_data, &$update_ case ATTACHMENT_CATEGORY_WM: $l_downloaded_viewed = $user->lang['VIEWED']; - // The download link is slightly different, because somehow phpBB is not able to get the correct results if called - // within the wmp object (cookies are not present). - // $download_link = (!$force_physical && $attachment['attach_id']) ? generate_board_url() . append_sid("/download.$phpEx", 'id=' . $attachment['attach_id'] . '&f=' . $forum_id, false, $user->session_id) : $filename; - // Giving the filename directly because within the wm object all variables are in local context making it impossible // to validate against a valid session (all params can differ) $download_link = $filename; $block_array += array( + 'U_FORUM' => generate_board_url(), 'S_WM_FILE' => true, ); - // Viewed/Heared File ... update the download count (download.php is not called here) + // Viewed/Heared File ... update the download count $update_count[] = $attachment['attach_id']; break; // Real Media Streams case ATTACHMENT_CATEGORY_RM: + case ATTACHMENT_CATEGORY_QUICKTIME: $l_downloaded_viewed = $user->lang['VIEWED']; $block_array += array( - 'S_RM_FILE' => true, - 'U_FORUM' => generate_board_url(), - 'ATTACH_ID' => $attachment['attach_id'], + 'S_RM_FILE' => ($display_cat == ATTACHMENT_CATEGORY_RM) ? true : false, + 'S_QUICKTIME_FILE' => ($display_cat == ATTACHMENT_CATEGORY_QUICKTIME) ? true : false, + 'U_FORUM' => generate_board_url(), + 'ATTACH_ID' => $attachment['attach_id'], ); - // Viewed/Heared File ... update the download count (download.php is not called here) + // Viewed/Heared File ... update the download count $update_count[] = $attachment['attach_id']; break; -/* // Macromedia Flash Files - case SWF_CAT: - list($width, $height) = swf_getdimension($filename); + // Macromedia Flash Files + case ATTACHMENT_CATEGORY_FLASH: + list($width, $height) = @getimagesize($filename); $l_downloaded_viewed = $user->lang['VIEWED']; - $download_link = $filename; $block_array += array( - 'S_SWF_FILE' => true, + 'S_FLASH_FILE' => true, 'WIDTH' => $width, 'HEIGHT' => $height, ); - // Viewed/Heared File ... update the download count (download.php is not called here) + // Viewed/Heared File ... update the download count $update_count[] = $attachment['attach_id']; break; -*/ + default: $l_downloaded_viewed = $user->lang['DOWNLOADED']; @@ -933,7 +974,7 @@ function display_custom_bbcodes() 'BBCODE_NAME' => "'[{$row['bbcode_tag']}]', '[/" . str_replace('=', '', $row['bbcode_tag']) . "]'", 'BBCODE_ID' => $num_predefined_bbcodes + ($i * 2), 'BBCODE_TAG' => $row['bbcode_tag'], - 'BBCODE_HELPLINE' => $row['bbcode_helpline']) + 'BBCODE_HELPLINE' => str_replace(array('&', '"', ''', '<', '>'), array('\&', '\"', '\\\'', '<', '>'), $row['bbcode_helpline'])) ); $i++; @@ -980,24 +1021,17 @@ function display_user_activity(&$userdata) global $auth, $template, $db, $user; global $phpbb_root_path, $phpEx; - // Init new auth class if user is different - if ($user->data['user_id'] != $userdata['user_id']) - { - $auth2 = new auth(); - $auth2->acl($userdata); - - $post_count_ary = $auth2->acl_getf('!f_postcount'); - } - else + // Do not display user activity for users having more than 5000 posts... + if ($userdata['user_posts'] > 5000) { - $post_count_ary = $auth->acl_getf('!f_postcount'); + return; } - $forum_read_ary = $auth->acl_getf('!f_read'); - $forum_ary = array(); // Do not include those forums the user is not having read access to... + $forum_read_ary = $auth->acl_getf('!f_read'); + foreach ($forum_read_ary as $forum_id => $not_allowed) { if ($not_allowed['f_read']) @@ -1006,44 +1040,18 @@ function display_user_activity(&$userdata) } } - // Now do not include those forums where the posts do not count... - foreach ($post_count_ary as $forum_id => $not_counted) - { - if ($not_counted['f_postcount']) - { - $forum_ary[] = (int) $forum_id; - } - } - $forum_ary = array_unique($forum_ary); - $post_count_sql = (sizeof($forum_ary)) ? 'AND ' . $db->sql_in_set('f.forum_id', $forum_ary, true) : ''; - - // Firebird does not support ORDER BY on aliased columns - // MySQL does not support ORDER BY on functions - switch (SQL_LAYER) - { - case 'firebird': - $sql = 'SELECT f.forum_id, COUNT(p.post_id) AS num_posts - FROM ' . POSTS_TABLE . ' p, ' . FORUMS_TABLE . ' f - WHERE p.poster_id = ' . $userdata['user_id'] . " - AND f.forum_id = p.forum_id - $post_count_sql - GROUP BY f.forum_id - ORDER BY COUNT(p.post_id) DESC"; - break; - - default: - $sql = 'SELECT f.forum_id, COUNT(p.post_id) AS num_posts - FROM ' . POSTS_TABLE . ' p, ' . FORUMS_TABLE . ' f - WHERE p.poster_id = ' . $userdata['user_id'] . " - AND f.forum_id = p.forum_id - $post_count_sql - GROUP BY f.forum_id - ORDER BY num_posts DESC"; - break; - } - - $result = $db->sql_query_limit($sql, 1); + $forum_sql = (sizeof($forum_ary)) ? 'AND ' . $db->sql_in_set('forum_id', $forum_ary, true) : ''; + + // Obtain active forum + $sql = 'SELECT forum_id, COUNT(post_id) AS num_posts + FROM ' . POSTS_TABLE . ' + WHERE poster_id = ' . $userdata['user_id'] . " + AND post_postcount = 1 + $forum_sql + GROUP BY forum_id + ORDER BY num_posts DESC"; + $result = $db->sql_query_limit($sql, 1, 0, 3600); $active_f_row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -1057,34 +1065,15 @@ function display_user_activity(&$userdata) $db->sql_freeresult($result); } - // Firebird does not support ORDER BY on aliased columns - // MySQL does not support ORDER BY on functions - switch (SQL_LAYER) - { - case 'firebird': - $sql = 'SELECT t.topic_id, COUNT(p.post_id) AS num_posts - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t, ' . FORUMS_TABLE . ' f - WHERE p.poster_id = ' . $userdata['user_id'] . " - AND t.topic_id = p.topic_id - AND f.forum_id = t.forum_id - $post_count_sql - GROUP BY t.topic_id - ORDER BY COUNT(p.post_id) DESC"; - break; - - default: - $sql = 'SELECT t.topic_id, COUNT(p.post_id) AS num_posts - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t, ' . FORUMS_TABLE . ' f - WHERE p.poster_id = ' . $userdata['user_id'] . " - AND t.topic_id = p.topic_id - AND f.forum_id = t.forum_id - $post_count_sql - GROUP BY t.topic_id - ORDER BY num_posts DESC"; - break; - } - - $result = $db->sql_query_limit($sql, 1); + // Obtain active topic + $sql = 'SELECT topic_id, COUNT(post_id) AS num_posts + FROM ' . POSTS_TABLE . ' + WHERE poster_id = ' . $userdata['user_id'] . " + AND post_postcount = 1 + $forum_sql + GROUP BY topic_id + ORDER BY num_posts DESC"; + $result = $db->sql_query_limit($sql, 1, 0, 3600); $active_t_row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -1127,7 +1116,8 @@ function display_user_activity(&$userdata) 'ACTIVE_TOPIC_POSTS' => ($active_t_count == 1) ? sprintf($user->lang['USER_POST'], 1) : sprintf($user->lang['USER_POSTS'], $active_t_count), 'ACTIVE_TOPIC_PCT' => sprintf($user->lang['POST_PCT_ACTIVE'], $active_t_pct), 'U_ACTIVE_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $active_f_id), - 'U_ACTIVE_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $active_t_id)) + 'U_ACTIVE_TOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $active_t_id), + 'S_SHOW_ACTIVITY' => true) ); } diff --git a/phpBB/includes/functions_jabber.php b/phpBB/includes/functions_jabber.php index d98293dd0f..726985e631 100644 --- a/phpBB/includes/functions_jabber.php +++ b/phpBB/includes/functions_jabber.php @@ -3,29 +3,29 @@ * * @package phpBB3 * @version $Id$ -* @copyright (c) 2005 phpBB Group +* @copyright (c) 2006 phpBB Group * @license http://opensource.org/licenses/gpl-license.php GNU Public License * */ /** * -* Class.Jabber.PHP v0.4 -* (c) 2002 Carlo "Gossip" Zottmann -* http://phpjabber.g-blog.net *** gossip@jabber.g-blog.net +* Class.Jabber.PHP v0.4.2 +* (c) 2004 Nathan "Fritzy" Fritz +* http://cjphp.netflint.net *** fritzy@netflint.net * -* The FULL documentation and examples for this software can be found at -* http://phpjabber.g-blog.net (not many doc comments in here, sorry) +* This is a bugfix version, specifically for those who can't get +* 0.4 to work on Jabberd2 servers. * -* last modified: 27.04.2003 13:01:53 CET -* -* Modified by members of the phpBB Group +* last modified: 24.03.2004 13:01:53 +* +* Modified by phpBB Development Team +* version: v0.4.3a * * @package phpBB3 */ class jabber { - var $encoding; var $server; var $port; var $username; @@ -37,13 +37,14 @@ class jabber var $delay_disconnect; var $stream_id; - var $roster; + + var $enable_logging; + var $log_array; var $iq_sleep_timer; var $last_ping_time; var $packet_queue; - var $subscription_queue; var $iq_version_name; var $iq_version_os; @@ -61,19 +62,24 @@ class jabber /** * Constructor */ - function jabber() + function jabber($server, $port, $username, $password, $resource) { - $this->port = '5222'; - $this->resource = NULL; - $this->packet_queue = $this->subscription_queue = array(); - $this->iq_sleep_timer = $this->delay_disconnect = 1; + $this->server = ($server) ? $server : 'localhost'; + $this->port = ($port) ? $port : '5222'; + $this->username = $username; + $this->password = $password; + $this->resource = ($resource) ? $resource : NULL; - $this->encoding = 'UTF-8'; + $this->enable_logging = true; + $this->log_array = array(); + + $this->packet_queue = array(); + $this->iq_sleep_timer = $this->delay_disconnect = 1; $this->returned_keep_alive = true; $this->txnid = 0; - $this->iq_version_name = "Class.Jabber.PHP -- http://phpjabber.g-blog.net -- by Carlo 'Gossip' Zottmann, gossip@jabber.g-blog.net"; + $this->iq_version_name = "Class.Jabber.PHP -- http://cjphp.netflint.net -- by Nathan 'Fritzy' Fritz, fritz@netflint.net"; $this->iq_version_version = '0.4'; $this->iq_version_os = $_SERVER['SERVER_SOFTWARE']; @@ -107,7 +113,7 @@ class jabber if ($this->connector->open_socket($this->server, $this->port)) { $this->send_packet("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); - $this->send_packet("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>\n"); + $this->send_packet("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); sleep(2); @@ -118,11 +124,13 @@ class jabber } else { + $this->add_to_log('ERROR: connect() #1'); return false; } } else { + $this->add_to_log('ERROR: connect() #2'); return false; } } @@ -142,55 +150,12 @@ class jabber } /** - * Cruise Control - */ - function cruise_control($seconds = -1) - { - $count = 0; - - while ($count != $seconds) - { - $this->listen(); - - do - { - $packet = $this->get_first_from_queue(); - - if ($packet) - { - $this->call_handler($packet); - } - } - while (sizeof($this->packet_queue) > 1); - - $count += 0.25; - usleep(250000); - - if ($this->last_ping_time != date('H:i')) - { - // Modified by Nathan Fritz - if ($this->returned_keep_alive == false) - { - $this->connected = false; - //EVENT: Disconnected - } - - $this->returned_keep_alive = false; - $this->keep_alive_id = 'keep_alive_' . time(); - $this->send_packet("<iq id='{$this->keep_alive_id}'/>", 'cruise_control'); - $this->last_ping_time = date('H:i'); - } - } - - return true; - } - - /** * Send authentication request */ function send_auth() { $this->auth_id = 'auth_' . md5(time() . $_SERVER['REMOTE_ADDR']); + $this->resource = ($this->resource != NULL) ? $this->resource : ('Class.Jabber.PHP ' . md5($this->auth_id)); $this->jid = "{$this->username}@{$this->server}/{$this->resource}"; // request available authentication methods @@ -200,6 +165,7 @@ class jabber // was a result returned? if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) { + // yes, now check for auth method availability in descending order (best to worst) if (isset($packet['iq']['#']['query'][0]['#']['sequence'][0]['#']) && isset($packet['iq']['#']['query'][0]['#']['token'][0]['#'])) { // auth_0k @@ -215,10 +181,16 @@ class jabber // plain text return $this->_sendauth_plaintext(); } + else + { + $this->add_to_log('ERROR: send_auth() #2 - No auth method available!'); + return false; + } } else { // no result returned + $this->add_to_log('ERROR: send_auth() #1'); return false; } } @@ -322,86 +294,15 @@ class jabber { $xml = trim($xml); - return ($this->connector->write_to_socket($xml)) ? true : false; - } - - /** - * get the transport registration fields - * method written by Steve Blinch, http://www.blitzaffe.com - */ - function transport_registration_details($transport) - { - $this->txnid++; - $packet = $this->send_iq($transport, 'get', "reg_{$this->txnid}", "jabber:iq:register", NULL, $this->jid); - - if ($packet) + if ($this->connector->write_to_socket($xml)) { - $res = array(); - - foreach ($packet['iq']['#']['query'][0]['#'] as $element => $data) - { - if ($element != 'instructions' && $element != 'key') - { - $res[] = $element; - } - } - - return $res; - } - else - { - return 3; - } - } - - /** - * register with the transport - * method written by Steve Blinch, http://www.blitzaffe.com - */ - function transport_registration($transport, $details) - { - $this->txnid++; - $packet = $this->send_iq($transport, 'get', "reg_{$this->txnid}", "jabber:iq:register", NULL, $this->jid); - - if ($packet) - { - // just in case a key was passed back from the server - $key = $this->get_info_from_iq_key($packet); - unset($packet); - - $payload = ($key) ? "<key>$key</key>\n" : ''; - foreach ($details as $element => $value) - { - $payload .= "<$element>$value</$element>\n"; - } - - $packet = $this->send_iq($transport, 'set', "reg_{$this->txnid}", "jabber:iq:register", $payload); - - if ($this->get_info_from_iq_type($packet) == 'result') - { - if (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) - { - $return_code = 1; - } - else - { - $return_code = 2; - } - } - else if ($this->get_info_from_iq_type($packet) == 'error') - { - if (isset($packet['iq']['#']['error'][0]['#'])) - { - $return_code = "Error " . $packet['iq']['#']['error'][0]['@']['code'] . ": " . $packet['iq']['#']['error'][0]['#']; - // ERROR: TransportRegistration() - } - } - - return $return_code; + $this->add_to_log('SEND: ' . $xml); + return true; } else { - return 3; + $this->add_to_log('ERROR: send_packet() #1'); + return false; } } @@ -421,11 +322,12 @@ class jabber if ($incoming != '') { + $this->add_to_log('RECV: ' . $incoming); $temp = $this->_split_incoming($incoming); - for ($a = 0, $size = sizeof($temp); $a < $size; $a++) + for ($i = 0, $size = sizeof($temp); $i < $size; $i++) { - $this->packet_queue[] = $this->xmlize($temp[$a]); + $this->packet_queue[] = $this->xmlize($temp[$i]); } } @@ -454,16 +356,15 @@ class jabber } $this->_array_xmlspecialchars($content); - $this->_array_conv_utf8($content); $xml = "<message to='$to' type='$type' id='$id'>\n"; - if (isset($content['subject']) && $content['subject']) + if (!empty($content['subject'])) { $xml .= '<subject>' . $content['subject'] . "</subject>\n"; } - if (isset($content['thread']) && $content['thread']) + if (!empty($content['thread'])) { $xml .= '<thread>' . $content['thread'] . "</thread>\n"; } @@ -472,10 +373,18 @@ class jabber $xml .= $payload; $xml .= "</message>\n"; - return ($this->send_packet($xml)) ? true : false; + if ($this->send_packet($xml)) + { + return true; + } + else + { + $this->add_to_log('ERROR: send_message() #1'); + } } else { + $this->add_to_log('ERROR: send_message() #2'); return false; } } @@ -496,7 +405,15 @@ class jabber $xml .= ($status || $show || $priority) ? "</presence>\n" : ''; - return ($this->send_packet($xml)) ? true : false; + if ($this->send_packet($xml)) + { + return true; + } + else + { + $this->add_to_log('ERROR: send_presence() #1'); + return false; + } } /** @@ -583,11 +500,63 @@ class jabber else { $this->handler_not_implemented($packet); + $this->add_to_log("ERROR: call_handler() #1 - neither method nor function $funcmeth() available"); } } } /** + * Cruise Control + */ + function cruise_control($seconds = -1) + { + $count = 0; + + while ($count != $seconds) + { + $this->listen(); + + do + { + $packet = $this->get_first_from_queue(); + + if ($packet) + { + $this->call_handler($packet); + } + } + while (sizeof($this->packet_queue) > 1); + + $count += 0.25; + usleep(250000); + + if (($this->last_ping_time + 180) < time()) + { + // Modified by Nathan Fritz + if ($this->returned_keep_alive == false) + { + $this->connected = false; + $this->add_to_log('EVENT: Disconnected'); + } + + if ($this->returned_keep_alive == true) + { + $this->connected = true; + } + + $this->returned_keep_alive = false; + + $this->keep_alive_id = 'keep_alive_' . time(); + // $this->send_packet("<iq id='{$this->keep_alive_id}'/>", 'cruise_control'); + $this->send_packet("<iq type='get' from='{$this->username}@{$this->server}/{$this->resource}' to='{$this->server}' id='{$this->keep_alive_id}'><query xmlns='jabber:iq:time' /></iq>"); + $this->last_ping_time = time(); + } + } + + return true; + } + + /** * Send iq */ function send_iq($to = NULL, $type = 'get', $id = NULL, $xmlns = NULL, $payload = NULL, $from = NULL) @@ -596,12 +565,13 @@ class jabber { unset($type); + $this->add_to_log("ERROR: send_iq() #2 - type must be 'get', 'set', 'result' or 'error'"); return false; } else if ($id && $xmlns) { $xml = "<iq type='$type' id='$id'"; - $xml .= ($to) ? " to='$to'" : ''; + $xml .= ($to) ? " to='" . htmlspecialchars($to) . "'" : ''; $xml .= ($from) ? " from='$from'" : ''; $xml .= "> <query xmlns='$xmlns'> @@ -617,17 +587,116 @@ class jabber } else { + $this->add_to_log('ERROR: send_iq() #1 - to, id and xmlns are mandatory'); return false; } } + /** + * get the transport registration fields + * method written by Steve Blinch, http://www.blitzaffe.com + */ + function transport_registration_details($transport) + { + $this->txnid++; + $packet = $this->send_iq($transport, 'get', "reg_{$this->txnid}", 'jabber:iq:register', NULL, $this->jid); + + if ($packet) + { + $res = array(); + + foreach ($packet['iq']['#']['query'][0]['#'] as $element => $data) + { + if ($element != 'instructions' && $element != 'key') + { + $res[] = $element; + } + } + + return $res; + } + else + { + return 3; + } + } + + /** + * register with the transport + * method written by Steve Blinch, http://www.blitzaffe.com + */ + function transport_registration($transport, $details) + { + $this->txnid++; + $packet = $this->send_iq($transport, 'get', "reg_{$this->txnid}", 'jabber:iq:register', NULL, $this->jid); + + if ($packet) + { + // just in case a key was passed back from the server + $key = $this->get_info_from_iq_key($packet); + unset($packet); + + $payload = ($key) ? "<key>$key</key>\n" : ''; + foreach ($details as $element => $value) + { + $payload .= "<$element>$value</$element>\n"; + } + + $packet = $this->send_iq($transport, 'set', "reg_{$this->txnid}", 'jabber:iq:register', $payload); + + if ($this->get_info_from_iq_type($packet) == 'result') + { + $return_code = (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) ? 1 : 2; + } + else if ($this->get_info_from_iq_type($packet) == 'error') + { + if (isset($packet['iq']['#']['error'][0]['#'])) + { + $return_code = 'Error ' . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; + $this->add_to_log('ERROR: transport_registration()'); + } + } + + return $return_code; + } + else + { + return 3; + } + } + + /** + * Return log + */ + function get_log() + { + if ($this->enable_logging && sizeof($this->log_array)) + { + return implode("\n\n", $this->log_array); + } + + return ''; + } + + /** + * Add information to log + */ + function add_to_log($string) + { + if ($this->enable_logging) + { + $this->log_array[] = htmlspecialchars($string); + } + } + + // ====================================================================== // private methods // ====================================================================== /** * Send auth - * @access: private + * @access private */ function _sendauth_ok($zerok_token, $zerok_sequence) { @@ -638,7 +707,7 @@ class jabber $zerok_hash = sha1($zerok_hash . $zerok_token); // repeat as often as needed - for ($a = 0; $a < $zerok_sequence; $a++) + for ($i = 0; $i < $zerok_sequence; $i++) { $zerok_hash = sha1($zerok_hash); } @@ -650,12 +719,20 @@ class jabber $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); // was a result returned? - return ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) ? true : false; + if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) + { + return true; + } + else + { + $this->add_to_log('ERROR: _sendauth_ok() #1'); + return false; + } } /** * Send auth digest - * @access: private + * @access private */ function _sendauth_digest() { @@ -666,12 +743,20 @@ class jabber $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); // was a result returned? - return ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) ? true : false; + if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) + { + return true; + } + else + { + $this->add_to_log('ERROR: _sendauth_digest() #1'); + return false; + } } /** * Send auth plain - * @access: private + * @access private */ function _sendauth_plaintext() { @@ -682,12 +767,20 @@ class jabber $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); // was a result returned? - return ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) ? true : false; + if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) + { + return true; + } + else + { + $this->add_to_log('ERROR: _sendauth_plaintext() #1'); + return false; + } } /** * Listen on socket - * @access: private + * @access private */ function _listen_incoming() { @@ -699,12 +792,18 @@ class jabber } $incoming = trim($incoming); + + if ($incoming != '') + { + $this->add_to_log('RECV: ' . $incoming); + } + return $this->xmlize($incoming); } /** * Check if connected - * @access: private + * @access private */ function _check_connected() { @@ -712,45 +811,87 @@ class jabber if (is_array($incoming_array)) { - if ($incoming_array['stream:stream']['@']['from'] == $this->server - && $incoming_array['stream:stream']['@']['xmlns'] == 'jabber:client' - && $incoming_array['stream:stream']['@']['xmlns:stream'] == 'http://etherx.jabber.org/streams') + if ($incoming_array['stream:stream']['@']['from'] == $this->server && $incoming_array['stream:stream']['@']['xmlns'] == 'jabber:client' && $incoming_array['stream:stream']['@']['xmlns:stream'] == 'http://etherx.jabber.org/streams') { $this->stream_id = $incoming_array['stream:stream']['@']['id']; - return true; + if (!empty($incoming_array['stream:stream']['#']['stream:features'][0]['#']['starttls'][0]['@']['xmlns']) && $incoming_array['stream:stream']['#']['stream:features'][0]['#']['starttls'][0]['@']['xmlns'] == 'urn:ietf:params:xml:ns:xmpp-tls') + { + return $this->_starttls(); + } + else + { + return true; + } } else { + $this->add_to_log('ERROR: _check_connected() #1'); return false; } } else { + $this->add_to_log('ERROR: _check_connected() #2'); return false; } } /** - * Split incoming packet - * @access: private + * Start TLS/SSL session if supported (PHP5.1) + * @access private */ - function _split_incoming($incoming) + function _starttls() { - $temp = preg_split('#<(message|iq|presence|stream)#', $incoming, -1, PREG_SPLIT_DELIM_CAPTURE); - $array = array(); + if (!function_exists('stream_socket_enable_crypto') || !function_exists('stream_get_meta_data') || !function_exists('socket_set_blocking')) + { + $this->add_to_log('WARNING: TLS is not available'); + return true; + } - for ($a = 1; $a < sizeof($temp); $a = $a + 2) + $this->send_packet("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n"); + sleep(2); + $incoming_array = $this->_listen_incoming(); + + if (!is_array($incoming_array)) { - $array[] = '<' . $temp[$a] . $temp[($a + 1)]; + $this->add_to_log('ERROR: _starttls() #1'); + return false; } - return $array; + if ($incoming_array['proceed']['@']['xmlns'] != 'urn:ietf:params:xml:ns:xmpp-tls') + { + $this->add_to_log('ERROR: _starttls() #2'); + return false; + } + + $meta = stream_get_meta_data($this->connector->active_socket); + socket_set_blocking($this->connector->active_socket, 1); + + if (!stream_socket_enable_crypto($this->connector->active_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) + { + socket_set_blocking($this->connector->active_socket, $meta['blocked']); + $this->add_to_log('ERROR: _starttls() #3'); + return false; + } + socket_set_blocking($this->connector->active_socket, $meta['blocked']); + + $this->send_packet("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); + $this->send_packet("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); + sleep(2); + + if (!$this->_check_connected()) + { + $this->add_to_log('ERROR: _starttls() #4'); + return false; + } + + return true; } /** * Get packet type - * @access: private + * @access private */ function _get_packet_type($packet = NULL) { @@ -764,98 +905,52 @@ class jabber } /** - * Recursively prepares the strings in an array to be used in XML data. - * @access: private + * Split incoming packet + * @access private */ - function _array_xmlspecialchars(&$array) + function _split_incoming($incoming) { - if (is_array($array)) + $temp = preg_split('#<(message|iq|presence|stream)#', $incoming, -1, PREG_SPLIT_DELIM_CAPTURE); + $array = array(); + + for ($i = 1, $size = sizeof($temp); $i < $size; $i += 2) { - foreach ($array as $k => $v) - { - if (is_array($v)) - { - $this->_array_xmlspecialchars($array[$k]); - } - else - { - $this->_xmlspecialchars($array[$k]); - } - } + $array[] = '<' . $temp[$i] . $temp[($i + 1)]; } - } - /** - * Prepares a string for usage in XML data. - * @access: private - */ - function _xmlspecialchars(&$string) - { - // we only have a few entities in xml - $string = str_replace(array('&', '>', '<', '"', '\''), array('&', '>', '<', '"', '''), $string); + return $array; } /** - * Recursively converts all elements in an array to UTF-8 from the encoding stored in {@link encoding the encoding attribute}. - * @access: private + * Recursively prepares the strings in an array to be used in XML data. + * @access private */ - function _array_conv_utf8(&$array) + function _array_xmlspecialchars(&$array) { - // no need to do anything if the encoding already is UTF-8 - if (strtoupper($this->encoding) == 'UTF-8') - { - return true; - } - if (is_array($array)) { foreach ($array as $k => $v) { if (is_array($v)) { - $this->_array_conv_utf8($array[$k]); + $this->_array_xmlspecialchars($array[$k]); } else { - $this->_conv_utf8($array[$k]); + $this->_xmlspecialchars($array[$k]); } } } } /** - * Converts a string to utf8 encoding. - * - * @param string $string has to have the same encoding as {@link encoding the encoding attribute} is set to. - * - * @return boolean True on success, false on failure. - * - * @access: private + * Prepares a string for usage in XML data. + * @access private */ - function _conv_utf8(&$string) + function _xmlspecialchars(&$string) { - // no need to do anything if the encoding already is UTF-8 - if (strtoupper($this->encoding) == 'UTF-8') - { - return true; - } - - // first try iconv then mb_convert_encoding and as a last fall back try recode_string - if (function_exists('iconv') && (($string = iconv($this->encoding, 'UTF-8', $string)) !== false)) - { - return true; - } - elseif (function_exists('mb_convert_encoding') && (($string = mb_convert_encoding($string, 'UTF-8', $this->encoding)) !== false)) - { - return true; - } - elseif (function_exists('recode_string') && (($string = recode_string($this->encoding . '..UTF-8', $string)) !== false)) - { - return true; - } - - // if everything fails we will just have to live with what we have, good luck! - return false; + // we only have a few entities in xml + $string = str_replace(array('&', '>', '<', '"', '\''), array('&', '>', '<', '"', '''), $string); } // ====================================================================== @@ -911,6 +1006,14 @@ class jabber } /** + * Get info from message (xmlns) + */ + function get_info_from_message_xmlns($packet = NULL) + { + return (is_array($packet)) ? $packet['message']['#']['x'] : false; + } + + /** * Get info from message (error) */ function get_info_from_message_error($packet = NULL) @@ -969,19 +1072,48 @@ class jabber // ====================================================================== /** - * return message (from) + * Message type normal */ function handler_message_normal($packet) { $from = $packet['message']['@']['from']; + $this->add_to_log("EVENT: Message (type normal) from $from"); + } + + /** + * Message type chat + */ + function handler_message_chat($packet) + { + $from = $packet['message']['@']['from']; + $this->add_to_log("EVENT: Message (type chat) from $from"); + } + + /** + * Message type groupchat + */ + function handler_message_groupchat($packet) + { + $from = $packet['message']['@']['from']; + $this->add_to_log("EVENT: Message (type groupchat) from $from"); + } + + /** + * Message type headline + */ + function handler_message_headline($packet) + { + $from = $packet['message']['@']['from']; + $this->add_to_log("EVENT: Message (type headline) from $from"); } /** - * return error (from) + * Message type error */ function handler_message_error($packet) { $from = $packet['message']['@']['from']; + $this->add_to_log("EVENT: Message (type error) from $from"); } // ====================================================================== @@ -989,6 +1121,42 @@ class jabber // ====================================================================== /** + * application version updates + */ + function handler_iq_jabber_iq_autoupdate($packet) + { + $from = $this->get_info_from_iq_from($packet); + $id = $this->get_info_from_iq_id($packet); + + $this->send_error($from, $id, 501); + $this->add_to_log("EVENT: jabber:iq:autoupdate from $from"); + } + + /** + * interactive server component properties + */ + function handler_iq_jabber_iq_agent($packet) + { + $from = $this->get_info_from_iq_from($packet); + $id = $this->get_info_from_iq_id($packet); + + $this->send_error($from, $id, 501); + $this->add_to_log("EVENT: jabber:iq:agent from $from"); + } + + /** + * method to query interactive server components + */ + function handler_iq_jabber_iq_agents($packet) + { + $from = $this->get_info_from_iq_from($packet); + $id = $this->get_info_from_iq_id($packet); + + $this->send_error($from, $id, 501); + $this->add_to_log("EVENT: jabber:iq:agents from $from"); + } + + /** * simple client authentication */ function handler_iq_jabber_iq_auth($packet) @@ -997,6 +1165,31 @@ class jabber $id = $this->get_info_from_iq_id($packet); $this->send_error($from, $id, 501); + $this->add_to_log("EVENT: jabber:iq:auth from $from"); + } + + /** + * out of band data + */ + function handler_iq_jabber_iq_oob($packet) + { + $from = $this->get_info_from_iq_from($packet); + $id = $this->get_info_from_iq_id($packet); + + $this->send_error($from, $id, 501); + $this->add_to_log("EVENT: jabber:iq:oob from $from"); + } + + /** + * method to store private data on the server + */ + function handler_iq_jabber_iq_private($packet) + { + $from = $this->get_info_from_iq_from($packet); + $id = $this->get_info_from_iq_id($packet); + + $this->send_error($from, $id, 501); + $this->add_to_log("EVENT: jabber:iq:private from $from"); } /** @@ -1008,19 +1201,89 @@ class jabber $id = $this->get_info_from_iq_id($packet); $this->send_error($from, $id, 501); + $this->add_to_log("EVENT: jabber:iq:register from $from"); + } + + /** + * client roster management + */ + function handler_iq_jabber_iq_roster($packet) + { + $from = $this->get_info_from_iq_from($packet); + $id = $this->get_info_from_iq_id($packet); + + $this->send_error($from, $id, 501); + $this->add_to_log("EVENT: jabber:iq:roster from $from"); + } + + /** + * method for searching a user database + */ + function handler_iq_jabber_iq_search($packet) + { + $from = $this->get_info_from_iq_from($packet); + $id = $this->get_info_from_iq_id($packet); + + $this->send_error($from, $id, 501); + $this->add_to_log("EVENT: jabber:iq:search from $from"); } /** - * keepalive method, added by Nathan Fritz + * method for requesting the current time */ - function handler_iq_($packet) + function handler_iq_jabber_iq_time($packet) { if ($this->keep_alive_id == $this->get_info_from_iq_id($packet)) { $this->returned_keep_alive = true; + $this->connected = true; + + $this->add_to_log('EVENT: Keep-Alive returned, connection alive.'); + } + + $type = $this->get_info_from_iq_type($packet); + $from = $this->get_info_from_iq_from($packet); + $id = $this->get_info_from_iq_id($packet); + $id = ($id != '') ? $id : 'time_' . time(); + + if ($type == 'get') + { + $payload = '<utc>' . gmdate("Ydm\TH:i:s") . '</utc><tz>' . date('T') . '</tz><display>' . date("Y/d/m h:i:s A") . '</display>'; + $this->send_iq($from, 'result', $id, 'jabber:iq:time', $payload); } + + $this->add_to_log("EVENT: jabber:iq:time (type $type) from $from"); + } + + /** + */ + function handler_iq_error($packet) + { + // We'll do something with these later. This is a placeholder so that errors don't bounce back and forth. + } + + /** + * method for requesting version + */ + function handler_iq_jabber_iq_version($packet) + { + $type = $this->get_info_from_iq_type($packet); + $from = $this->get_info_from_iq_from($packet); + $id = $this->get_info_from_iq_id($packet); + $id = ($id != '') ? $id : 'version_' . time(); + + if ($type == 'get') + { + $payload = "<name>{$this->iq_version_name}</name> + <os>{$this->iq_version_os}</os> + <version>{$this->iq_version_version}</version>"; + + //$this->SendIq($from, 'result', $id, "jabber:iq:version", $payload); + } + + $this->add_to_log("EVENT: jabber:iq:version (type $type) from $from -- DISABLED"); } - + // ====================================================================== // Generic handlers // ====================================================================== @@ -1035,28 +1298,34 @@ class jabber $id = call_user_func(array(&$this, 'get_info_from_' . strtolower($packet_type) . '_id'), $packet); $this->send_error($from, $id, 501); + $this->add_to_log("EVENT: Unrecognized <$packet_type/> from $from"); } + // ====================================================================== // Third party code // m@d pr0ps to the coders ;) + // ====================================================================== /** * xmlize() - * (c) Hans Anderson / http://www.hansanderson.com/php/xml/ + * @author Hans Anderson + * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/ */ - function xmlize($data) + function xmlize($data, $skip_white = 1, $encoding = 'UTF-8') { + $data = trim($data); + $vals = $index = $array = array(); - $parser = @xml_parser_create(); - @xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); - @xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); - @xml_parse_into_struct($parser, $data, $vals, $index); - @xml_parser_free($parser); + $parser = xml_parser_create($encoding); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); + xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, $skip_white); + xml_parse_into_struct($parser, $data, $vals, $index); + xml_parser_free($parser); $i = 0; - $tagname = $vals[$i]['tag']; - $array[$tagname]['@'] = $vals[$i]['attributes']; + + $array[$tagname]['@'] = (isset($vals[$i]['attributes'])) ? $vals[$i]['attributes'] : array(); $array[$tagname]['#'] = $this->_xml_depth($vals, $i); return $array; @@ -1064,47 +1333,51 @@ class jabber /** * _xml_depth() - * (c) Hans Anderson / http://www.hansanderson.com/php/xml/ + * @author Hans Anderson + * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/ */ function _xml_depth($vals, &$i) { $children = array(); - if (isset($vals[$i]['value']) && $vals[$i]['value']) + if (isset($vals[$i]['value'])) { - array_push($children, trim($vals[$i]['value'])); + array_push($children, $vals[$i]['value']); } while (++$i < sizeof($vals)) { switch ($vals[$i]['type']) { - case 'cdata': - array_push($children, trim($vals[$i]['value'])); - break; + case 'open': - case 'complete': - $tagname = $vals[$i]['tag']; + $tagname = (isset($vals[$i]['tag'])) ? $vals[$i]['tag'] : ''; $size = (isset($children[$tagname])) ? sizeof($children[$tagname]) : 0; - $children[$tagname][$size]['#'] = (isset($vals[$i]['value'])) ? trim($vals[$i]['value']) : ''; - if (isset($vals[$i]['attributes']) && $vals[$i]['attributes']) + + if (isset($vals[$i]['attributes'])) { $children[$tagname][$size]['@'] = $vals[$i]['attributes']; } + + $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i); + break; - case 'open': + case 'cdata': + array_push($children, $vals[$i]['value']); + break; + + case 'complete': + $tagname = $vals[$i]['tag']; $size = (isset($children[$tagname])) ? sizeof($children[$tagname]) : 0; - if ($vals[$i]['attributes']) + $children[$tagname][$size]['#'] = (isset($vals[$i]['value'])) ? $vals[$i]['value'] : array(); + + if (isset($vals[$i]['attributes'])) { $children[$tagname][$size]['@'] = $vals[$i]['attributes']; - $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i); - } - else - { - $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i); } + break; case 'close': @@ -1117,8 +1390,9 @@ class jabber } /** - * traverse_xmlize() - * (c) acebone@f2s.com, a HUGE help! + * TraverseXMLize() + * @author acebone@f2s.com + * @copyright acebone@f2s.com, a HUGE help! */ function traverse_xmlize($array, $arr_name = 'array', $level = 0) { @@ -1127,7 +1401,7 @@ class jabber echo '<pre>'; } - while (list($key, $val) = @each($array)) + foreach ($array as $key => $val) { if (is_array($val)) { @@ -1135,7 +1409,7 @@ class jabber } else { - echo '$' . $arr_name . '[' . $key . '] = "' . $val . "\"\n"; + $GLOBALS['traverse_array'][] = '$' . $arr_name . '[' . $key . '] = "' . $val . "\"\n"; } } @@ -1143,117 +1417,13 @@ class jabber { echo '</pre>'; } - } -} - -/** -* make_xml -* Currently not in use -* @package phpBB3 -class make_xml extends jabber -{ - var $nodes; - - function make_xml() - { - $nodes = array(); - } - - function add_packet_details($string, $value = NULL) - { - if (preg_match('#\(([0-9]*)\)$#i', $string)) - { - $string .= '/["#"]'; - } - - $temp = @explode('/', $string); - - for ($a = 0, $size = sizeof($temp); $a < $size; $a++) - { - $temp[$a] = preg_replace('#^[@]{1}([a-z0-9_]*)$#i', '["@"]["\1"]', $temp[$a]); - $temp[$a] = preg_replace('#^([a-z0-9_]*)\(([0-9]*)\)$/i', '["\1"][\2]', $temp[$a]); - $temp[$a] = preg_replace('#^([a-z0-9_]*)$#i', '["\1"]', $temp[$a]); - } - - $node = implode('', $temp); - - // Yeahyeahyeah, I know it's ugly... get over it. ;) - echo '$this->nodes' . $node . ' = "' . htmlspecialchars($value) . '";<br/>'; - eval('$this->nodes' . $node . ' = "' . htmlspecialchars($value) . '";'); - } - - function build_packet($array = NULL) - { - if (!$array) - { - $array = $this->nodes; - } - - if (is_array($array)) - { - array_multisort($array, SORT_ASC, SORT_STRING); - - foreach ($array as $key => $value) - { - if (is_array($value) && $key == '@') - { - foreach ($value as $subkey => $subvalue) - { - $subvalue = htmlspecialchars($subvalue); - $text .= " $subkey='$subvalue'"; - } - - $text .= ">\n"; - - } - else if ($key == '#') - { - $text .= htmlspecialchars($value); - } - else if (is_array($value)) - { - for ($a = 0, $size = sizeof($value); $a < $size; $a++) - { - $text .= "<$key"; - - if (!$this->_preg_grep_keys('#^@#', $value[$a])) - { - $text .= '>'; - } - - $text .= $this->build_packet($value[$a]); - $text .= "</$key>\n"; - } - } - else - { - $value = htmlspecialchars($value); - $text .= "<$key>$value</$key>\n"; - } - } - - return $text; - } - - return false; - } - function _preg_grep_keys($pattern, $array) - { - foreach ($array as $key => $val) - { - if (preg_match($pattern, $key)) - { - $newarray[$key] = $val; - } - } - return (is_array($newarray)) ? $newarray : false; + return 1; } } -*/ /** -* connector +* Jabber Connector * @package phpBB3 */ class cjp_standard_connector @@ -1265,7 +1435,21 @@ class cjp_standard_connector */ function open_socket($server, $port) { - if ($this->active_socket = @fsockopen($server, $port, $err, $err2, 5)) + if (function_exists('dns_get_record')) + { + $record = dns_get_record("_xmpp-client._tcp.$server", DNS_SRV); + + if (!empty($record)) + { + $server = $record[0]['target']; + $port = $record[0]['port']; + } + } + + $errno = 0; + $errstr = ''; + + if ($this->active_socket = @fsockopen($server, $port, $errno, $errstr, 5)) { @socket_set_blocking($this->active_socket, 0); @socket_set_timeout($this->active_socket, 31536000); @@ -1300,9 +1484,7 @@ class cjp_standard_connector function read_from_socket($chunksize) { $buffer = @fread($this->active_socket, $chunksize); - - //$buffer = (STRIP) ? stripslashes($buffer) : $buffer; - //@set_magic_quotes_runtime(get_magic_quotes_gpc()); + $buffer = (STRIP) ? stripslashes($buffer) : $buffer; return $buffer; } diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index 052f372443..75eda9b10c 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -14,7 +14,7 @@ */ class messenger { - var $vars, $msg, $extra_headers, $replyto, $from, $subject, $encoding; + var $vars, $msg, $extra_headers, $replyto, $from, $subject; var $addresses = array(); var $mail_priority = MAIL_NORMAL_PRIORITY; @@ -44,8 +44,8 @@ class messenger */ function reset() { - $this->addresses = array(); - $this->vars = $this->msg = $this->extra_headers = $this->replyto = $this->from = $this->encoding = ''; + $this->addresses = $this->extra_headers = array(); + $this->vars = $this->msg = $this->replyto = $this->from = ''; $this->mail_priority = MAIL_NORMAL_PRIORITY; } @@ -118,7 +118,7 @@ class messenger */ function headers($headers) { - $this->extra_headers .= trim($headers) . "\n"; + $this->extra_headers[] = trim($headers); } /** @@ -189,24 +189,17 @@ class messenger { global $config, $user; + // We add some standard variables we always use, no need to specify them always + $this->vars['U_BOARD'] = (!isset($this->vars['U_BOARD'])) ? generate_board_url() : $this->vars['U_BOARD']; + $this->vars['EMAIL_SIG'] = (!isset($this->vars['EMAIL_SIG'])) ? str_replace('<br />', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])) : $this->vars['EMAIL_SIG']; + $this->vars['SITENAME'] = (!isset($this->vars['SITENAME'])) ? htmlspecialchars_decode($config['sitename']) : $this->vars['SITENAME']; + // Escape all quotes, else the eval will fail. $this->msg = str_replace ("'", "\'", $this->msg); - $this->msg = preg_replace('#\{([a-z0-9\-_]*?)\}#is', "' . $\\1 . '", $this->msg); - - // Set vars - foreach ($this->vars as $key => $val) - { - $$key = $val; - } + $this->msg = preg_replace('#\{([a-z0-9\-_]*?)\}#is', "' . ((isset(\$this->vars['\\1'])) ? \$this->vars['\\1'] : '') . '", $this->msg); eval("\$this->msg = '$this->msg';"); - // Clear vars - foreach ($this->vars as $key => $val) - { - unset($$key); - } - // We now try and pull a subject from the email body ... if it exists, // do this here because the subject may contain a variable $drop_header = ''; @@ -221,16 +214,6 @@ class messenger $this->subject = (($this->subject != '') ? $this->subject : $user->lang['NO_SUBJECT']); } - if (preg_match('#^(Charset:(.*?))$#m', $this->msg, $match)) - { - $this->encoding = (trim($match[2]) != '') ? trim($match[2]) : trim($user->lang['ENCODING']); - $drop_header .= '[\r\n]*?' . preg_quote($match[1], '#'); - } - else - { - $this->encoding = trim($user->lang['ENCODING']); - } - if ($drop_header) { $this->msg = trim(preg_replace('#' . $drop_header . '#s', '', $this->msg)); @@ -291,6 +274,53 @@ class messenger } /** + * Return email header + */ + function build_header($to, $cc, $bcc) + { + global $config; + + $headers = array(); + + $headers[] = 'From: ' . $this->from; + + if ($cc) + { + $headers[] = 'Cc: ' . $cc; + } + + if ($bcc) + { + $headers[] = 'Bcc: ' . $bcc; + } + + $headers[] = 'Reply-To: ' . $this->replyto; + $headers[] = 'Return-Path: <' . $config['board_email'] . '>'; + $headers[] = 'Sender: <' . $config['board_email'] . '>'; + $headers[] = 'MIME-Version: 1.0'; + $headers[] = 'Message-ID: <' . md5(unique_id(time())) . '@' . $config['server_name'] . '>'; + $headers[] = 'Date: ' . gmdate('D, d M Y H:i:s T', time()); + $headers[] = 'Content-Type: text/plain; charset=UTF-8'; // format=flowed + $headers[] = 'Content-Transfer-Encoding: 8bit'; // 7bit + + $headers[] = 'X-Priority: ' . $this->mail_priority; + $headers[] = 'X-MSMail-Priority: ' . (($this->mail_priority == MAIL_LOW_PRIORITY) ? 'Low' : (($this->mail_priority == MAIL_NORMAL_PRIORITY) ? 'Normal' : 'High')); + $headers[] = 'X-Mailer: PhpBB3'; + $headers[] = 'X-MimeOLE: phpBB3'; + $headers[] = 'X-phpBB-Origin: phpbb://' . str_replace(array('http://', 'https://'), array('', ''), generate_board_url()); + + // We use \n here instead of \r\n because our smtp mailer is adjusting it to \r\n automatically, whereby the php mail function only works + // if using \n. + + if (sizeof($this->extra_headers)) + { + $headers[] = implode("\n", $this->extra_headers); + } + + return implode("\n", $headers); + } + + /** * Send out emails */ function msg_email() @@ -313,8 +343,18 @@ class messenger $use_queue = true; } - $to = $cc = $bcc = ''; + if (empty($this->replyto)) + { + $this->replyto = '<' . $config['board_email'] . '>'; + } + + if (empty($this->from)) + { + $this->from = '<' . $config['board_email'] . '>'; + } + // Build to, cc and bcc strings + $to = $cc = $bcc = ''; foreach ($this->addresses as $type => $address_ary) { if ($type == 'im') @@ -324,40 +364,14 @@ class messenger foreach ($address_ary as $which_ary) { - $$type .= (($$type != '') ? ', ' : '') . (($which_ary['name'] != '') ? '"' . mail_encode($which_ary['name'], $this->encoding) . '" <' . $which_ary['email'] . '>' : $which_ary['email']); + $$type .= (($$type != '') ? ', ' : '') . (($which_ary['name'] != '') ? '"' . mail_encode($which_ary['name']) . '" <' . $which_ary['email'] . '>' : $which_ary['email']); } } - if (empty($this->replyto)) - { - $this->replyto = '<' . $config['board_email'] . '>'; - } - - if (empty($this->from)) - { - $this->from = '<' . $config['board_email'] . '>'; - } - // Build header - $headers = 'From: ' . $this->from . "\n"; - $headers .= ($cc != '') ? "Cc: $cc\n" : ''; - $headers .= ($bcc != '') ? "Bcc: $bcc\n" : ''; - $headers .= 'Reply-to: ' . $this->replyto . "\n"; - $headers .= 'Return-Path: <' . $config['board_email'] . ">\n"; - $headers .= 'Sender: <' . $config['board_email'] . ">\n"; - $headers .= "MIME-Version: 1.0\n"; - $headers .= 'Message-ID: <' . md5(unique_id(time())) . "@" . $config['server_name'] . ">\n"; - $headers .= 'Date: ' . gmdate('D, d M Y H:i:s T', time()) . "\n"; - $headers .= "Content-type: text/plain; charset={$this->encoding}\n"; - $headers .= "Content-transfer-encoding: 8bit\n"; - $headers .= "X-Priority: {$this->mail_priority}\n"; - $headers .= 'X-MSMail-Priority: ' . (($this->mail_priority == MAIL_LOW_PRIORITY) ? 'Low' : (($this->mail_priority == MAIL_NORMAL_PRIORITY) ? 'Normal' : 'High')) . "\n"; - $headers .= "X-Mailer: PhpBB3\n"; - $headers .= "X-MimeOLE: phpBB3\n"; - $headers .= "X-phpBB-Origin: phpbb://" . str_replace(array('http://', 'https://'), array('', ''), generate_board_url()) . "\n"; - $headers .= ($this->extra_headers != '') ? $this->extra_headers : ''; - - // Send message ... removed $this->encode() from subject for time being + $headers = $this->build_header($to, $cc, $bcc); + + // Send message ... if (!$use_queue) { $mail_to = ($to == '') ? 'Undisclosed-Recipient:;' : $to; @@ -365,11 +379,11 @@ class messenger if ($config['smtp_delivery']) { - $result = smtpmail($this->addresses, $this->subject, wordwrap($this->msg), $err_msg, $this->encoding, $headers); + $result = smtpmail($this->addresses, mail_encode($this->subject), wordwrap($this->msg), $err_msg, $headers); } else { - $result = @$config['email_function_name']($mail_to, $this->subject, implode("\n", preg_split("/\r?\n/", wordwrap($this->msg))), $headers); + $result = @$config['email_function_name']($mail_to, mail_encode($this->subject), implode("\n", preg_split("/\r?\n/", wordwrap($this->msg))), $headers); } if (!$result) @@ -387,7 +401,6 @@ class messenger 'addresses' => $this->addresses, 'subject' => $this->subject, 'msg' => $this->msg, - 'encoding' => $this->encoding, 'headers' => $headers) ); } @@ -428,14 +441,7 @@ class messenger if (!$use_queue) { include_once($phpbb_root_path . 'includes/functions_jabber.'.$phpEx); - $this->jabber = new jabber; - - $this->jabber->server = $config['jab_host']; - $this->jabber->port = ($config['jab_port']) ? $config['jab_port'] : 5222; - $this->jabber->username = $config['jab_username']; - $this->jabber->password = $config['jab_password']; - $this->jabber->resource = ($config['jab_resource']) ? $config['jab_resource'] : ''; - $this->jabber->encoding = $this->encoding; + $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], $config['jab_password'], $config['jab_resource']); if (!$this->jabber->connect()) { @@ -548,7 +554,7 @@ class queue } $package_size = $data_ary['package_size']; - $num_items = (sizeof($data_ary['data']) < $package_size) ? sizeof($data_ary['data']) : $package_size; + $num_items = (!$package_size || sizeof($data_ary['data']) < $package_size) ? sizeof($data_ary['data']) : $package_size; switch ($object) { @@ -569,13 +575,7 @@ class queue } include_once($phpbb_root_path . 'includes/functions_jabber.'.$phpEx); - $this->jabber = new jabber; - - $this->jabber->server = $config['jab_host']; - $this->jabber->port = ($config['jab_port']) ? $config['jab_port'] : 5222; - $this->jabber->username = $config['jab_username']; - $this->jabber->password = $config['jab_password']; - $this->jabber->resource = ($config['jab_resource']) ? $config['jab_resource'] : ''; + $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], $config['jab_password'], $config['jab_resource']); if (!$this->jabber->connect()) { @@ -607,7 +607,7 @@ class queue $err_msg = ''; $to = (!$to) ? 'Undisclosed-Recipient:;' : $to; - $result = ($config['smtp_delivery']) ? smtpmail($addresses, $subject, wordwrap($msg), $err_msg, $encoding, $headers) : @$config['email_function_name']($to, $subject, implode("\n", preg_split("/\r?\n/", wordwrap($msg))), $headers); + $result = ($config['smtp_delivery']) ? smtpmail($addresses, mail_encode($subject), wordwrap($msg), $err_msg, $headers) : @$config['email_function_name']($to, mail_encode($subject), implode("\n", preg_split("/\r?\n/", wordwrap($msg))), $headers); if (!$result) { @@ -615,14 +615,19 @@ class queue $message = 'Method: [ ' . (($config['smtp_delivery']) ? 'SMTP' : 'PHP') . ' ]<br /><br />' . $err_msg . '<br /><br /><u>CALLING PAGE</u><br /><br />' . ((!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']); messenger::error('EMAIL', $message); - continue 3; + continue 2; } break; case 'jabber': foreach ($addresses as $address) { - $this->jabber->send_message($address, 'normal', NULL, array('body' => $msg)); + if ($this->jabber->send_message($address, 'normal', NULL, array('body' => $msg)) === false) + { + $message = 'Method: [ JABBER ]<br /><br />' . $this->jabber->get_log() . '<br /><br /><u>CALLING PAGE</u><br /><br />' . ((!empty($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']); + messenger::error('JABBER', $message); + continue 3; + } } break; } @@ -706,7 +711,7 @@ class queue /** * Format array - * @access: private + * @access private */ function format_array($array) { @@ -739,7 +744,7 @@ class queue /** * Replacement or substitute for PHP's mail command */ -function smtpmail($addresses, $subject, $message, &$err_msg, $encoding, $headers = '') +function smtpmail($addresses, $subject, $message, &$err_msg, $headers = '') { global $config, $user; @@ -790,10 +795,13 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $encoding, $headers $mail_rcpt = $mail_to = $mail_cc = array(); // Build correct addresses for RCPT TO command and the client side display (TO, CC) - foreach ($addresses['to'] as $which_ary) + if (isset($addresses['to']) && sizeof($addresses['to'])) { - $mail_to[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name']), $encoding) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>'; - $mail_rcpt['to'][] = '<' . trim($which_ary['email']) . '>'; + foreach ($addresses['to'] as $which_ary) + { + $mail_to[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>'; + $mail_rcpt['to'][] = '<' . trim($which_ary['email']) . '>'; + } } if (isset($addresses['bcc']) && sizeof($addresses['bcc'])) @@ -808,16 +816,18 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $encoding, $headers { foreach ($addresses['cc'] as $which_ary) { - $mail_cc[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name']), $encoding) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>'; + $mail_cc[] = ($which_ary['name'] != '') ? mail_encode(trim($which_ary['name'])) . ' <' . trim($which_ary['email']) . '>' : '<' . trim($which_ary['email']) . '>'; $mail_rcpt['cc'][] = '<' . trim($which_ary['email']) . '>'; } } - $smtp = new smtp_class; + $smtp = new smtp_class(); $errno = 0; $errstr = ''; + $smtp->add_backtrace('Connecting to ' . $config['smtp_host'] . ':' . $config['smtp_port']); + // Ok we have error checked as much as we can to this point let's get on it already. if (!$smtp->socket = @fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 20)) { @@ -828,14 +838,14 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $encoding, $headers // Wait for reply if ($err_msg = $smtp->server_parse('220', __LINE__)) { - $smtp->close_session(); + $smtp->close_session($err_msg); return false; } // Let me in. This function handles the complete authentication process if ($err_msg = $smtp->log_into_server($config['smtp_host'], $config['smtp_username'], $config['smtp_password'], $config['smtp_auth_method'])) { - $smtp->close_session(); + $smtp->close_session($err_msg); return false; } @@ -844,7 +854,7 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $encoding, $headers $smtp->server_send('MAIL FROM:<' . $config['board_email'] . '>'); if ($err_msg = $smtp->server_parse('250', __LINE__)) { - $smtp->close_session(); + $smtp->close_session($err_msg); return false; } @@ -867,7 +877,7 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $encoding, $headers // We continue... if users are not resolved we do not care if ($smtp->numeric_response_code != 550) { - $smtp->close_session(); + $smtp->close_session($err_msg); return false; } } @@ -885,7 +895,7 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $encoding, $headers $user->session_begin(); $err_msg .= '<br /><br />'; $err_msg .= (isset($user->lang['INVALID_EMAIL_LOG'])) ? sprintf($user->lang['INVALID_EMAIL_LOG'], htmlspecialchars($mail_to_address)) : '<strong>' . htmlspecialchars($mail_to_address) . '</strong> possibly an invalid email address?'; - $smtp->close_session(); + $smtp->close_session($err_msg); return false; } @@ -895,7 +905,7 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $encoding, $headers // This is the last response code we look for until the end of the message. if ($err_msg = $smtp->server_parse('354', __LINE__)) { - $smtp->close_session(); + $smtp->close_session($err_msg); return false; } @@ -922,13 +932,13 @@ function smtpmail($addresses, $subject, $message, &$err_msg, $encoding, $headers $smtp->server_send('.'); if ($err_msg = $smtp->server_parse('250', __LINE__)) { - $smtp->close_session(); + $smtp->close_session($err_msg); return false; } // Now tell the server we are done and close the socket... $smtp->server_send('QUIT'); - $smtp->close_session(); + $smtp->close_session($err_msg); return true; } @@ -947,16 +957,41 @@ class smtp_class var $commands = array(); var $numeric_response_code = 0; + var $backtrace = false; + var $backtrace_log = array(); + + function smtp_class() + { + if (defined('DEBUG_EXTRA')) + { + $this->backtrace = true; + $this->backtrace_log = array(); + } + } + + /** + * Add backtrace message for debugging + */ + function add_backtrace($message) + { + if ($this->backtrace) + { + $this->backtrace_log[] = $message; + } + } + /** * Send command to smtp server */ - function server_send($command) + function server_send($command, $private_info = false) { fputs($this->socket, $command . "\r\n"); + (!$private_info) ? $this->add_backtrace("# $command") : $this->add_backtrace('# Ommitting sensitive Informations'); + // We could put additional code here } - + /** * We use the line to give the support people an indication at which command the error occurred */ @@ -976,6 +1011,8 @@ class smtp_class } $this->responses[] = substr(rtrim($this->server_response), 4); $this->numeric_response_code = (int) substr($this->server_response, 0, 3); + + $this->add_backtrace("LINE: $line <- {$this->server_response}"); } if (!(substr($this->server_response, 0, 3) == $response)) @@ -990,9 +1027,15 @@ class smtp_class /** * Close session */ - function close_session() + function close_session(&$err_msg) { fclose($this->socket); + + if ($this->backtrace) + { + $message = '<h1>Backtrace</h1><p>' . implode('<br />', array_map('htmlspecialchars', $this->backtrace_log)) . '</p>'; + $err_msg .= $message; + } } /** @@ -1008,10 +1051,37 @@ class smtp_class // If we are authenticating through pop-before-smtp, we // have to login ones before we get authenticated + // NOTE: on some configurations the time between an update of the auth database takes so + // long that the first email send does not work. This is not a biggie on a live board (only + // the install mail will most likely fail) - but on a dynamic ip connection this might produce + // severe problems and is not fixable! if ($default_auth_method == 'POP-BEFORE-SMTP' && $username && $password) { + global $config; + + $errno = 0; + $errstr = ''; + + $this->server_send("QUIT"); + fclose($this->socket); + $result = $this->pop_before_smtp($hostname, $username, $password); $username = $password = $default_auth_method = ''; + + // We need to close the previous session, else the server is not + // able to get our ip for matching... + if (!$this->socket = @fsockopen($config['smtp_host'], $config['smtp_port'], $errno, $errstr, 10)) + { + $err_msg = (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr"; + return $err_msg; + } + + // Wait for reply + if ($err_msg = $this->server_parse('220', __LINE__)) + { + $this->close_session($err_msg); + return $err_msg; + } } // Try EHLO first @@ -1090,32 +1160,26 @@ class smtp_class { global $user; - $old_socket = $this->socket; - - if (!$this->socket = fsockopen($hostname, 110, $errno, $errstr, 20)) + if (!$this->socket = @fsockopen($hostname, 110, $errno, $errstr, 10)) { - $this->socket = $old_socket; return (isset($user->lang['NO_CONNECT_TO_SMTP_HOST'])) ? sprintf($user->lang['NO_CONNECT_TO_SMTP_HOST'], $errno, $errstr) : "Could not connect to smtp host : $errno : $errstr"; } - $this->server_parse('0', __LINE__); - if (substr($this->server_response, 0, 3) == '+OK') + $this->server_send("USER $username", true); + if ($err_msg = $this->server_parse('+OK', __LINE__)) { - fputs($this->socket, "USER $username\r\n"); - fputs($this->socket, "PASS $password\r\n"); + return $err_msg; } - else + + $this->server_send("PASS $password", true); + if ($err_msg = $this->server_parse('+OK', __LINE__)) { - $this->socket = $old_socket; - return $this->responses[0]; + return $err_msg; } $this->server_send('QUIT'); - $this->server_parse('0', __LINE__); fclose($this->socket); - $this->socket = $old_socket; - return false; } @@ -1131,7 +1195,7 @@ class smtp_class } $base64_method_plain = base64_encode("\0" . $username . "\0" . $password); - $this->server_send($base64_method_plain); + $this->server_send($base64_method_plain, true); if ($err_msg = $this->server_parse('235', __LINE__)) { return $err_msg; @@ -1151,13 +1215,13 @@ class smtp_class return ($this->numeric_response_code == 503) ? false : $err_msg; } - $this->server_send(base64_encode($username)); + $this->server_send(base64_encode($username), true); if ($err_msg = $this->server_parse('334', __LINE__)) { return $err_msg; } - $this->server_send(base64_encode($password)); + $this->server_send(base64_encode($password), true); if ($err_msg = $this->server_parse('235', __LINE__)) { return $err_msg; @@ -1183,7 +1247,7 @@ class smtp_class $base64_method_cram_md5 = base64_encode($username . ' ' . $md5_digest); - $this->server_send($base64_method_cram_md5); + $this->server_send($base64_method_cram_md5, true); if ($err_msg = $this->server_parse('235', __LINE__)) { return $err_msg; @@ -1287,7 +1351,7 @@ class smtp_class } $base64_method_digest_md5 = base64_encode($input_string); - $this->server_send($base64_method_digest_md5); + $this->server_send($base64_method_digest_md5, true); if ($err_msg = $this->server_parse('334', __LINE__)) { return $err_msg; @@ -1304,25 +1368,24 @@ class smtp_class } /** -* Encodes the given string for proper display for this encoding ... nabbed +* Encodes the given string for proper display in UTF-8 ... nabbed * from php.net and modified. There is an alternative encoding method which * may produce less output but it's questionable as to its worth in this -* scenario IMO +* scenario. +* +* This version is using base64 encoded data. The downside of this +* is if the mail client does not understand this encoding the user +* is basically doomed with an unreadable subject. */ -function mail_encode($str, $encoding) +function mail_encode($str) { - if ($encoding == '') - { - return $str; - } - // define start delimimter, end delimiter and spacer - $end = "?="; - $start = "=?$encoding?B?"; - $spacer = "$end\r\n $start"; + $end = '?='; + $start = '=?UTF-8?B?'; + $spacer = "$end $start"; // determine length of encoded text within chunks and ensure length is even - $length = 75 - strlen($start) - strlen($end); + $length = 76 - strlen($start) - strlen($end); $length = floor($length / 2) * 2; // encode the string and split it into chunks with spacers after each chunk diff --git a/phpBB/includes/functions_module.php b/phpBB/includes/functions_module.php index 9541c9f4cf..89dda74700 100644 --- a/phpBB/includes/functions_module.php +++ b/phpBB/includes/functions_module.php @@ -256,9 +256,9 @@ class p_master // If no category or module selected, go active for first module in first category if ( (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && (($item_ary['mode'] == $mode && !$item_ary['cat']) || ($icat && $item_ary['cat']))) || - ($item_ary['parent'] === $category && !$item_ary['cat'] && !$icat) || + ($item_ary['parent'] === $category && !$item_ary['cat'] && !$icat && $item_ary['display']) || (($item_ary['name'] === $id || $item_ary['id'] === (int) $id) && !$mode && !$item_ary['cat']) || - (!$id && !$mode && !$item_ary['cat']) + (!$id && !$mode && !$item_ary['cat'] && $item_ary['display']) ) { if ($item_ary['cat']) @@ -309,14 +309,14 @@ class p_master { if (!file_exists("$module_path/{$this->p_class}_$this->p_name.$phpEx")) { - trigger_error('Cannot find module', E_USER_ERROR); + trigger_error("Cannot find module $module_path/{$this->p_class}_$this->p_name.$phpEx", E_USER_ERROR); } include("$module_path/{$this->p_class}_$this->p_name.$phpEx"); if (!class_exists("{$this->p_class}_$this->p_name")) { - trigger_error('Module does not contain correct class', E_USER_ERROR); + trigger_error("Module file $module_path/{$this->p_class}_$this->p_name.$phpEx does not contain correct class [{$this->p_class}_$this->p_name]", E_USER_ERROR); } if (!empty($mode)) diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index b40fdb369c..b15466b487 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -111,21 +111,41 @@ function update_post_information($type, $ids, $return_update_sql = false) $ids = array($ids); } - $update_sql = $empty_forums = array(); + $update_sql = $empty_forums = $not_empty_forums = array(); - $sql = 'SELECT ' . $type . '_id, MAX(post_id) as last_post_id - FROM ' . POSTS_TABLE . ' - WHERE post_approved = 1 - AND ' . $db->sql_in_set($type . '_id', $ids) . " - GROUP BY {$type}_id"; + if (sizeof($ids) == 1) + { + $sql = 'SELECT MAX(post_id) as last_post_id + FROM ' . POSTS_TABLE . ' + WHERE ' . $db->sql_in_set($type . '_id', $ids) . ' + AND post_approved = 1'; + } + else + { + $sql = 'SELECT ' . $type . '_id, MAX(post_id) as last_post_id + FROM ' . POSTS_TABLE . ' + WHERE ' . $db->sql_in_set($type . '_id', $ids) . " + AND post_approved = 1 + GROUP BY {$type}_id"; + } $result = $db->sql_query($sql); $last_post_ids = array(); while ($row = $db->sql_fetchrow($result)) { + if (sizeof($ids) == 1) + { + $row[$type . '_id'] = $ids[0]; + } + if ($type == 'forum') { - $empty_forums[] = $row['forum_id']; + $not_empty_forums[] = $row['forum_id']; + + if (empty($row['last_post_id'])) + { + $empty_forums[] = $row['forum_id']; + } } $last_post_ids[] = $row['last_post_id']; @@ -134,20 +154,22 @@ function update_post_information($type, $ids, $return_update_sql = false) if ($type == 'forum') { - $empty_forums = array_diff($ids, $empty_forums); + $empty_forums = array_merge($empty_forums, array_diff($ids, $not_empty_forums)); foreach ($empty_forums as $void => $forum_id) { $update_sql[$forum_id][] = 'forum_last_post_id = 0'; - $update_sql[$forum_id][] = 'forum_last_post_time = 0'; + $update_sql[$forum_id][] = "forum_last_post_subject = ''"; + $update_sql[$forum_id][] = 'forum_last_post_time = 0'; $update_sql[$forum_id][] = 'forum_last_poster_id = 0'; $update_sql[$forum_id][] = "forum_last_poster_name = ''"; + $update_sql[$forum_id][] = "forum_last_poster_colour = ''"; } } if (sizeof($last_post_ids)) { - $sql = 'SELECT p.' . $type . '_id, p.post_id, p.post_time, p.poster_id, p.post_username, u.user_id, u.username + $sql = 'SELECT p.' . $type . '_id, p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u WHERE p.poster_id = u.user_id AND ' . $db->sql_in_set('p.post_id', $last_post_ids); @@ -156,8 +178,10 @@ function update_post_information($type, $ids, $return_update_sql = false) while ($row = $db->sql_fetchrow($result)) { $update_sql[$row["{$type}_id"]][] = $type . '_last_post_id = ' . (int) $row['post_id']; + $update_sql[$row["{$type}_id"]][] = "{$type}_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'"; $update_sql[$row["{$type}_id"]][] = $type . '_last_post_time = ' . (int) $row['post_time']; $update_sql[$row["{$type}_id"]][] = $type . '_last_poster_id = ' . (int) $row['poster_id']; + $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'"; $update_sql[$row["{$type}_id"]][] = "{$type}_last_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'"; } $db->sql_freeresult($result); @@ -190,8 +214,7 @@ function posting_gen_topic_icons($mode, $icon_id) global $phpbb_root_path, $config, $template, $cache; // Grab icons - $icons = array(); - $cache->obtain_icons($icons); + $icons = $cache->obtain_icons(); if (!$icon_id) { @@ -311,13 +334,11 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage if (!$filedata['post_attach']) { - $filedata['error'][] = 'No filedata found'; + $filedata['error'][] = $user->lang['NO_UPLOAD_FORM_FOUND']; return $filedata; } - $extensions = array(); - $cache->obtain_attach_extensions($extensions, $forum_id); - + $extensions = $cache->obtain_attach_extensions($forum_id); $upload->set_allowed_extensions(array_keys($extensions['_allowed_'])); $file = ($local) ? $upload->local_upload($local_storage) : $upload->form_upload($form_name); @@ -330,6 +351,16 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage $cat_id = (isset($extensions[$file->get('extension')]['display_cat'])) ? $extensions[$file->get('extension')]['display_cat'] : ATTACHMENT_CATEGORY_NONE; + // Make sure the image category only holds valid images... + if ($cat_id == ATTACHMENT_CATEGORY_IMAGE && !$file->is_image()) + { + $file->remove(); + + // If this error occurs a user tried to exploit an IE Bug by renaming extensions + // Since the image category is displaying content inline we need to catch this. + trigger_error($user->lang['UNABLE_GET_IMAGE_SIZE']); + } + // Do we have to create a thumbnail? $filedata['thumbnail'] = ($cat_id == ATTACHMENT_CATEGORY_IMAGE && $config['img_create_thumbnail']) ? 1 : 0; @@ -421,8 +452,10 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage */ function get_img_size_format($width, $height) { + global $config; + // Maximum Width the Image can take - $max_width = 400; + $max_width = ($config['img_max_thumb_width']) ? $config['img_max_thumb_width'] : 400; if ($width > $height) { @@ -533,7 +566,8 @@ function create_thumbnail($source, $destination, $mimetype) // Only use imagemagick if defined and the passthru function not disabled if ($config['img_imagick'] && function_exists('passthru')) { - passthru(escapeshellcmd($config['img_imagick']) . 'convert' . ((defined('PHP_OS') && preg_match('#^win#i', PHP_OS)) ? '.exe' : '') . ' -quality 85 -antialias -sample ' . $new_width . 'x' . $new_height . ' "' . str_replace('\\', '/', $source) . '" +profile "*" "' . str_replace('\\', '/', $destination) . '"'); + @passthru(escapeshellcmd($config['img_imagick']) . 'convert' . ((defined('PHP_OS') && preg_match('#^win#i', PHP_OS)) ? '.exe' : '') . ' -quality 85 -antialias -sample ' . $new_width . 'x' . $new_height . ' "' . str_replace('\\', '/', $source) . '" +profile "*" "' . str_replace('\\', '/', $destination) . '"'); + if (file_exists($destination)) { $used_imagick = true; @@ -638,7 +672,7 @@ function posting_gen_inline_attachments(&$attachment_data) foreach ($attachment_data as $i => $attachment) { - $s_inline_attachment_options .= '<option value="' . $i . '">' . $attachment['real_filename'] . '</option>'; + $s_inline_attachment_options .= '<option value="' . $i . '">' . basename($attachment['real_filename']) . '</option>'; } $template->assign_var('S_INLINE_ATTACHMENT_OPTIONS', $s_inline_attachment_options); @@ -654,7 +688,7 @@ function posting_gen_inline_attachments(&$attachment_data) */ function posting_gen_attachment_entry(&$attachment_data, &$filename_data) { - global $template, $config, $phpbb_root_path, $phpEx; + global $template, $config, $phpbb_root_path, $phpEx, $user; $template->assign_vars(array( 'S_SHOW_ATTACH_BOX' => true) @@ -677,13 +711,13 @@ function posting_gen_attachment_entry(&$attachment_data, &$filename_data) $hidden .= '<input type="hidden" name="attachment_data[' . $count . '][' . $key . ']" value="' . $value . '" />'; } - $download_link = (!$attach_row['attach_id']) ? $phpbb_root_path . $config['upload_path'] . '/' . basename($attach_row['physical_filename']) : append_sid("{$phpbb_root_path}download.$phpEx", 'id=' . (int) $attach_row['attach_id']); + $download_link = append_sid("{$phpbb_root_path}download.$phpEx", 'id=' . (int) $attach_row['attach_id'], false, ($attach_row['is_orphan']) ? $user->session_id : false); $template->assign_block_vars('attach_row', array( 'FILENAME' => basename($attach_row['real_filename']), - 'ATTACH_FILENAME' => basename($attach_row['physical_filename']), 'FILE_COMMENT' => $attach_row['attach_comment'], 'ATTACH_ID' => $attach_row['attach_id'], + 'S_IS_ORPHAN' => $attach_row['is_orphan'], 'ASSOC_INDEX' => $count, 'U_VIEW_ATTACHMENT' => $download_link, @@ -848,10 +882,10 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id $db->sql_freeresult($result); // Instantiate BBCode class - if (!isset($bbcode) && $bbcode_bitfield) + if (!isset($bbcode) && $bbcode_bitfield !== '') { include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); - $bbcode = new bbcode($bbcode_bitfield); + $bbcode = new bbcode(base64_encode($bbcode_bitfield)); } foreach ($rowset as $i => $row) @@ -868,6 +902,8 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id $post_subject = $row['post_subject']; $message = $row['post_text']; + $message = censor_text($message); + $message = str_replace("\n", '<br />', $message); $decoded_message = false; if ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) @@ -887,20 +923,18 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id $message = smiley_text($message, !$row['enable_smilies']); $post_subject = censor_text($post_subject); - $message = censor_text($message); $template->assign_block_vars($mode . '_row', array( 'POSTER_NAME' => $poster, 'POST_SUBJECT' => $post_subject, 'MINI_POST_IMG' => $user->img('icon_post_target', $user->lang['POST']), 'POST_DATE' => $user->format_date($row['post_time']), - 'MESSAGE' => str_replace("\n", '<br />', $message), + 'MESSAGE' => $message, 'DECODED_MESSAGE' => $decoded_message, - 'U_POST_ID' => $row['post_id'], 'U_MINI_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'p=' . $row['post_id']) . '#p' . $row['post_id'], 'U_MCP_DETAILS' => ($auth->acl_get('m_info', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&mode=post_details&f=' . $forum_id . '&p=' . $row['post_id'], true, $user->session_id) : '', - 'U_QUOTE' => ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) ? 'javascript:addquote(' . $row['post_id'] . ", '" . addslashes($poster) . "')" : '') + 'POSTER_QUOTE' => ($show_quote_button && $auth->acl_get('f_reply', $forum_id)) ? addslashes($poster) : '') ); unset($rowset[$i]); } @@ -920,8 +954,8 @@ function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id { global $db, $user, $config, $phpbb_root_path, $phpEx, $auth; - $topic_notification = ($mode == 'reply' || $mode == 'quote'); - $forum_notification = ($mode == 'post'); + $topic_notification = ($mode == 'reply' || $mode == 'quote') ? true : false; + $forum_notification = ($mode == 'post') ? true : false; if (!$topic_notification && !$forum_notification) { @@ -1053,8 +1087,6 @@ function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id include_once($phpbb_root_path . 'includes/functions_messenger.'.$phpEx); $messenger = new messenger(); - $email_sig = str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']); - $msg_list_ary = array(); foreach ($msg_users as $row) { @@ -1079,11 +1111,9 @@ function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id $messenger->im($addr['jabber'], $addr['name']); $messenger->assign_vars(array( - 'EMAIL_SIG' => $email_sig, - 'SITENAME' => html_entity_decode($config['sitename']), - 'USERNAME' => html_entity_decode($addr['name']), - 'TOPIC_TITLE' => html_entity_decode($topic_title), - 'FORUM_NAME' => html_entity_decode($forum_name), + 'USERNAME' => htmlspecialchars_decode($addr['name']), + 'TOPIC_TITLE' => htmlspecialchars_decode($topic_title), + 'FORUM_NAME' => htmlspecialchars_decode($forum_name), 'U_FORUM' => generate_board_url() . "/viewforum.$phpEx?f=$forum_id&e=0", 'U_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&t=$topic_id&e=0", @@ -1197,7 +1227,7 @@ function delete_post($forum_id, $topic_id, $post_id, &$data) break; case 'delete_first_post': - $sql = 'SELECT p.post_id, p.poster_id, p.post_username, u.username + $sql = 'SELECT p.post_id, p.poster_id, p.post_username, u.username, u.user_colour FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u WHERE p.topic_id = $topic_id AND p.poster_id = u.user_id @@ -1211,7 +1241,7 @@ function delete_post($forum_id, $topic_id, $post_id, &$data) $sql_data[FORUMS_TABLE] = 'forum_posts = forum_posts - 1'; } - $sql_data[TOPICS_TABLE] = 'topic_first_post_id = ' . intval($row['post_id']) . ", topic_first_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'"; + $sql_data[TOPICS_TABLE] = 'topic_first_post_id = ' . intval($row['post_id']) . ", topic_first_poster_colour = '" . $db->sql_escape($row['user_colour']) . ", topic_first_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "'"; $sql_data[TOPICS_TABLE] .= ', topic_replies_real = topic_replies_real - 1' . (($data['post_approved']) ? ', topic_replies = topic_replies - 1' : ''); $next_post_id = (int) $row['post_id']; @@ -1381,8 +1411,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u 'post_subject' => $subject, 'post_text' => $data['message'], 'post_checksum' => $data['message_md5'], - 'post_encoding' => $user->lang['ENCODING'], - 'post_attachment' => (isset($data['filename_data']['physical_filename']) && sizeof($data['filename_data'])) ? 1 : 0, + 'post_attachment' => (!empty($data['attachment_data'])) ? 1 : 0, 'bbcode_bitfield' => $data['bbcode_bitfield'], 'bbcode_uid' => $data['bbcode_uid'], 'post_postcount' => ($auth->acl_get('f_postcount', $data['forum_id'])) ? 1 : 0, @@ -1435,8 +1464,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u 'post_edit_reason' => $data['post_edit_reason'], 'post_edit_user' => (int) $data['post_edit_user'], 'post_checksum' => $data['message_md5'], - 'post_encoding' => $user->lang['ENCODING'], - 'post_attachment' => (isset($data['filename_data']['physical_filename']) && sizeof($data['filename_data'])) ? 1 : 0, + 'post_attachment' => (!empty($data['attachment_data'])) ? 1 : 0, 'bbcode_bitfield' => $data['bbcode_bitfield'], 'bbcode_uid' => $data['bbcode_uid'], 'post_edit_locked' => $data['post_edit_locked']) @@ -1462,9 +1490,10 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u 'topic_approved' => (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) ? 0 : 1, 'topic_title' => $subject, 'topic_first_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''), + 'topic_first_poster_colour' => (($user->data['user_id'] != ANONYMOUS) ? $user->data['user_colour'] : ''), 'topic_type' => $topic_type, 'topic_time_limit' => ($topic_type == POST_STICKY || $topic_type == POST_ANNOUNCE) ? ($data['topic_time_limit'] * 86400) : 0, - 'topic_attachment' => (isset($data['filename_data']['physical_filename']) && sizeof($data['filename_data'])) ? 1 : 0 + 'topic_attachment' => (!empty($data['attachment_data'])) ? 1 : 0, ); if (isset($poll['poll_options']) && !empty($poll['poll_options'])) @@ -1517,7 +1546,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u 'poll_length' => (isset($poll['poll_options'])) ? ($poll['poll_length'] * 86400) : 0, 'poll_vote_change' => (isset($poll['poll_vote_change'])) ? $poll['poll_vote_change'] : 0, - 'topic_attachment' => ($post_mode == 'edit_topic') ? ((isset($data['filename_data']['physical_filename']) && sizeof($data['filename_data'])) ? 1 : 0) : (isset($data['topic_attachment']) ? $data['topic_attachment'] : 0) + 'topic_attachment' => (!empty($data['attachment_data'])) ? 1 : (isset($data['topic_attachment']) ? $data['topic_attachment'] : 0), ); break; } @@ -1560,7 +1589,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u 'topic_last_post_id' => $data['post_id'], 'topic_last_post_time' => $current_time, 'topic_last_poster_id' => (int) $user->data['user_id'], - 'topic_last_poster_name'=> (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '') + 'topic_last_poster_name'=> (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''), + 'topic_last_poster_colour' => (($user->data['user_id'] != ANONYMOUS) ? $user->data['user_colour'] : ''), ); } @@ -1675,24 +1705,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u } } - if (sizeof($sql_insert_ary)) - { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query('INSERT INTO ' . POLL_OPTIONS_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $sql_insert_ary)); - break; - - default: - foreach ($sql_insert_ary as $ary) - { - $db->sql_query('INSERT INTO ' . POLL_OPTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } - } + $db->sql_multi_insert(POLL_OPTIONS_TABLE, $sql_insert_ary); if (sizeof($poll['poll_options']) < sizeof($cur_poll_options)) { @@ -1704,67 +1717,81 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u } // Submit Attachments - if (sizeof($data['attachment_data']) && $data['post_id'] && in_array($mode, array('post', 'reply', 'quote', 'edit'))) + if (!empty($data['attachment_data']) && $data['post_id'] && in_array($mode, array('post', 'reply', 'quote', 'edit'))) { $space_taken = $files_added = 0; + $orphan_rows = array(); foreach ($data['attachment_data'] as $pos => $attach_row) { - if ($attach_row['attach_id']) + $orphan_rows[(int) $attach_row['attach_id']] = array(); + } + + if (sizeof($orphan_rows)) + { + $sql = 'SELECT attach_id, filesize, physical_filename + FROM ' . ATTACHMENTS_TABLE . ' + WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . ' + AND is_orphan = 1 + AND poster_id = ' . $user->data['user_id']; + $result = $db->sql_query($sql); + + $orphan_rows = array(); + while ($row = $db->sql_fetchrow($result)) + { + $orphan_rows[$row['attach_id']] = $row; + } + $db->sql_freeresult($result); + } + + foreach ($data['attachment_data'] as $pos => $attach_row) + { + if ($attach_row['is_orphan'] && !in_array($attach_row['attach_id'], array_keys($orphan_rows))) + { + continue; + } + + if (!$attach_row['is_orphan']) { // update entry in db if attachment already stored in db and filespace $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "' - WHERE attach_id = " . (int) $attach_row['attach_id']; + WHERE attach_id = " . (int) $attach_row['attach_id'] . ' + AND is_orphan = 0'; $db->sql_query($sql); } else { // insert attachment into db - if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . basename($attach_row['physical_filename']))) + if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . basename($orphan_rows[$attach_row['attach_id']]['physical_filename']))) { continue; } + $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize']; + $files_added++; + $attach_sql = array( 'post_msg_id' => $data['post_id'], 'topic_id' => $data['topic_id'], - 'in_message' => 0, + 'is_orphan' => 0, 'poster_id' => $poster_id, - 'physical_filename' => basename($attach_row['physical_filename']), - 'real_filename' => basename($attach_row['real_filename']), 'attach_comment' => $attach_row['attach_comment'], - 'extension' => $attach_row['extension'], - 'mimetype' => $attach_row['mimetype'], - 'filesize' => $attach_row['filesize'], - 'filetime' => $attach_row['filetime'], - 'thumbnail' => $attach_row['thumbnail'] ); - $sql = 'INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . - $db->sql_build_array('INSERT', $attach_sql); + $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . ' + WHERE attach_id = ' . $attach_row['attach_id'] . ' + AND is_orphan = 1 + AND poster_id = ' . $user->data['user_id']; $db->sql_query($sql); - - $space_taken += $attach_row['filesize']; - $files_added++; } } - if (sizeof($data['attachment_data'])) + if ($space_taken && $files_added) { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_attachment = 1 - WHERE post_id = ' . $data['post_id']; - $db->sql_query($sql); - - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_attachment = 1 - WHERE topic_id = ' . $data['topic_id']; - $db->sql_query($sql); + set_config('upload_dir_size', $config['upload_dir_size'] + $space_taken, true); + set_config('num_files', $config['num_files'] + $files_added, true); } - - set_config('upload_dir_size', $config['upload_dir_size'] + $space_taken, true); - set_config('num_files', $config['num_files'] + $files_added, true); } $db->sql_transaction('commit'); @@ -1852,7 +1879,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u trigger_error('NO_SUCH_SEARCH_MODULE'); } - require("{$phpbb_root_path}includes/search/$search_type.$phpEx"); + require_once("{$phpbb_root_path}includes/search/$search_type.$phpEx"); $error = false; $search = new $search_type($error); @@ -1862,7 +1889,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u trigger_error($error); } - $search->index($mode, $data['post_id'], $data['message'], $subject, $user->lang['ENCODING'], $poster_id, ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id']); + $search->index($mode, $data['post_id'], $data['message'], $subject, $poster_id, ($topic_type == POST_GLOBAL) ? 0 : $data['forum_id']); } $db->sql_transaction('commit'); @@ -1921,7 +1948,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u $f_mark_time = false; } - if ($config['load_db_lastread'] || $config['load_anon_lastread'] || $user->data['is_registered']) + if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered']) { // Update forum info $sql = 'SELECT forum_last_post_time diff --git a/phpBB/includes/functions_privmsgs.php b/phpBB/includes/functions_privmsgs.php index fe38b6276b..58d854b928 100644 --- a/phpBB/includes/functions_privmsgs.php +++ b/phpBB/includes/functions_privmsgs.php @@ -279,9 +279,31 @@ function check_rule(&$rules, &$rule_row, &$message_row, $user_id) case ACTION_MARK_AS_READ: case ACTION_MARK_AS_IMPORTANT: - case ACTION_DELETE_MESSAGE: return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']); break; + + case ACTION_DELETE_MESSAGE: + global $db, $auth; + + // Check for admins/mods - users are not allowed to remove those messages... + // We do the check here to make sure the data we use is consistent + $sql = 'SELECT user_id, user_type, user_permissions + FROM ' . USERS_TABLE . ' + WHERE user_id = ' . (int) $message_row['author_id']; + $result = $db->sql_query($sql); + $userdata = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + $auth2 = new auth(); + $auth2->acl($userdata); + + if (!$auth2->acl_get('a_') && !$auth->acl_get('m_') && !$auth2->acl_getf_global('m_')) + { + return array('action' => $rule_row['rule_action'], 'pm_unread' => $message_row['pm_unread'], 'pm_marked' => $message_row['pm_marked']); + } + + return false; + break; default: return false; @@ -486,8 +508,8 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false) } } - $num_new += sizeof(array_unique($delete_ids)); - $num_unread += sizeof(array_unique($delete_ids)); +// $num_new += sizeof(array_unique($delete_ids)); +// $num_unread += sizeof(array_unique($delete_ids)); $num_unread += sizeof(array_unique($unread_ids)); // Do not change the order of processing @@ -589,13 +611,12 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false) } else if ($full_folder_action == FULL_FOLDER_DELETE) { - // Delete some messages ;) - $sql = 'SELECT t.msg_id - FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . " p - WHERE t.msg_id = p.msg_id - AND t.user_id = $user_id - AND t.folder_id = $dest_folder - ORDER BY p.message_time ASC"; + // Delete some messages. NOTE: Ordered by msg_id here instead of message_time! + $sql = 'SELECT msg_id + FROM ' . PRIVMSGS_TO_TABLE . " + WHERE user_id = $user_id + AND folder_id = $dest_folder + ORDER BY msg_id ASC"; $result = $db->sql_query_limit($sql, (($folder[$dest_folder] + sizeof($msg_ary)) - $user->data['message_limit'])); $delete_ids = array(); @@ -668,6 +689,7 @@ function place_pm_into_folder(&$global_privmsgs_rules, $release = false) } $db->sql_query('UPDATE ' . USERS_TABLE . " SET $set_sql WHERE user_id = $user_id"); + $user->data['user_new_privmsg'] -= $num_new; $user->data['user_unread_privmsg'] -= $num_unread; } @@ -778,7 +800,7 @@ function update_unread_status($unread, $msg_id, $user_id, $folder_id) return; } - global $db; + global $db, $user; $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . " SET pm_unread = 0 @@ -791,6 +813,11 @@ function update_unread_status($unread, $msg_id, $user_id, $folder_id) SET user_unread_privmsg = user_unread_privmsg - 1 WHERE user_id = $user_id"; $db->sql_query($sql); + + if ($user->data['user_id'] == $user_id) + { + $user->data['user_unread_privmsg']--; + } } /** @@ -860,7 +887,7 @@ function handle_mark_actions($user_id, $mark_action) */ function delete_pm($user_id, $msg_ids, $folder_id) { - global $db; + global $db, $user; $user_id = (int) $user_id; $folder_id = (int) $folder_id; @@ -957,6 +984,7 @@ function delete_pm($user_id, $msg_ids, $folder_id) if ($num_unread || $num_new) { $set_sql = ($num_unread) ? 'user_unread_privmsg = user_unread_privmsg - ' . $num_unread : ''; + if ($num_new) { $set_sql .= ($set_sql != '') ? ', ' : ''; @@ -964,6 +992,9 @@ function delete_pm($user_id, $msg_ids, $folder_id) } $db->sql_query('UPDATE ' . USERS_TABLE . " SET $set_sql WHERE user_id = $user_id"); + + $user->data['user_new_privmsg'] -= $num_new; + $user->data['user_unread_privmsg'] -= $num_unread; } // Now we have to check which messages we can delete completely @@ -1141,7 +1172,7 @@ function write_pm_addresses($check_ary, $author_id, $plaintext = false) 'IS_USER' => ($type == 'user'), 'COLOUR' => ($row['colour']) ? $row['colour'] : '', 'UG_ID' => $id, - 'U_VIEW' => ($type == 'user') ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $id) : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $id), + 'U_VIEW' => ($type == 'user') ? (($id != ANONYMOUS) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $id) : '') : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $id), 'TYPE' => $type) ); } @@ -1223,7 +1254,7 @@ function submit_pm($mode, $subject, &$data, $update_message, $put_in_outbox = tr $id = (int) $id; // Do not rely on the address list being "valid" - if (!$id) + if (!$id || ($ug_type == 'u' && $id == ANONYMOUS)) { continue; } @@ -1291,8 +1322,7 @@ function submit_pm($mode, $subject, &$data, $update_message, $put_in_outbox = tr 'enable_sig' => $data['enable_sig'], 'message_subject' => $subject, 'message_text' => $data['message'], - 'message_encoding' => $user->lang['ENCODING'], - 'message_attachment'=> (isset($data['filename_data']['physical_filename']) && sizeof($data['filename_data'])) ? 1 : 0, + 'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0, 'bbcode_bitfield' => $data['bbcode_bitfield'], 'bbcode_uid' => $data['bbcode_uid'], 'to_address' => implode(':', $to), @@ -1310,8 +1340,7 @@ function submit_pm($mode, $subject, &$data, $update_message, $put_in_outbox = tr 'enable_sig' => $data['enable_sig'], 'message_subject' => $subject, 'message_text' => $data['message'], - 'message_encoding' => $user->lang['ENCODING'], - 'message_attachment'=> (isset($data['filename_data']['physical_filename']) && sizeof($data['filename_data'])) ? 1 : 0, + 'message_attachment'=> (!empty($data['attachment_data'])) ? 1 : 0, 'bbcode_bitfield' => $data['bbcode_bitfield'], 'bbcode_uid' => $data['bbcode_uid'] ); @@ -1360,24 +1389,7 @@ function submit_pm($mode, $subject, &$data, $update_message, $put_in_outbox = tr ); } - if (sizeof($sql_ary)) - { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $sql_ary)); - break; - - default: - foreach ($sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } - } + $db->sql_multi_insert(PRIVMSGS_TO_TABLE, $sql_ary); $sql = 'UPDATE ' . USERS_TABLE . ' SET user_new_privmsg = user_new_privmsg + 1, user_unread_privmsg = user_unread_privmsg + 1, user_last_privmsg = ' . time() . ' @@ -1416,52 +1428,74 @@ function submit_pm($mode, $subject, &$data, $update_message, $put_in_outbox = tr if (!empty($data['attachment_data']) && $data['msg_id'] && in_array($mode, array('post', 'reply', 'quote', 'quotepost', 'edit', 'forward'))) { $space_taken = $files_added = 0; + $orphan_rows = array(); + + foreach ($data['attachment_data'] as $pos => $attach_row) + { + $orphan_rows[(int) $attach_row['attach_id']] = array(); + } + + if (sizeof($orphan_rows)) + { + $sql = 'SELECT attach_id, filesize, physical_filename + FROM ' . ATTACHMENTS_TABLE . ' + WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan_rows)) . ' + AND in_message = 1 + AND is_orphan = 1 + AND poster_id = ' . $user->data['user_id']; + $result = $db->sql_query($sql); + + $orphan_rows = array(); + while ($row = $db->sql_fetchrow($result)) + { + $orphan_rows[$row['attach_id']] = $row; + } + $db->sql_freeresult($result); + } foreach ($data['attachment_data'] as $pos => $attach_row) { - if ($attach_row['attach_id']) + if ($attach_row['is_orphan'] && !in_array($attach_row['attach_id'], array_keys($orphan_rows))) + { + continue; + } + + if (!$attach_row['is_orphan']) { // update entry in db if attachment already stored in db and filespace - $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " - SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "' - WHERE attach_id = " . (int) $attach_row['attach_id']; + $sql = 'UPDATE ' . ATTACHMENTS_TABLE . " + SET attach_comment = '" . $db->sql_escape($attach_row['attach_comment']) . "' + WHERE attach_id = " . (int) $attach_row['attach_id'] . ' + AND is_orphan = 0'; $db->sql_query($sql); } else { - // insert attachment into db + // insert attachment into db + if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . basename($orphan_rows[$attach_row['attach_id']]['physical_filename']))) + { + continue; + } + + $space_taken += $orphan_rows[$attach_row['attach_id']]['filesize']; + $files_added++; + $attach_sql = array( 'post_msg_id' => $data['msg_id'], 'topic_id' => 0, - 'in_message' => 1, + 'is_orphan' => 0, 'poster_id' => $data['from_user_id'], - 'physical_filename' => basename($attach_row['physical_filename']), - 'real_filename' => basename($attach_row['real_filename']), 'attach_comment' => $attach_row['attach_comment'], - 'extension' => $attach_row['extension'], - 'mimetype' => $attach_row['mimetype'], - 'filesize' => $attach_row['filesize'], - 'filetime' => $attach_row['filetime'], - 'thumbnail' => $attach_row['thumbnail'] ); - $sql = 'INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . - $db->sql_build_array('INSERT', $attach_sql); + $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $attach_sql) . ' + WHERE attach_id = ' . $attach_row['attach_id'] . ' + AND is_orphan = 1 + AND poster_id = ' . $user->data['user_id']; $db->sql_query($sql); - - $space_taken += $attach_row['filesize']; - $files_added++; } } - if (sizeof($data['attachment_data'])) - { - $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' - SET message_attachment = 1 - WHERE msg_id = ' . $data['msg_id']; - $db->sql_query($sql); - } - if ($space_taken && $files_added) { set_config('upload_dir_size', $config['upload_dir_size'] + $space_taken, true); @@ -1553,8 +1587,6 @@ function pm_notification($mode, $author, $recipients, $subject, $message) include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); $messenger = new messenger(); - $email_sig = str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']); - foreach ($msg_list_ary as $pos => $addr) { $messenger->template('privmsg_notify', $addr['lang']); @@ -1564,11 +1596,9 @@ function pm_notification($mode, $author, $recipients, $subject, $message) $messenger->im($addr['jabber'], $addr['name']); $messenger->assign_vars(array( - 'EMAIL_SIG' => $email_sig, - 'SITENAME' => $config['sitename'], - 'SUBJECT' => html_entity_decode($subject), - 'AUTHOR_NAME' => html_entity_decode($author), - 'USERNAME' => html_entity_decode($addr['name']), + 'SUBJECT' => htmlspecialchars_decode($subject), + 'AUTHOR_NAME' => htmlspecialchars_decode($author), + 'USERNAME' => htmlspecialchars_decode($addr['name']), 'U_INBOX' => generate_board_url() . "/ucp.$phpEx?i=pm&folder=inbox") ); diff --git a/phpBB/includes/functions_profile_fields.php b/phpBB/includes/functions_profile_fields.php index 6f71724754..b35781e198 100644 --- a/phpBB/includes/functions_profile_fields.php +++ b/phpBB/includes/functions_profile_fields.php @@ -21,7 +21,7 @@ class custom_profile /** * Assign editable fields to template, mode can be profile (for profile change) or register (for registration) * Called by ucp_profile and ucp_register - * @access: public + * @access public */ function generate_profile_fields($mode, $lang_id) { @@ -74,7 +74,7 @@ class custom_profile /** * Validate entered profile field data - * @access: public + * @access public */ function validate_profile_field($field_type, &$field_value, $field_data) { @@ -161,11 +161,11 @@ class custom_profile return 'FIELD_REQUIRED'; } - if ($field_data['field_minlen'] && strlen($field_value) < $field_data['field_minlen']) + if ($field_data['field_minlen'] && utf8_strlen($field_value) < $field_data['field_minlen']) { return 'FIELD_TOO_SHORT'; } - else if ($field_data['field_maxlen'] && strlen($field_value) > $field_data['field_maxlen']) + else if ($field_data['field_maxlen'] && utf8_strlen($field_value) > $field_data['field_maxlen']) { return 'FIELD_TOO_LONG'; } @@ -186,7 +186,7 @@ class custom_profile /** * Build profile cache, used for display - * @access: private + * @access private */ function build_cache() { @@ -248,7 +248,7 @@ class custom_profile /** * Submit profile field - * @access: public + * @access public */ function submit_cp_field($mode, $lang_id, &$cp_data, &$cp_error) { @@ -286,8 +286,8 @@ class custom_profile while ($row = $db->sql_fetchrow($result)) { - $cp_data['_' . $row['field_ident']] = $this->get_profile_field($row); - $check_value = $cp_data['_' . $row['field_ident']]; + $cp_data['pf_' . $row['field_ident']] = $this->get_profile_field($row); + $check_value = $cp_data['pf_' . $row['field_ident']]; if (($cp_result = $this->validate_profile_field($row['field_type'], $check_value, $row)) !== false) { @@ -340,7 +340,7 @@ class custom_profile /** * Assign fields to template, used for viewprofile, viewtopic and memberlist (if load setting is enabled) * This is directly connected to the user -> mode == grab is to grab the user specific fields, mode == show is for assigning the row to the template - * @access: public + * @access public */ function generate_profile_fields_template($mode, $user_id = 0, $profile_row = false) { @@ -382,7 +382,7 @@ class custom_profile { foreach ($field_data as $user_id => $row) { - $user_fields[$user_id][$used_ident]['value'] = $row['_' . $used_ident]; + $user_fields[$user_id][$used_ident]['value'] = $row['pf_' . $used_ident]; $user_fields[$user_id][$used_ident]['data'] = $this->profile_cache[$used_ident]; } } @@ -535,14 +535,14 @@ class custom_profile /** * Get field value for registration/profile - * @access: private + * @access private */ function get_var($field_validation, &$profile_row, $default_value, $preview) { global $user; $profile_row['field_ident'] = (isset($profile_row['var_name'])) ? $profile_row['var_name'] : 'pf_' . $profile_row['field_ident']; - $user_ident = '_' . str_replace('pf_', '', $profile_row['field_ident']); + $user_ident = 'pf_' . str_replace('pf_', '', $profile_row['field_ident']); // checkbox - only testing for isset if ($profile_row['field_type'] == FIELD_BOOL && $profile_row['field_length'] == 2) @@ -576,6 +576,11 @@ class custom_profile else { $value = (isset($_REQUEST[$profile_row['field_ident']])) ? request_var($profile_row['field_ident'], $default_value, true) : ((!isset($user->profile_fields[$user_ident]) || $preview) ? $default_value : $user->profile_fields[$user_ident]); + + if (gettype($value) == 'string') + { + utf8_normalize_nfc(&$value); + } } switch ($field_validation) @@ -590,7 +595,7 @@ class custom_profile /** * Process int-type - * @access: private + * @access private */ function generate_int($profile_row, $preview = false) { @@ -602,14 +607,14 @@ class custom_profile /** * Process date-type - * @access: private + * @access private */ function generate_date($profile_row, $preview = false) { global $user, $template; $profile_row['field_ident'] = (isset($profile_row['var_name'])) ? $profile_row['var_name'] : 'pf_' . $profile_row['field_ident']; - $user_ident = '_' . str_replace('pf_', '', $profile_row['field_ident']); + $user_ident = 'pf_' . str_replace('pf_', '', $profile_row['field_ident']); $now = getdate(); @@ -661,7 +666,7 @@ class custom_profile /** * Process bool-type - * @access: private + * @access private */ function generate_bool($profile_row, $preview = false) { @@ -692,7 +697,7 @@ class custom_profile /** * Process string-type - * @access: private + * @access private */ function generate_string($profile_row, $preview = false) { @@ -704,7 +709,7 @@ class custom_profile /** * Process text-type - * @access: private + * @access private */ function generate_text($profile_row, $preview = false) { @@ -721,7 +726,7 @@ class custom_profile /** * Process dropdown-type - * @access: private + * @access private */ function generate_dropdown($profile_row, $preview = false) { @@ -750,7 +755,7 @@ class custom_profile /** * Return Templated value/field. Possible values for $mode are: * change == user is able to set/enter profile values; preview == just show the value - * @access: private + * @access private */ function process_field_row($mode, $profile_row) { @@ -787,7 +792,7 @@ class custom_profile $sql_not_in = array(); foreach ($cp_data as $key => $null) { - $sql_not_in[] = (strncmp($key, '_', 1) === 0) ? substr($key, 1) : $key; + $sql_not_in[] = (strncmp($key, 'pf_', 3) === 0) ? substr($key, 3) : $key; } $sql = 'SELECT f.field_type, f.field_ident, f.field_default_value, l.lang_default_value @@ -805,7 +810,7 @@ class custom_profile $row['field_default_value'] = sprintf('%2d-%2d-%4d', $now['mday'], $now['mon'], $now['year']); } - $cp_data['_' . $row['field_ident']] = (in_array($row['field_type'], array(FIELD_TEXT, FIELD_STRING))) ? $row['lang_default_value'] : $row['field_default_value']; + $cp_data['pf_' . $row['field_ident']] = (in_array($row['field_type'], array(FIELD_TEXT, FIELD_STRING))) ? $row['lang_default_value'] : $row['field_default_value']; } $db->sql_freeresult($result); @@ -814,7 +819,7 @@ class custom_profile /** * Get profile field value on submit - * @access: private + * @access private */ function get_profile_field($profile_row) { @@ -861,6 +866,7 @@ class custom_profile case FIELD_STRING: case FIELD_TEXT: $var = request_var($var_name, $profile_row['field_default_value'], true); + utf8_normalize_nfc(&$var); break; case FIELD_INT: diff --git a/phpBB/includes/functions_template.php b/phpBB/includes/functions_template.php index 7f29c2a040..47ff906a28 100644 --- a/phpBB/includes/functions_template.php +++ b/phpBB/includes/functions_template.php @@ -52,7 +52,7 @@ class template_compile /** * Load template source from file - * @access: private + * @access private */ function _tpl_load_file($handle) { @@ -82,78 +82,19 @@ class template_compile */ function remove_php_tags(&$code) { - if (!function_exists('token_get_all')) - { - /** - * If the tokenizer extension is not available, try to load it and if - * it's still not available we fall back to some pattern replacement. - * - * Note that the pattern replacement may affect the well-formedness - * of the HTML if a PHP tag is found because even if we escape PHP - * opening tags we do NOT escape PHP closing tags and cannot do so - * reliably without the use of a full-blown tokenizer. - * - * The bottom line is, a template should NEVER contain PHP because it - * would comprise the security of the installation, that's why we - * prevent it from being executed. Our job is to secure the installation, - * not fix unsecure templates. if a template contains some PHP then it - * should not be used at all. - */ - @dl('tokenizer'); - - if (!function_exists('token_get_all')) - { - $match = array( - '\\?php[\n\r\s\t]+', - '[\\?%]=', - '[\\?%][^\w]', - 'script[\n\r\s\t]+language[\n\r\s\t]*=[\n\r\s\t]*[\'"]php[\'"]' - ); - - $code = preg_replace('#<(' . implode('|', $match) . ')#is', '<$1', $code); - return; - } - } - - do - { - $tokens = token_get_all('<?php ?>' . $code); - $code = ''; - $php_found = false; - - foreach ($tokens as $i => $token) - { - if (!is_array($token)) - { - $code .= $token; - } - else if ($token[0] == T_OPEN_TAG || $token[0] == T_OPEN_TAG_WITH_ECHO || $token[0] == T_CLOSE_TAG) - { - if ($i > 1) - { - $code .= htmlspecialchars($token[1]); - $php_found = true; - } - } - else - { - $code .= $token[1]; - } - } - unset($tokens); - - // Fix for a tokenizer oddity - if (!strncmp($code, '<?php ?>', 11)) - { - $code = substr($code, 11); - } - } - while ($php_found); + // This matches the information gathered from the internal PHP lexer + $match = array( + '#<([\?%])=?.*?\1>#s', + '#<script\s+language\s*=\s*(["\']?)php\1\s*>.*?</script\s*>#s', + '#<\?php(?:\r\n?|[ \n\t]).*?\?>#s' + ); + + $code = preg_replace($match, '', $code); } /** * The all seeing all doing compile method. Parts are inspired by or directly from Smarty - * @access: private + * @access private */ function compile($code, $no_echo = false, $echo_var = '') { @@ -169,12 +110,6 @@ class template_compile // php is a no-no. There is a potential issue here in that non-php // content may be removed ... however designers should use entities // if they wish to display < and > -/* - $match_php_tags = array('#\<\?php.*?\?\>#is', '#<[^\w<]*(script)(((?:"[^"]*"|\'[^\']*\'|[^<>\'"])+)?(language[^<>\'"]+("[^"]*php[^"]*"|\'[^\']*php[^\']*\'))((?:"[^"]*"|\'[^\']*\'|[^<>\'"])+)?)?>.*?</script>#is', '#\<\?.*?\?\>#s', '#\<%.*?%\>#s'); - $code = preg_replace($match_php_tags, '', $code); -*/ - - // An alternative to the above would be calling this function which would be the ultimate solution but also has its drawbacks. $this->remove_php_tags($code); // Pull out all block/statement level elements and seperate plain text @@ -279,14 +214,14 @@ class template_compile // There will be a number of occassions where we switch into and out of // PHP mode instantaneously. Rather than "burden" the parser with this // we'll strip out such occurences, minimising such switching - $template_php = str_replace(' ?><?php ', '', $template_php); + $template_php = str_replace(' ?><?php ', ' ', $template_php); return (!$no_echo) ? $template_php : "\$$echo_var .= '" . $template_php . "'"; } /** * Compile variables - * @access: private + * @access private */ function compile_var_tags(&$text_blocks) { @@ -328,7 +263,7 @@ class template_compile /** * Compile blocks - * @access: private + * @access private */ function compile_tag_block($tag_args) { @@ -419,7 +354,7 @@ class template_compile /** * Compile IF tags - much of this is from Smarty with * some adaptions for our block level methods - * @access: private + * @access private */ function compile_tag_if($tag_args, $elseif) { @@ -533,8 +468,10 @@ class template_compile } else if (preg_match('#^\.(([a-z0-9\-_]+\.?)+)$#s', $token, $varrefs)) { + // Allow checking if loops are set with .loopname + // It is also possible to check the loop count by doing <!-- IF .loopname > 1 --> for example $_tok = $this->generate_block_data_ref($varrefs[1], false); - $token = "(isset($_tok) && sizeof($_tok))"; + $token = "sizeof($_tok)"; } break; @@ -546,7 +483,7 @@ class template_compile /** * Compile DEFINE tags - * @access: private + * @access private */ function compile_tag_define($tag_args, $op) { @@ -599,7 +536,7 @@ class template_compile /** * Compile INCLUDE tag - * @access: private + * @access private */ function compile_tag_include($tag_args) { @@ -608,21 +545,21 @@ class template_compile /** * Compile INCLUDE_PHP tag - * @access: private + * @access private */ function compile_tag_include_php($tag_args) { - return "include('" . $this->template->root . '/' . $tag_args . "');"; + return "include('" . $tag_args . "');"; } /** * parse expression * This is from Smarty - * @access: private + * @access private */ function _parse_is_expr($is_arg, $tokens) { - $expr_end = 0; + $expr_end = 0; $negate_expr = false; if (($first_token = array_shift($tokens)) == 'not') @@ -641,12 +578,12 @@ class template_compile if (@$tokens[$expr_end] == 'by') { $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!(($is_arg / $expr_arg) % $expr_arg)"; + $expr_arg = $tokens[$expr_end++]; + $expr = "!(($is_arg / $expr_arg) % $expr_arg)"; } else { - $expr = "!($is_arg % 2)"; + $expr = "!($is_arg % 2)"; } break; @@ -654,12 +591,12 @@ class template_compile if (@$tokens[$expr_end] == 'by') { $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "(($is_arg / $expr_arg) % $expr_arg)"; + $expr_arg = $tokens[$expr_end++]; + $expr = "(($is_arg / $expr_arg) % $expr_arg)"; } else { - $expr = "($is_arg % 2)"; + $expr = "($is_arg % 2)"; } break; @@ -667,18 +604,18 @@ class template_compile if (@$tokens[$expr_end] == 'by') { $expr_end++; - $expr_arg = $tokens[$expr_end++]; - $expr = "!($is_arg % $expr_arg)"; + $expr_arg = $tokens[$expr_end++]; + $expr = "!($is_arg % $expr_arg)"; } break; } if ($negate_expr) { - $expr = "!($expr)"; + $expr = "!($expr)"; } - array_splice($tokens, 0, $expr_end, $expr); + array_splice($tokens, 0, $expr_end, $expr); return $tokens; } @@ -689,7 +626,7 @@ class template_compile * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . ' * It's ready to be inserted into an "echo" line in one of the templates. * NOTE: expects a trailing "." on the namespace. - * @access: private + * @access private */ function generate_block_varref($namespace, $varname, $echo = true, $defop = false) { @@ -714,7 +651,7 @@ class template_compile * * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. * NOTE: does not expect a trailing "." on the blockname. - * @access: private + * @access private */ function generate_block_data_ref($blockname, $include_last_iterator, $defop = false) { @@ -743,7 +680,7 @@ class template_compile /** * Write compiled file to cache directory - * @access: private + * @access private */ function compile_write(&$handle, $data) { diff --git a/phpBB/includes/functions_transfer.php b/phpBB/includes/functions_transfer.php index d2cc95f728..00ef78f933 100644 --- a/phpBB/includes/functions_transfer.php +++ b/phpBB/includes/functions_transfer.php @@ -189,6 +189,24 @@ class transfer } /** + * Check if a specified file exist... + */ + function file_exists($directory, $filename) + { + global $phpbb_root_path; + + $directory = $this->root_path . str_replace($phpbb_root_path, '', $directory); + $result = $this->_ls($directory); + + if ($result !== false && is_array($result)) + { + return (in_array($filename, $result)) ? true : false; + } + + return false; + } + + /** * Open session */ function open_session() @@ -245,7 +263,7 @@ class ftp extends transfer // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end) $this->root_path = str_replace('\\', '/', $this->root_path); - $this->root_path = (($root_path{0} != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/'); + $this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/'); // Init some needed values transfer::transfer(); @@ -272,7 +290,7 @@ class ftp extends transfer /** * Init FTP Session - * @access: private + * @access private */ function _init() { @@ -304,7 +322,7 @@ class ftp extends transfer /** * Create Directory (MKDIR) - * @access: private + * @access private */ function _mkdir($dir) { @@ -313,7 +331,7 @@ class ftp extends transfer /** * Remove directory (RMDIR) - * @access: private + * @access private */ function _rmdir($dir) { @@ -322,7 +340,7 @@ class ftp extends transfer /** * Rename file - * @access: private + * @access private */ function _rename($old_handle, $new_handle) { @@ -331,7 +349,7 @@ class ftp extends transfer /** * Change current working directory (CHDIR) - * @access: private + * @access private */ function _chdir($dir = '') { @@ -345,7 +363,7 @@ class ftp extends transfer /** * change file permissions (CHMOD) - * @access: private + * @access private */ function _chmod($file, $perms) { @@ -364,7 +382,7 @@ class ftp extends transfer /** * Upload file to location (PUT) - * @access: private + * @access private */ function _put($from_file, $to_file) { @@ -386,7 +404,7 @@ class ftp extends transfer /** * Delete file (DELETE) - * @access: private + * @access private */ function _delete($file) { @@ -395,7 +413,7 @@ class ftp extends transfer /** * Close ftp session (CLOSE) - * @access: private + * @access private */ function _close() { @@ -410,7 +428,7 @@ class ftp extends transfer /** * Return current working directory (CWD) * At the moment not used by parent class - * @access: private + * @access private */ function _cwd() { @@ -419,8 +437,7 @@ class ftp extends transfer /** * Return list of files in a given directory (LS) - * At the moment not used by parent class - * @access: private + * @access private */ function _ls($dir = './') { @@ -429,7 +446,7 @@ class ftp extends transfer /** * FTP SITE command (ftp-only function) - * @access: private + * @access private */ function _site($command) { @@ -458,9 +475,9 @@ class ftp_fsock extends transfer $this->password = $password; $this->timeout = $timeout; - // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (prefixed with / and no / at the end) + // Make sure $this->root_path is layed out the same way as the $user->page['root_script_path'] value (/ at the end) $this->root_path = str_replace('\\', '/', $this->root_path); - $this->root_path = (($root_path{0} != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/'); + $this->root_path = (($root_path[0] != '/' ) ? '/' : '') . $root_path . ((substr($root_path, -1, 1) == '/') ? '' : '/'); // Init some needed values transfer::transfer(); @@ -487,7 +504,7 @@ class ftp_fsock extends transfer /** * Init FTP Session - * @access: private + * @access private */ function _init() { @@ -526,7 +543,7 @@ class ftp_fsock extends transfer /** * Create Directory (MKDIR) - * @access: private + * @access private */ function _mkdir($dir) { @@ -535,7 +552,7 @@ class ftp_fsock extends transfer /** * Remove directory (RMDIR) - * @access: private + * @access private */ function _rmdir($dir) { @@ -544,7 +561,7 @@ class ftp_fsock extends transfer /** * Rename File - * @access: private + * @access private */ function _rename($old_handle, $new_handle) { @@ -554,7 +571,7 @@ class ftp_fsock extends transfer /** * Change current working directory (CHDIR) - * @access: private + * @access private */ function _chdir($dir = '') { @@ -568,7 +585,7 @@ class ftp_fsock extends transfer /** * change file permissions (CHMOD) - * @access: private + * @access private */ function _chmod($file, $perms) { @@ -577,7 +594,7 @@ class ftp_fsock extends transfer /** * Upload file to location (PUT) - * @access: private + * @access private */ function _put($from_file, $to_file) { @@ -613,7 +630,7 @@ class ftp_fsock extends transfer /** * Delete file (DELETE) - * @access: private + * @access private */ function _delete($file) { @@ -622,7 +639,7 @@ class ftp_fsock extends transfer /** * Close ftp session (CLOSE) - * @access: private + * @access private */ function _close() { @@ -637,7 +654,7 @@ class ftp_fsock extends transfer /** * Return current working directory (CWD) * At the moment not used by parent class - * @access: private + * @access private */ function _cwd() { @@ -647,8 +664,7 @@ class ftp_fsock extends transfer /** * Return list of files in a given directory (LS) - * At the moment not used by parent class - * @access: private + * @access private */ function _ls($dir = './') { @@ -671,7 +687,7 @@ class ftp_fsock extends transfer /** * Send a command to server (FTP fsock only function) - * @access: private + * @access private */ function _send_command($command, $args = '', $check = true) { @@ -692,7 +708,7 @@ class ftp_fsock extends transfer /** * Opens a connection to send data (FTP fosck only function) - * @access: private + * @access private */ function _open_data_connection() { @@ -727,7 +743,7 @@ class ftp_fsock extends transfer /** * Closes a connection used to send data - * @access: private + * @access private */ function _close_data_connection() { @@ -736,7 +752,7 @@ class ftp_fsock extends transfer /** * Check to make sure command was successful (FTP fsock only function) - * @access: private + * @access private */ function _check_command($return = false) { diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index 28701339e4..a7a76cf526 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -38,7 +38,7 @@ class filespec /** * File Class - * @access: private + * @access private */ function filespec($upload_ary, $upload_namespace) { @@ -138,7 +138,7 @@ class filespec /** * Check if the file got correctly uploaded * - * @return true if it is a valid upload and the file exist, false if not + * @return true if it is a valid upload, false if not */ function is_uploaded() { @@ -147,7 +147,12 @@ class filespec return false; } - return (file_exists($this->filename)) ? true : false; + if ($this->local && !file_exists($this->filename)) + { + return false; + } + + return true; } /** @@ -221,24 +226,27 @@ class filespec return false; } - // Adjust destination path (no trailing slash) - if ($destination{(sizeof($destination)-1)} == '/' || $destination{(sizeof($destination)-1)} == '\\') - { - $destination = substr($destination, 0, sizeof($destination)-2); - } + // We need to trust the admin in specifying valid upload directories and an attacker not being able to overwrite it... + $this->destination_path = $phpbb_root_path . $destination; - $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination); - if ($destination && ($destination{0} == '/' || $destination{0} == "\\")) + // Check if the destination path exist... + if (!file_exists($this->destination_path)) { - $destination = ''; + @unlink($this->filename); + return false; } - $this->destination_path = $phpbb_root_path . $destination; - $upload_mode = (@ini_get('open_basedir') || @ini_get('safe_mode')) ? 'move' : 'copy'; $upload_mode = ($this->local) ? 'local' : $upload_mode; $this->destination_file = $this->destination_path . '/' . basename($this->realname); + // Check if the file already exist, else there is something wrong... + if (file_exists($this->destination_file)) + { + @unlink($this->filename); + return false; + } + switch ($upload_mode) { case 'copy': @@ -305,6 +313,25 @@ class filespec { $this->mimetype = $this->image_info['mime']; } + + // Check image type + $types = $this->upload->image_types(); + + if (!isset($types[$this->image_info[2]]) || !in_array($this->extension, $types[$this->image_info[2]])) + { + if (!isset($types[$this->image_info[2]])) + { + $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_INVALID'], $this->image_info[2], $this->mimetype); + } + else + { + $this->error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$this->image_info[2]][0], $this->extension); + } + } + } + else + { + $this->error[] = $user->lang['UNABLE_GET_IMAGE_SIZE']; } } @@ -790,6 +817,31 @@ class fileupload { return (isset($_FILES[$form_name]) && $_FILES[$form_name]['name'] != 'none') ? true : false; } + + /** + * Return image type/extension mapping + */ + function image_types() + { + return array( + 1 => array('gif'), + 2 => array('jpg', 'jpeg'), + 3 => array('png'), + 4 => array('swf'), + 5 => array('psd'), + 6 => array('bmp'), + 7 => array('tif', 'tiff'), + 8 => array('tif', 'tiff'), + 9 => array('jpg', 'jpeg'), + 10 => array('jpg', 'jpeg'), + 11 => array('jpg', 'jpeg'), + 12 => array('jpg', 'jpeg'), + 13 => array('swc'), + 14 => array('iff'), + 15 => array('wbmp'), + 16 => array('xbm'), + ); + } } ?>
\ No newline at end of file diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php index c03e92d0b0..15daa0c999 100644 --- a/phpBB/includes/functions_user.php +++ b/phpBB/includes/functions_user.php @@ -12,7 +12,7 @@ * Obtain user_ids from usernames or vice versa. Returns false on * success else the error string */ -function user_get_id_name(&$user_id_ary, &$username_ary) +function user_get_id_name(&$user_id_ary, &$username_ary, $only_active = false) { global $db; @@ -34,16 +34,22 @@ function user_get_id_name(&$user_id_ary, &$username_ary) $$which_ary = array($$which_ary); } - $sql_in = ($which_ary == 'user_id_ary') ? array_map('intval', $$which_ary) : $$which_ary; + $sql_in = ($which_ary == 'user_id_ary') ? array_map('intval', $$which_ary) : array_map('utf8_clean_string', $$which_ary); unset($$which_ary); $user_id_ary = $username_ary = array(); // Grab the user id/username records - $sql_where = ($which_ary == 'user_id_ary') ? 'user_id' : 'username'; + $sql_where = ($which_ary == 'user_id_ary') ? 'user_id' : 'username_clean'; $sql = 'SELECT user_id, username FROM ' . USERS_TABLE . ' WHERE ' . $db->sql_in_set($sql_where, $sql_in); + + if ($only_active) + { + $sql .= ' AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; + } + $result = $db->sql_query($sql); if (!($row = $db->sql_fetchrow($result))) @@ -134,6 +140,7 @@ function user_add($user_row, $cp_data = false) $sql_ary = array( 'username' => $user_row['username'], + 'username_clean' => utf8_clean_string($user_row['username']), 'user_password' => (isset($user_row['user_password'])) ? $user_row['user_password'] : '', 'user_email' => $user_row['user_email'], 'user_email_hash' => (int) crc32(strtolower($user_row['user_email'])) . strlen($user_row['user_email']), @@ -141,10 +148,6 @@ function user_add($user_row, $cp_data = false) 'user_type' => $user_row['user_type'], ); - /** - * @todo user_allow_email is not used anywhere. Think about removing it. - */ - // These are the additional vars able to be specified $additional_vars = array( 'user_permissions' => '', @@ -156,7 +159,10 @@ function user_add($user_row, $cp_data = false) 'user_actkey' => '', 'user_ip' => '', 'user_regdate' => time(), + 'user_passchg' => time(), + 'user_inactive_reason' => 0, + 'user_inactive_time' => 0, 'user_lastmark' => time(), 'user_lastvisit' => 0, 'user_lastpost_time' => 0, @@ -164,6 +170,7 @@ function user_add($user_row, $cp_data = false) 'user_posts' => 0, 'user_dst' => 0, 'user_colour' => '', + 'user_interests' => '', 'user_avatar' => '', 'user_avatar_type' => 0, 'user_avatar_width' => 0, @@ -179,7 +186,6 @@ function user_add($user_row, $cp_data = false) 'user_notify_pm' => 1, 'user_notify_type' => NOTIFY_EMAIL, 'user_allow_pm' => 1, - 'user_allow_email' => 1, 'user_allow_viewonline' => 1, 'user_allow_viewemail' => 1, 'user_allow_massemail' => 1, @@ -254,39 +260,67 @@ function user_add($user_row, $cp_data = false) */ function user_delete($mode, $user_id, $post_username = false) { - global $config, $db, $user, $auth; + global $cache, $config, $db, $user, $auth; + global $phpbb_root_path, $phpEx; $db->sql_transaction('begin'); switch ($mode) { case 'retain': + + if ($post_username === false) + { + $post_username = $user->lang['GUEST']; + } + $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_last_poster_id = ' . ANONYMOUS . (($post_username !== false) ? ", forum_last_poster_name = '" . $db->sql_escape($post_username) . "'" : '') . " + SET forum_last_poster_id = ' . ANONYMOUS . ", forum_last_poster_name = '" . $db->sql_escape($post_username) . "', forum_last_poster_colour = '' WHERE forum_last_poster_id = $user_id"; $db->sql_query($sql); $sql = 'UPDATE ' . POSTS_TABLE . ' - SET poster_id = ' . ANONYMOUS . (($post_username !== false) ? ", post_username = '" . $db->sql_escape($post_username) . "'" : '') . " + SET poster_id = ' . ANONYMOUS . ", post_username = '" . $db->sql_escape($post_username) . "' WHERE poster_id = $user_id"; $db->sql_query($sql); + $sql = 'UPDATE ' . POSTS_TABLE . ' + SET post_edit_user = ' . ANONYMOUS . " + WHERE post_edit_user = $user_id"; + $db->sql_query($sql); + $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_poster = ' . ANONYMOUS . " + SET topic_poster = ' . ANONYMOUS . ", topic_first_poster_name = '" . $db->sql_escape($post_username) . "', topic_first_poster_colour = '' WHERE topic_poster = $user_id"; $db->sql_query($sql); $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_last_poster_id = ' . ANONYMOUS . (($post_username !== false) ? ", topic_last_poster_name = '" . $db->sql_escape($post_username) . "'" : '') . " + SET topic_last_poster_id = ' . ANONYMOUS . ", topic_last_poster_name = '" . $db->sql_escape($post_username) . "', topic_last_poster_colour = '' WHERE topic_last_poster_id = $user_id"; $db->sql_query($sql); + + // Since we change every post by this author, we need to count this amount towards the anonymous user + $sql = 'SELECT user_posts + FROM ' . USERS_TABLE . ' + WHERE user_id = ' . $user_id; + $result = $db->sql_query($sql); + $num_posts = (int) $db->sql_fetchfield('user_posts'); + $db->sql_freeresult($result); + + // Update the post count for the anonymous user + if ($num_posts) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_posts = user_posts + ' . $num_posts . ' + WHERE user_id = ' . ANONYMOUS; + $db->sql_query($sql); + } break; case 'remove': if (!function_exists('delete_posts')) { - global $phpbb_root_path, $phpEx; include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx); } @@ -334,7 +368,7 @@ function user_delete($mode, $user_id, $post_username = false) break; } - $table_ary = array(USERS_TABLE, USER_GROUP_TABLE, TOPICS_WATCH_TABLE, FORUMS_WATCH_TABLE, ACL_USERS_TABLE, TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, FORUMS_TRACK_TABLE, PROFILE_FIELDS_DATA_TABLE); + $table_ary = array(USERS_TABLE, USER_GROUP_TABLE, TOPICS_WATCH_TABLE, FORUMS_WATCH_TABLE, ACL_USERS_TABLE, TOPICS_TRACK_TABLE, TOPICS_POSTED_TABLE, FORUMS_TRACK_TABLE, PROFILE_FIELDS_DATA_TABLE, MODERATOR_CACHE_TABLE); foreach ($table_ary as $table) { @@ -343,6 +377,67 @@ function user_delete($mode, $user_id, $post_username = false) $db->sql_query($sql); } + $cache->destroy('sql', MODERATOR_CACHE_TABLE); + + include_once($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); + + // Remove any undelivered mails... + $sql = 'SELECT msg_id, user_id + FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE author_id = ' . $user_id . ' + AND folder_id = ' . PRIVMSGS_NO_BOX; + $result = $db->sql_query($sql); + + $undelivered_msg = $undelivered_user = array(); + while ($row = $db->sql_fetchrow($result)) + { + $undelivered_msg[] = $row['msg_id']; + $undelivered_user[$row['user_id']][] = true; + } + $db->sql_freeresult($result); + + if (sizeof($undelivered_msg)) + { + $sql = 'DELETE FROM ' . PRIVMSGS_TABLE . ' + WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg); + $db->sql_query($sql); + } + + $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE author_id = ' . $user_id . ' + AND folder_id = ' . PRIVMSGS_NO_BOX; + $db->sql_query($sql); + + // Delete all to-informations + $sql = 'DELETE FROM ' . PRIVMSGS_TO_TABLE . ' + WHERE user_id = ' . $user_id; + $db->sql_query($sql); + + // Set the remaining author id to anonymous - this way users are still able to read messages from users being removed + $sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' + SET author_id = ' . ANONYMOUS . ' + WHERE author_id = ' . $user_id; + $db->sql_query($sql); + + $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' + SET author_id = ' . ANONYMOUS . ' + WHERE author_id = ' . $user_id; + $db->sql_query($sql); + + foreach ($undelivered_user as $_user_id => $ary) + { + if ($_user_id == $user_id) + { + continue; + } + + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_new_privmsg = user_new_privmsg - ' . sizeof($ary) . ', + user_unread_privmsg = user_unread_privmsg - ' . sizeof($ary) . ' + WHERE user_id = ' . $_user_id; + $db->sql_query($sql); + } + // Reset newest user info if appropriate if ($config['newest_user_id'] == $user_id) { @@ -351,98 +446,96 @@ function user_delete($mode, $user_id, $post_username = false) set_config('num_users', $config['num_users'] - 1, true); - // Adjust last post info... - - $db->sql_transaction('commit'); return false; } /** -* Flips user_type from active to inactive and vice versa, handles -* group membership updates +* Flips user_type from active to inactive and vice versa, handles group membership updates +* +* @param string $mode can be flip for flipping from active/inactive, activate or deactivate */ -function user_active_flip($user_id, $user_type, $user_actkey = false, $username = false, $no_log = false) +function user_active_flip($mode, $user_id_ary, $reason = INACTIVE_MANUAL) { - global $db, $user, $auth; + global $config, $db, $user, $auth; - $sql = 'SELECT group_id, group_name - FROM ' . GROUPS_TABLE . " - WHERE group_name IN ('REGISTERED', 'REGISTERED_COPPA', 'INACTIVE', 'INACTIVE_COPPA')"; - $result = $db->sql_query($sql); + $deactivated = $activated = 0; + $sql_statements = array(); - $group_id_ary = array(); - while ($row = $db->sql_fetchrow($result)) + if (!is_array($user_id_ary)) { - $group_id_ary[$row['group_name']] = $row['group_id']; + $user_id_ary = array($user_id_ary); + } + + if (!sizeof($user_id_ary)) + { + return; } - $db->sql_freeresult($result); - $sql = 'SELECT group_id - FROM ' . USER_GROUP_TABLE . " - WHERE user_id = $user_id"; + $sql = 'SELECT user_id, group_id, user_type, user_inactive_reason + FROM ' . USERS_TABLE . ' + WHERE ' . $db->sql_in_set('user_id', $user_id_ary); $result = $db->sql_query($sql); - $group_name = ($user_type == USER_NORMAL) ? 'REGISTERED' : 'INACTIVE'; while ($row = $db->sql_fetchrow($result)) { - if ($name = array_search($row['group_id'], $group_id_ary)) + $sql_ary = array(); + + if ($row['user_type'] == USER_IGNORE || $row['user_type'] == USER_FOUNDER || + ($mode == 'activate' && $row['user_type'] != USER_INACTIVE) || + ($mode == 'deactivate' && $row['user_type'] == USER_INACTIVE)) { - $group_name = $name; - break; + continue; } - } - $db->sql_freeresult($result); - $current_group = ($user_type == USER_NORMAL) ? 'REGISTERED' : 'INACTIVE'; - $switch_group = ($user_type == USER_NORMAL) ? 'INACTIVE' : 'REGISTERED'; + if ($row['user_type'] == USER_INACTIVE) + { + $activated++; + } + else + { + $deactivated++; - $new_group_id = $group_id_ary[str_replace($current_group, $switch_group, $group_name)]; + // Remove the users session key... + $user->reset_login_keys($row['user_id']); + } - $sql = 'UPDATE ' . USER_GROUP_TABLE . " - SET group_id = $new_group_id - WHERE user_id = $user_id - AND group_id = " . $group_id_ary[$group_name]; - $db->sql_query($sql); + $sql_ary += array( + 'user_type' => ($row['user_type'] == USER_NORMAL) ? USER_INACTIVE : USER_NORMAL, + 'user_inactive_time' => ($row['user_type'] == USER_NORMAL) ? time() : 0, + 'user_inactive_reason' => ($row['user_type'] == USER_NORMAL) ? $reason : 0, + ); - $sql_ary = array( - 'user_type' => ($user_type == USER_NORMAL) ? USER_INACTIVE : USER_NORMAL - ); + $sql_statements[$row['user_id']] = $sql_ary; + } + $db->sql_freeresult($result); - if ($new_group_id == $group_id_ary[$group_name]) + if (sizeof($sql_statements)) { - $sql_ary['group_id'] = $new_group_id; + foreach ($sql_statements as $user_id => $sql_ary) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE user_id = ' . $user_id; + $db->sql_query($sql); + } + + $auth->acl_clear_prefetch(array_keys($sql_statements)); } - if ($user_actkey !== false) + if ($deactivated) { - $sql_ary['user_actkey'] = $user_actkey; + set_config('num_users', $config['num_users'] - $deactivated, true); } - $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - - $auth->acl_clear_prefetch($user_id); - - if (!$no_log) + if ($activated) { - if ($username === false) - { - $sql = 'SELECT username - FROM ' . USERS_TABLE . " - WHERE user_id = $user_id"; - $result = $db->sql_query($sql); - $username = (string) $db->sql_fetchfield('username'); - $db->sql_freeresult($result); - } - - $log = ($user_type == USER_NORMAL) ? 'LOG_USER_INACTIVE' : 'LOG_USER_ACTIVE'; - add_log('admin', $log, $username); + set_config('num_users', $config['num_users'] + $activated, true); } - return false; + // Update latest username + update_last_username(); } /** @@ -528,7 +621,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas $username = trim($username); if ($username != '') { - $sql_usernames[] = strtolower($username); + $sql_usernames[] = utf8_clean_string($username); } } @@ -540,11 +633,16 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas $sql = 'SELECT user_id FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('LOWER(username)', $sql_usernames); + WHERE ' . $db->sql_in_set('username_clean', $sql_usernames); + // Do not allow banning yourself if (sizeof($founder)) { - $sql .= ' AND ' . $db->sql_in_set('user_id', array_keys($founder), true); + $sql .= ' AND ' . $db->sql_in_set('user_id', array_merge(array_keys($founder), array($user->data['user_id'])), true); + } + else + { + $sql .= ' AND user_id <> ' . $user->data['user_id']; } $result = $db->sql_query($sql); @@ -736,24 +834,7 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas ); } - if (sizeof($sql_ary)) - { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query('INSERT INTO ' . BANLIST_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $sql_ary)); - break; - - default: - foreach ($sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . BANLIST_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } - } + $db->sql_multi_insert(BANLIST_TABLE, $sql_ary); // If we are banning we want to logout anyone matching the ban if (!$ban_exclude) @@ -973,11 +1054,11 @@ function validate_string($string, $optional = false, $min = 0, $max = 0) return false; } - if ($min && strlen($string) < $min) + if ($min && utf8_strlen(htmlspecialchars_decode($string)) < $min) { return 'TOO_SHORT'; } - else if ($max && strlen($string) > $max) + else if ($max && utf8_strlen(htmlspecialchars_decode($string)) > $max) { return 'TOO_LONG'; } @@ -1034,25 +1115,28 @@ function validate_match($string, $optional = false, $match) * Also checks if it includes the " character, which we don't allow in usernames. * Used for registering, changing names, and posting anonymously with a username * +* @todo do we really check and disallow the " character in usernames as written above. Has it only be forgotten to include the check? * @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) */ function validate_username($username) { - global $config, $db, $user; + global $config, $db, $user, $cache; - if (strtolower($user->data['username']) == strtolower($username)) + $clean_username = utf8_clean_string($username); + + if (utf8_clean_string($user->data['username']) == $clean_username) { return false; } - if (!preg_match('#^' . str_replace('\\\\', '\\', $config['allow_name_chars']) . '$#i', $username)) + if (!preg_match('#^' . str_replace('\\\\', '\\', $config['allow_name_chars']) . '$#i', $username) || strpos($username, '"') !== false || strpos($username, '"') !== false) { return 'INVALID_CHARS'; } $sql = 'SELECT username FROM ' . USERS_TABLE . " - WHERE LOWER(username) = '" . strtolower($db->sql_escape($username)) . "'"; + WHERE username_clean = '" . $db->sql_escape($clean_username) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -1064,7 +1148,7 @@ function validate_username($username) $sql = 'SELECT group_name FROM ' . GROUPS_TABLE . " - WHERE LOWER(group_name) = '" . strtolower($db->sql_escape($username)) . "'"; + WHERE LOWER(group_name) = '" . $db->sql_escape(utf8_strtolower($username)) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -1074,19 +1158,16 @@ function validate_username($username) return 'USERNAME_TAKEN'; } - $sql = 'SELECT disallow_username - FROM ' . DISALLOW_TABLE; - $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) + $bad_usernames = $cache->obtain_disallowed_usernames(); + + foreach ($bad_usernames as $bad_username) { - if (preg_match('#^' . str_replace('%', '.*?', preg_quote($row['disallow_username'], '$#')) . '#i', $username)) + if (preg_match('#^' . $bad_username . '#', $clean_username)) { - $db->sql_freeresult($result); return 'USERNAME_DISALLOWED'; } } - $db->sql_freeresult($result); $sql = 'SELECT word FROM ' . WORDS_TABLE; @@ -1106,6 +1187,29 @@ function validate_username($username) } /** +* Check to see if the password meets the complexity settings +* +* @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) +*/ +function validate_password($password) +{ + global $config, $db, $user; + + if (!$password) + { + return false; + } + + // We only check for existance of characters + if (!preg_match('#' . str_replace('\\\\', '\\', $config['pass_complex']) . '#i', $password)) + { + return 'INVALID_CHARS'; + } + + return false; +} + +/** * Check to see if email address is banned or already present in the DB * * @return boolean|string Either false if validation succeeded or a string which will be used as the error message (with the variable name appended) @@ -1124,6 +1228,18 @@ function validate_email($email) return 'EMAIL_INVALID'; } + // Check MX record. + // The idea for this is from reading the UseBB blog/announcement. :) + if ($config['email_check_mx']) + { + list(, $domain) = explode('@', $email); + + if (phpbb_checkdnsrr($domain, 'MX') === false) + { + return 'DOMAIN_NO_MX_RECORD'; + } + } + if ($user->check_ban(false, false, $email, true) == true) { return 'EMAIL_BANNED'; @@ -1150,13 +1266,23 @@ function validate_email($email) /** * Remove avatar */ -function avatar_delete($id) +function avatar_delete($mode, $row) { global $phpbb_root_path, $config, $db, $user; - if (file_exists($phpbb_root_path . $config['avatar_path'] . '/' . basename($id))) + // Check if the users avatar is actually *not* a group avatar + if ($mode == 'user') { - @unlink($phpbb_root_path . $config['avatar_path'] . '/' . basename($id)); + if (strpos($row['user_avatar'], 'g' . $row['group_id'] . '_') === 0 || strpos($row['user_avatar'], $row['user_id'] . '_') !== 0) + { + return false; + } + } + + if (file_exists($phpbb_root_path . $config['avatar_path'] . '/' . basename($row[$mode . '_avatar']))) + { + @unlink($phpbb_root_path . $config['avatar_path'] . '/' . basename($row[$mode . '_avatar'])); + return true; } return false; @@ -1167,7 +1293,7 @@ function avatar_delete($id) */ function avatar_remote($data, &$error) { - global $config, $db, $user, $phpbb_root_path; + global $config, $db, $user, $phpbb_root_path, $phpEx; if (!preg_match('#^(http|https|ftp)://#i', $data['remotelink'])) { @@ -1196,6 +1322,24 @@ function avatar_remote($data, &$error) return false; } + // Check image type + include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx); + $types = fileupload::image_types(); + $extension = strtolower(filespec::get_extension($data['remotelink'])); + + if (!isset($types[$image_data[2]]) || !in_array($extension, $types[$image_data[2]])) + { + if (!isset($types[$image_data[2]])) + { + $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE']; + } + else + { + $error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$image_data[2]][0], $extension); + } + return false; + } + if ($config['avatar_max_width'] || $config['avatar_max_height']) { if ($width > $config['avatar_max_width'] || $height > $config['avatar_max_height']) @@ -1238,7 +1382,21 @@ function avatar_upload($data, &$error) } $file->clean_filename('real', $data['user_id'] . '_'); - $file->move_file($config['avatar_path']); + + $destination = $config['avatar_path']; + + if ($destination{(sizeof($destination)-1)} == '/' || $destination{(sizeof($destination)-1)} == '\\') + { + $destination = substr($destination, 0, sizeof($destination)-2); + } + + $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination); + if ($destination && ($destination[0] == '/' || $destination[0] == "\\")) + { + $destination = ''; + } + + $file->move_file($destination); if (sizeof($file->error)) { @@ -1272,7 +1430,7 @@ function avatar_gallery($category, $avatar_select, $items_per_column, $block_var while (($file = readdir($dp)) !== false) { - if ($file{0} != '.' && is_dir("$path/$file")) + if ($file[0] != '.' && is_dir("$path/$file")) { $avatar_row_count = $avatar_col_count = 0; @@ -1376,12 +1534,12 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow $group_only_ary = array('group_receive_pm', 'group_legend', 'group_message_limit'); // Check data - if (!strlen($name) || strlen($name) > 40) + if (!utf8_strlen($name) || utf8_strlen($name) > 40) { - $error[] = (!strlen($name)) ? $user->lang['GROUP_ERR_USERNAME'] : $user->lang['GROUP_ERR_USER_LONG']; + $error[] = (!utf8_strlen($name)) ? $user->lang['GROUP_ERR_USERNAME'] : $user->lang['GROUP_ERR_USER_LONG']; } - if (strlen($desc) > 255) + if (utf8_strlen($desc) > 255) { $error[] = $user->lang['GROUP_ERR_DESC_LONG']; } @@ -1455,33 +1613,30 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow continue; } - $sql_ary[str_replace('group', 'user', $attribute)] = $group_attributes[$attribute]; + $sql_ary[$attribute] = $group_attributes[$attribute]; } } } if (sizeof($sql_ary)) { - // Before we update the user attributes, we will make a list of those having now the group avatar assigned - if (in_array('user_avatar', array_keys($sql_ary))) - { - // Ok, get the original avatar data from users having an uploaded one (we need to remove these from the filesystem) - $sql = 'SELECT user_id, user_avatar - FROM ' . USERS_TABLE . ' - WHERE group_id = ' . $group_id . ' - AND user_avatar_type = ' . AVATAR_UPLOAD; - $result = $db->sql_query($sql); + $sql = 'SELECT user_id + FROM ' . USERS_TABLE . ' + WHERE group_id = ' . $group_id; + $result = $db->sql_query($sql); - while ($row = $db->sql_fetchrow($result)) - { - avatar_delete($row['user_avatar']); - } - $db->sql_freeresult($result); + $user_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $user_ary[] = $row['user_id']; } - $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " - WHERE group_id = $group_id"; - $db->sql_query($sql); + $db->sql_freeresult($result); + + if (sizeof($user_ary)) + { + group_set_user_default($group_id, $user_ary, $sql_ary); + } } $name = ($type == GROUP_SPECIAL) ? $user->lang['G_' . $name] : $name; @@ -1496,7 +1651,7 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow */ function group_delete($group_id, $group_name = false) { - global $db; + global $db, $phpbb_root_path, $phpEx; if (!$group_name) { @@ -1548,6 +1703,11 @@ function group_delete($group_id, $group_name = false) $db->sql_query($sql); // Re-cache moderators + if (!function_exists('cache_moderators')) + { + include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); + } + cache_moderators(); add_log('admin', 'LOG_GROUP_DELETE', $group_name); @@ -1557,6 +1717,8 @@ function group_delete($group_id, $group_name = false) /** * Add user(s) to group +* +* @return false if no errors occurred, else the user lang string for the relevant error, for example 'NO_USER' */ function group_user_add($group_id, $user_id_ary = false, $username_ary = false, $group_name = false, $default = false, $leader = 0, $pending = 0, $group_attributes = false) { @@ -1580,11 +1742,11 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false, $add_id_ary = $update_id_ary = array(); while ($row = $db->sql_fetchrow($result)) { - $add_id_ary[] = $row['user_id']; + $add_id_ary[] = (int) $row['user_id']; if ($leader && !$row['group_leader']) { - $update_id_ary[] = $row['user_id']; + $update_id_ary[] = (int) $row['user_id']; } } $db->sql_freeresult($result); @@ -1598,31 +1760,24 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false, return 'GROUP_USERS_EXIST'; } + $db->sql_transaction('begin'); + + // Insert the new users if (sizeof($add_id_ary)) { - // Insert the new users - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - case 'mssql': - case 'mssql_odbc': - case 'sqlite': - $sql = 'INSERT INTO ' . USER_GROUP_TABLE . " (user_id, group_id, group_leader, user_pending) - VALUES " . implode(', ', preg_replace('#^([0-9]+)$#', "(\\1, $group_id, $leader, $pending)", $add_id_ary)); - $db->sql_query($sql); - break; + $sql_ary = array(); - default: - foreach ($add_id_ary as $user_id) - { - $sql = 'INSERT INTO ' . USER_GROUP_TABLE . " (user_id, group_id, group_leader, user_pending) - VALUES ($user_id, $group_id, $leader, $pending)"; - $db->sql_query($sql); - } - break; + foreach ($add_id_ary as $user_id) + { + $sql_ary[] = array( + 'user_id' => $user_id, + 'group_id' => $group_id, + 'group_leader' => $leader, + 'user_pending' => $pending, + ); } + + $db->sql_multi_insert(USER_GROUP_TABLE, $sql_ary); } if (sizeof($update_id_ary)) @@ -1639,6 +1794,8 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false, group_set_user_default($group_id, $user_id_ary, $group_attributes); } + $db->sql_transaction('commit'); + // Clear permissions cache of relevant users $auth->acl_clear_prefetch($user_id_ary); @@ -1651,13 +1808,18 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false, add_log('admin', $log, $group_name, implode(', ', $username_ary)); - return ($leader) ? 'GROUP_LEADERS_ADDED' : 'GROUP_USERS_ADDED'; + group_update_listings($group_id); + + // Return false - no error + return false; } /** * Remove a user/s from a given group. When we remove users we update their * default group_id. We do this by examining which "special" groups they belong * to. The selection is made based on a reasonable priority system +* +* @return false if no errors occurred, else the user lang string for the relevant error, for example 'NO_USER' */ function group_user_del($group_id, $user_id_ary = false, $username_ary = false, $group_name = false) { @@ -1684,18 +1846,18 @@ function group_user_del($group_id, $user_id_ary = false, $username_ary = false, $group_order_id[$row['group_name']] = $row['group_id']; $special_group_data[$row['group_id']] = array( - 'user_colour' => $row['group_colour'], - 'user_rank' => $row['group_rank'], + 'group_colour' => $row['group_colour'], + 'group_rank' => $row['group_rank'], ); // Only set the group avatar if one is defined... if ($row['group_avatar']) { $special_group_data[$row['group_id']] = array_merge($special_group_data[$row['group_id']], array( - 'user_avatar' => $row['group_avatar'], - 'user_avatar_type' => $row['group_avatar_type'], - 'user_avatar_width' => $row['group_avatar_width'], - 'user_avatar_height' => $row['group_avatar_height']) + 'group_avatar' => $row['group_avatar'], + 'group_avatar_type' => $row['group_avatar_type'], + 'group_avatar_width' => $row['group_avatar_width'], + 'group_avatar_height' => $row['group_avatar_height']) ); } } @@ -1745,28 +1907,7 @@ function group_user_del($group_id, $user_id_ary = false, $username_ary = false, { if (isset($sql_where_ary[$gid]) && sizeof($sql_where_ary[$gid])) { - $special_group_data[$gid]['group_id'] = $gid; - - // Before we update the user attributes, we will make a list of those having now the group avatar assigned - if (in_array('user_avatar', array_keys($special_group_data[$gid]))) - { - // Ok, get the original avatar data from users having an uploaded one (we need to remove these from the filesystem) - $sql = 'SELECT user_id, user_avatar - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $sql_where_ary[$gid]) . ' - AND user_avatar_type = ' . AVATAR_UPLOAD; - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - avatar_delete($row['user_avatar']); - } - $db->sql_freeresult($result); - } - - $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $special_group_data[$gid]) . ' - WHERE ' . $db->sql_in_set('user_id', $sql_where_ary[$gid]); - $db->sql_query($sql); + group_set_user_default($gid, $sql_where_ary[$gid], $special_group_data[$gid]); } } unset($special_group_data); @@ -1788,7 +1929,8 @@ function group_user_del($group_id, $user_id_ary = false, $username_ary = false, add_log('admin', $log, $group_name, implode(', ', $username_ary)); - return 'GROUP_USERS_REMOVE'; + // Return false - no error + return false; } /** @@ -1857,8 +1999,6 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); $messenger = new messenger(); - $email_sig = str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']); - foreach ($email_users as $row) { $messenger->template('group_approved', $row['user_lang']); @@ -1868,11 +2008,8 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna $messenger->im($row['user_jabber'], $row['username']); $messenger->assign_vars(array( - 'EMAIL_SIG' => $email_sig, - 'SITENAME' => $config['sitename'], - 'USERNAME' => html_entity_decode($row['username']), - 'GROUP_NAME' => html_entity_decode($group_name), - + 'USERNAME' => htmlspecialchars_decode($row['username']), + 'GROUP_NAME' => htmlspecialchars_decode($group_name), 'U_GROUP' => generate_board_url() . "/ucp.$phpEx?i=groups&mode=membership") ); @@ -1954,7 +2091,7 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal if (in_array('user_avatar', array_keys($sql_ary))) { // Ok, get the original avatar data from users having an uploaded one (we need to remove these from the filesystem) - $sql = 'SELECT user_id, user_avatar + $sql = 'SELECT user_id, group_id, user_avatar FROM ' . USERS_TABLE . ' WHERE ' . $db->sql_in_set('user_id', $user_id_ary) . ' AND user_avatar_type = ' . AVATAR_UPLOAD; @@ -1962,7 +2099,7 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal while ($row = $db->sql_fetchrow($result)) { - avatar_delete($row['user_avatar']); + avatar_delete('user', $row); } $db->sql_freeresult($result); } @@ -1970,6 +2107,22 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' WHERE ' . $db->sql_in_set('user_id', $user_id_ary); $db->sql_query($sql); + + if (in_array('user_colour', array_keys($sql_ary))) + { + // Update any cached colour information for these users + $sql = 'UPDATE ' . FORUMS_TABLE . " SET forum_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' + WHERE " . $db->sql_in_set('forum_last_poster_id', $user_id_ary); + $db->sql_query($sql); + + $sql = 'UPDATE ' . TOPICS_TABLE . " SET topic_first_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' + WHERE " . $db->sql_in_set('topic_poster', $user_id_ary); + $db->sql_query($sql); + + $sql = 'UPDATE ' . TOPICS_TABLE . " SET topic_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "' + WHERE " . $db->sql_in_set('topic_last_poster_id', $user_id_ary); + $db->sql_query($sql); + } } /** @@ -2062,4 +2215,64 @@ function group_memberships($group_id_ary = false, $user_id_ary = false, $return_ return $return; } +/** +* Re-cache moderators and foes if group has a_ or m_ permissions +*/ +function group_update_listings($group_id) +{ + global $auth; + + $hold_ary = $auth->acl_group_raw_data($group_id, array('a_', 'm_')); + + if (!sizeof($hold_ary)) + { + return; + } + + $mod_permissions = $admin_permissions = false; + + foreach ($hold_ary as $g_id => $forum_ary) + { + foreach ($forum_ary as $forum_id => $auth_ary) + { + foreach ($auth_ary as $auth_option => $setting) + { + if ($mod_permissions && $admin_permissions) + { + break 3; + } + + if ($setting != ACL_YES) + { + continue; + } + + if ($auth_option == 'm_') + { + $mod_permissions = true; + } + + if ($auth_option == 'a_') + { + $admin_permissions = true; + } + } + } + } + + if ($mod_permissions) + { + if (!function_exists('cache_moderators')) + { + include($phpbb_root_path . 'includes/functions_admin.' . $phpEx); + } + cache_moderators(); + } + + if ($mod_permissions || $admin_permissions) + { + update_foes(); + } +} + ?>
\ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index 09470b8269..b20bd63a08 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -74,6 +74,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info) 'S_CAN_LOCK' => $auth->acl_get('m_lock', $forum_id), 'S_CAN_SYNC' => $auth->acl_get('m_', $forum_id), 'S_CAN_APPROVE' => $auth->acl_get('m_approve', $forum_id), + 'S_MERGE_SELECT' => ($action == 'merge_select') ? true : false, 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id), 'U_VIEW_FORUM_LOGS' => ($auth->acl_gets('a_', 'm_', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=logs&mode=forum_logs&f=' . $forum_id) : '', @@ -86,8 +87,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info) ); // Grab icons - $icons = array(); - $cache->obtain_icons($icons); + $icons = $cache->obtain_icons(); $topic_rows = array(); @@ -117,8 +117,8 @@ function mcp_forum_view($id, $mode, $action, $forum_info) $topic_title = censor_text($row['topic_title']); - $topic_unapproved = (!$row['topic_approved'] && $auth->acl_gets('m_approve', $row['forum_id'])) ? true : false; - $posts_unapproved = ($row['topic_approved'] && $row['topic_replies'] < $row['topic_replies_real'] && $auth->acl_gets('m_approve', $row['forum_id'])) ? true : false; + $topic_unapproved = (!$row['topic_approved'] && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false; + $posts_unapproved = ($row['topic_approved'] && $row['topic_replies'] < $row['topic_replies_real'] && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false; $u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? $url . '&i=queue&mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . '&t=' . $row['topic_id'] : ''; $template->assign_block_vars('topicrow', array( @@ -129,7 +129,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info) 'U_MCP_QUEUE' => $u_mcp_queue, 'U_MCP_REPORT' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main&mode=topic_view&t=' . $row['topic_id'] . '&action=reports'), - 'ATTACH_ICON_IMG' => ($auth->acl_gets('f_download', 'u_download', $row['forum_id']) && $row['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', + 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']) && $row['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt), 'TOPIC_FOLDER_IMG_SRC' => $user->img($folder_img, $folder_alt, false, '', 'src'), 'TOPIC_ICON_IMG' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['img'] : '', @@ -144,7 +144,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info) 'TOPIC_ID' => $row['topic_id'], 'S_TOPIC_CHECKED' => ($topic_id_list && in_array($row['topic_id'], $topic_id_list)) ? 'checked="checked" ' : '', - 'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && $auth->acl_gets('m_report', $row['forum_id'])) ? true : false, + 'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && $auth->acl_get('m_report', $row['forum_id'])) ? true : false, 'S_TOPIC_UNAPPROVED' => $topic_unapproved, 'S_POSTS_UNAPPROVED' => $posts_unapproved) ); @@ -191,7 +191,7 @@ function mcp_resync_topics($topic_ids) $redirect = request_var('redirect', $user->data['session_page']); - meta_refresh(2, $redirect); + meta_refresh(3, $redirect); trigger_error($msg . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>')); return; diff --git a/phpBB/includes/mcp/mcp_front.php b/phpBB/includes/mcp/mcp_front.php index 745b2c0d61..8b798fc1b2 100644 --- a/phpBB/includes/mcp/mcp_front.php +++ b/phpBB/includes/mcp/mcp_front.php @@ -114,7 +114,7 @@ function mcp_front_view($id, $mode, $action) } // Latest 5 reported - $forum_list = get_forum_list('m_'); + $forum_list = get_forum_list('m_report'); $template->assign_var('S_SHOW_REPORTS', (!empty($forum_list)) ? true : false); diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index b77c3e4451..1fe9233ba9 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -207,9 +207,18 @@ function lock_unlock($action, $ids) $l_prefix = 'POST'; } - if (!($forum_id = check_ids($ids, $table, $sql_id, array('f_user_lock', 'm_lock')))) + if (!($forum_id = check_ids($ids, $table, $sql_id, array('m_lock')))) { - return; + // Make sure that for f_user_lock only the lock action is triggered. + if ($action != 'lock') + { + return; + } + + if (!($forum_id = check_ids($ids, $table, $sql_id, array('f_user_lock')))) + { + return; + } } $redirect = request_var('redirect', $user->data['session_page']); @@ -474,8 +483,17 @@ function mcp_move_topic($topic_ids) $forum_ids[] = $row['forum_id']; add_log('mod', $to_forum_id, $topic_id, 'LOG_MOVE', $row['forum_name']); + // If we have moved a global announcement, we need to correct the topic type + if ($row['topic_type'] == POST_GLOBAL) + { + $sql = 'UPDATE ' . TOPICS_TABLE . ' + SET topic_type = ' . POST_ANNOUNCE . ' + WHERE topic_id = ' . (int) $row['topic_id']; + $db->sql_query($sql); + } + // Leave a redirection if required and only if the topic is visible to users - if ($leave_shadow && $row['topic_approved']) + if ($leave_shadow && $row['topic_approved'] && $row['topic_type'] != POST_GLOBAL) { $shadow = array( 'forum_id' => (int) $row['forum_id'], @@ -884,7 +902,6 @@ function mcp_fork_topic($topic_ids) 'post_edit_reason' => (string) $row['post_edit_reason'], 'post_edit_user' => (int) $row['post_edit_user'], 'post_checksum' => (string) $row['post_checksum'], - 'post_encoding' => (string) $row['post_encoding'], 'post_attachment' => (int) $row['post_attachment'], 'bbcode_bitfield' => $row['bbcode_bitfield'], 'bbcode_uid' => (string) $row['bbcode_uid'], diff --git a/phpBB/includes/mcp/mcp_notes.php b/phpBB/includes/mcp/mcp_notes.php index cc4ed0e72b..302ace9755 100755 --- a/phpBB/includes/mcp/mcp_notes.php +++ b/phpBB/includes/mcp/mcp_notes.php @@ -68,13 +68,13 @@ class mcp_notes global $template, $db, $user, $auth; $user_id = request_var('u', 0); - $username = request_var('username', ''); + $username = request_var('username', '', true); $start = request_var('start', 0); $st = request_var('st', 0); $sk = request_var('sk', 'b'); $sd = request_var('sd', 'd'); - $sql_where = ($user_id) ? "user_id = $user_id" : "username = '" . $db->sql_escape($username) . "'"; + $sql_where = ($user_id) ? "user_id = $user_id" : "username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $sql = 'SELECT * FROM ' . USERS_TABLE . " @@ -161,7 +161,7 @@ class mcp_notes $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); $sort_by_text = array('a' => $user->lang['SORT_USERNAME'], 'b' => $user->lang['SORT_DATE'], 'c' => $user->lang['SORT_IP'], 'd' => $user->lang['SORT_ACTION']); - $sort_by_sql = array('a' => 'l.username', 'b' => 'l.log_time', 'c' => 'l.log_ip', 'd' => 'l.log_operation'); + $sort_by_sql = array('a' => 'u.username', 'b' => 'l.log_time', 'c' => 'l.log_ip', 'd' => 'l.log_operation'); $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; gen_sort_selects($limit_days, $sort_by_text, $st, $sk, $sd, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); diff --git a/phpBB/includes/mcp/mcp_post.php b/phpBB/includes/mcp/mcp_post.php index 08bcc713f8..201137a9a4 100644 --- a/phpBB/includes/mcp/mcp_post.php +++ b/phpBB/includes/mcp/mcp_post.php @@ -42,7 +42,7 @@ function mcp_post_details($id, $mode, $action) $whois = user_ipwhois($ip); $whois = preg_replace('#(\s)([\w\-\._\+]+@[\w\-\.]+)(\s)#', '\1<a href="mailto:\2">\2</a>\3', $whois); - $whois = preg_replace('#(\s)(http:/{2}[^\s]*)(\s)#', '\1<a href="\2" target="_blank">\2</a>\3', $whois); + $whois = preg_replace('#(\s)(http:/{2}[^\s]*)(\s)#', '\1<a href="\2">\2</a>\3', $whois); $template->assign_vars(array( 'RETURN_POST' => sprintf($user->lang['RETURN_POST'], '<a href="' . append_sid("{$phpbb_root_path}mcp.$phpEx", "i=$id&mode=$mode&p=$post_id") . '">', '</a>'), @@ -59,8 +59,8 @@ function mcp_post_details($id, $mode, $action) if ($action == 'chgposter') { - $username = request_var('username', ''); - $sql_where = "username = '" . $db->sql_escape($username) . "'"; + $username = request_var('username', '', true); + $sql_where = "username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; } else { @@ -89,12 +89,13 @@ function mcp_post_details($id, $mode, $action) } // Set some vars - $users_ary = array(); + $users_ary = $usernames_ary = array(); $post_id = $post_info['post_id']; $poster = ($post_info['user_colour']) ? '<span style="color:#' . $post_info['user_colour'] . '">' . $post_info['username'] . '</span>' : $post_info['username']; // Process message, leave it uncensored $message = $post_info['post_text']; + $message = str_replace("\n", '<br />', $message); if ($post_info['bbcode_bitfield']) { include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); @@ -102,7 +103,6 @@ function mcp_post_details($id, $mode, $action) $bbcode->bbcode_second_pass($message, $post_info['bbcode_uid'], $post_info['bbcode_bitfield']); } $message = smiley_text($message); - $message = str_replace("\n", '<br />', $message); $template->assign_vars(array( 'U_MCP_ACTION' => "$url&i=main&quickmod=1", // Use this for mode paramaters @@ -134,6 +134,7 @@ function mcp_post_details($id, $mode, $action) 'REPORTED_IMG' => $user->img('icon_topic_reported', $user->lang['POST_REPORTED']), 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', $user->lang['POST_UNAPPROVED']), 'EDIT_IMG' => $user->img('icon_post_edit', $user->lang['EDIT_POST']), + 'SEARCH_IMG' => $user->img('icon_user_search', $user->lang['SEARCH']), 'POSTER_NAME' => $poster, 'POST_PREVIEW' => $message, @@ -217,75 +218,62 @@ function mcp_post_details($id, $mode, $action) } // Get other users who've posted under this IP + $sql = 'SELECT poster_id, COUNT(poster_id) as postings + FROM ' . POSTS_TABLE . " + WHERE poster_ip = '" . $db->sql_escape($post_info['poster_ip']) . "' + GROUP BY poster_id + ORDER BY postings DESC"; + $result = $db->sql_query($sql); - // Firebird does not support ORDER BY on aliased columns - // MySQL does not support ORDER BY on functions - switch (SQL_LAYER) + while ($row = $db->sql_fetchrow($result)) { - case 'firebird': - $sql = 'SELECT u.user_id, u.username, COUNT(*) as postings - FROM ' . USERS_TABLE . ' u, ' . POSTS_TABLE . " p - WHERE p.poster_id = u.user_id - AND p.poster_ip = '" . $db->sql_escape($post_info['poster_ip']) . "' - AND p.poster_id <> {$post_info['user_id']} - GROUP BY u.user_id, u.username - ORDER BY COUNT(*) DESC"; - break; - - default: - $sql = 'SELECT u.user_id, u.username, COUNT(*) as postings - FROM ' . USERS_TABLE . ' u, ' . POSTS_TABLE . " p - WHERE p.poster_id = u.user_id - AND p.poster_ip = '" . $db->sql_escape($post_info['poster_ip']) . "' - AND p.poster_id <> {$post_info['user_id']} - GROUP BY u.user_id, u.username - ORDER BY postings DESC"; - break; + // Fill the user select list with users who have posted under this IP + if ($row['poster_id'] != $post_info['poster_id']) + { + $users_ary[$row['poster_id']] = $row; + } } - $result = $db->sql_query($sql); + $db->sql_freeresult($result); - while ($row = $db->sql_fetchrow($result)) + if (sizeof($users_ary)) { - // Fill the user select list with users who have posted - // under this IP - if ($row['user_id'] != $post_info['poster_id']) + // Get the usernames + $sql = 'SELECT user_id, username + FROM ' . USERS_TABLE . ' + WHERE ' . $db->sql_in_set('user_id', array_keys($users_ary)); + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) { - $users_ary[strtolower($row['username'])] = $row; + $users_ary[$row['user_id']]['username'] = $row['username']; + $usernames_ary[utf8_clean_string($row['username'])] = $users_ary[$row['user_id']]; } + $db->sql_freeresult($result); - $template->assign_block_vars('userrow', array( - 'USERNAME' => ($row['user_id'] == ANONYMOUS) ? $user->lang['GUEST'] : $row['username'], - 'NUM_POSTS' => $row['postings'], - 'L_POST_S' => ($row['postings'] == 1) ? $user->lang['POST'] : $user->lang['POSTS'], + foreach ($users_ary as $user_id => $user_row) + { + $template->assign_block_vars('userrow', array( + 'USERNAME' => ($user_id == ANONYMOUS) ? $user->lang['GUEST'] : $user_row['username'], + 'NUM_POSTS' => $user_row['postings'], + 'L_POST_S' => ($user_row['postings'] == 1) ? $user->lang['POST'] : $user->lang['POSTS'], - 'U_PROFILE' => ($row['user_id'] == ANONYMOUS) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['user_id']), - 'U_SEARCHPOSTS' => append_sid("{$phpbb_root_path}search.$phpEx", 'author=' . urlencode($row['username']) . '&sr=topics')) - ); + 'U_PROFILE' => ($user_id == ANONYMOUS) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $user_id), + 'U_SEARCHPOSTS' => append_sid("{$phpbb_root_path}search.$phpEx", 'author_id=' . $user_id . '&sr=topics')) + ); + } } - $db->sql_freeresult($result); // Get other IP's this user has posted under - // Firebird does not support ORDER BY on aliased columns - // MySQL does not support ORDER BY on functions - switch (SQL_LAYER) - { - case 'firebird': - $sql = 'SELECT poster_ip, COUNT(*) AS postings - FROM ' . POSTS_TABLE . ' - WHERE poster_id = ' . $post_info['poster_id'] . ' - GROUP BY poster_ip - ORDER BY COUNT(*) DESC'; - break; - - default: - $sql = 'SELECT poster_ip, COUNT(*) AS postings - FROM ' . POSTS_TABLE . ' - WHERE poster_id = ' . $post_info['poster_id'] . ' - GROUP BY poster_ip - ORDER BY postings DESC'; - break; - } + // A compound index on poster_id, poster_ip (posts table) would help speed up this query a lot, + // but the extra size is only valuable if there are persons having more than a thousands posts. + // This is better left to the really really big forums. + + $sql = 'SELECT poster_ip, COUNT(poster_ip) AS postings + FROM ' . POSTS_TABLE . ' + WHERE poster_id = ' . $post_info['poster_id'] . ' + GROUP BY poster_ip + ORDER BY postings DESC'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -305,12 +293,17 @@ function mcp_post_details($id, $mode, $action) $db->sql_freeresult($result); $user_select = ''; - ksort($users_ary); - foreach ($users_ary as $row) + if (sizeof($usernames_ary)) { - $user_select .= '<option value="' . $row['user_id'] . '">' . $row['username'] . "</option>\n"; + ksort($usernames_ary); + + foreach ($usernames_ary as $row) + { + $user_select .= '<option value="' . $row['poster_id'] . '">' . $row['username'] . "</option>\n"; + } } + $template->assign_var('S_USER_SELECT', $user_select); } @@ -379,7 +372,16 @@ function change_poster(&$post_info, $userdata) } } - // Do not change the poster_id within the attachments table, since they were still posted by the original user + // change the poster_id within the attachments table, else the data becomes out of sync and errors displayed because of wrong ownership + if ($post_info['post_attachment']) + { + $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' + SET poster_id = ' . $userdata['user_id'] . ' + WHERE poster_id = ' . $post_info['user_id'] . ' + AND post_msg_id = ' . $post_info['post_id'] . ' + AND topic_id = ' . $post_info['topic_id']; + $db->sql_query($sql); + } $from_username = $post_info['username']; $to_username = $userdata['username']; diff --git a/phpBB/includes/mcp/mcp_queue.php b/phpBB/includes/mcp/mcp_queue.php index 95e89fa9dc..0f6fae18ee 100644 --- a/phpBB/includes/mcp/mcp_queue.php +++ b/phpBB/includes/mcp/mcp_queue.php @@ -109,6 +109,7 @@ class mcp_queue // Process message, leave it uncensored $message = $post_info['post_text']; + $message = str_replace("\n", '<br />', $message); if ($post_info['bbcode_bitfield']) { include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); @@ -181,13 +182,15 @@ class mcp_queue $forum_list[] = $row['forum_id']; } - $global_id = $forum_list[0]; - - if (!($forum_list = implode(', ', $forum_list))) + if (!sizeof($forum_list)) { trigger_error('NOT_MODERATOR'); } + $global_id = $forum_list[0]; + + $forum_list = implode(', ', $forum_list); + $sql = 'SELECT SUM(forum_topics) as sum_forum_topics FROM ' . FORUMS_TABLE . " WHERE forum_id IN (0, $forum_list)"; @@ -228,10 +231,10 @@ class mcp_queue if ($mode == 'unapproved_posts') { $sql = 'SELECT p.post_id - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t' . (($sort_order_sql{0} == 'u') ? ', ' . USERS_TABLE . ' u' : '') . " + FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t' . (($sort_order_sql[0] == 'u') ? ', ' . USERS_TABLE . ' u' : '') . " WHERE p.forum_id IN (0, $forum_list) AND p.post_approved = 0 - " . (($sort_order_sql{0} == 'u') ? 'AND u.user_id = p.poster_id' : '') . ' + " . (($sort_order_sql[0] == 'u') ? 'AND u.user_id = p.poster_id' : '') . ' ' . (($topic_id) ? 'AND p.topic_id = ' . $topic_id : '') . " AND t.topic_id = p.topic_id AND t.topic_first_post_id <> p.post_id @@ -283,8 +286,8 @@ class mcp_queue { $sql = 'SELECT t.forum_id, t.topic_id, t.topic_title, t.topic_title AS post_subject, t.topic_time AS post_time, t.topic_poster AS poster_id, t.topic_first_post_id AS post_id, t.topic_first_poster_name AS username FROM ' . TOPICS_TABLE . " t - WHERE topic_approved = 0 - AND forum_id IN (0, $forum_list) + WHERE forum_id IN (0, $forum_list) + AND topic_approved = 0 $limit_time_sql ORDER BY $sort_order_sql"; $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); @@ -409,6 +412,8 @@ function approve_post($post_id_list, $mode) $total_topics = $total_posts = $forum_topics = $forum_posts = 0; $topic_approve_sql = $topic_replies_sql = $post_approve_sql = $topic_id_list = array(); + $update_forum_information = false; + foreach ($post_info as $post_id => $post_data) { $topic_id_list[$post_data['topic_id']] = 1; @@ -443,6 +448,12 @@ function approve_post($post_id_list, $mode) } $post_approve_sql[] = $post_id; + + // If the post is newer than the last post information stored we need to update the forum information + if ($post_data['post_time'] >= $post_data['forum_last_post_time']) + { + $update_forum_information = true; + } } if (sizeof($topic_approve_sql)) @@ -496,7 +507,11 @@ function approve_post($post_id_list, $mode) unset($topic_approve_sql, $topic_replies_sql, $post_approve_sql); update_post_information('topic', array_keys($topic_id_list)); - update_post_information('forum', $forum_id); + + if ($update_forum_information) + { + update_post_information('forum', $forum_id); + } unset($topic_id_list); $messenger = new messenger(); @@ -504,8 +519,6 @@ function approve_post($post_id_list, $mode) // Notify Poster? if ($notify_poster) { - $email_sig = str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']); - foreach ($post_info as $post_id => $post_data) { if ($post_data['poster_id'] == ANONYMOUS) @@ -522,11 +535,9 @@ function approve_post($post_id_list, $mode) $messenger->im($post_data['user_jabber'], $post_data['username']); $messenger->assign_vars(array( - 'EMAIL_SIG' => $email_sig, - 'SITENAME' => $config['sitename'], - 'USERNAME' => html_entity_decode($post_data['username']), - 'POST_SUBJECT' => html_entity_decode(censor_text($post_data['post_subject'])), - 'TOPIC_TITLE' => html_entity_decode(censor_text($post_data['topic_title'])), + 'USERNAME' => htmlspecialchars_decode($post_data['username']), + 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_data['post_subject'])), + 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_data['topic_title'])), 'U_VIEW_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&t={$post_data['topic_id']}&e=0", 'U_VIEW_POST' => generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&t={$post_data['topic_id']}&p=$post_id&e=$post_id") @@ -629,7 +640,7 @@ function disapprove_post($post_id_list, $mode) $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - if (!$row || (!$reason && $row['reason_title'] == 'other')) + if (!$row || (!$reason && strtolower($row['reason_title']) == 'other')) { $additional_msg = $user->lang['NO_REASON_DISAPPROVAL']; unset($_POST['confirm']); @@ -637,7 +648,7 @@ function disapprove_post($post_id_list, $mode) else { // If the reason is defined within the language file, we will use the localized version, else just use the database entry... - $disapprove_reason = ($row['reason_title'] != 'other') ? ((isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])])) ? $user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])] : $row['reason_description']) : ''; + $disapprove_reason = (strtolower($row['reason_title']) != 'other') ? ((isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])])) ? $user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])] : $row['reason_description']) : ''; $disapprove_reason .= ($reason) ? "\n\n" . $reason : ''; } } @@ -719,8 +730,6 @@ function disapprove_post($post_id_list, $mode) // Notify Poster? if ($notify_poster) { - $email_sig = str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']); - foreach ($post_info as $post_id => $post_data) { if ($post_data['poster_id'] == ANONYMOUS) @@ -737,12 +746,10 @@ function disapprove_post($post_id_list, $mode) $messenger->im($post_data['user_jabber'], $post_data['username']); $messenger->assign_vars(array( - 'EMAIL_SIG' => $email_sig, - 'SITENAME' => $config['sitename'], - 'USERNAME' => html_entity_decode($post_data['username']), - 'REASON' => html_entity_decode($disapprove_reason), - 'POST_SUBJECT' => html_entity_decode(censor_text($post_data['post_subject'])), - 'TOPIC_TITLE' => html_entity_decode(censor_text($post_data['topic_title']))) + 'USERNAME' => htmlspecialchars_decode($post_data['username']), + 'REASON' => htmlspecialchars_decode($disapprove_reason), + 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_data['post_subject'])), + 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_data['topic_title']))) ); $messenger->send($post_data['user_notify_type']); diff --git a/phpBB/includes/mcp/mcp_reports.php b/phpBB/includes/mcp/mcp_reports.php index a52bc02359..ebd1295090 100755 --- a/phpBB/includes/mcp/mcp_reports.php +++ b/phpBB/includes/mcp/mcp_reports.php @@ -117,6 +117,7 @@ class mcp_reports // Process message, leave it uncensored $message = $post_info['post_text']; + $message = str_replace("\n", '<br />', $message); if ($post_info['bbcode_bitfield']) { include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); @@ -200,13 +201,13 @@ class mcp_reports $forum_list[] = $row['forum_id']; } - $global_id = $forum_list[0]; - if (!sizeof($forum_list)) { trigger_error('NOT_MODERATOR'); } + $global_id = $forum_list[0]; + $sql = 'SELECT SUM(forum_topics) as sum_forum_topics FROM ' . FORUMS_TABLE . ' WHERE ' . $db->sql_in_set('forum_id', $forum_list); @@ -363,7 +364,7 @@ function close_report($post_id_list, $mode, $action) trigger_error('NOT_AUTHORIZED'); } - if (($action == 'delete') && (strpos($user->data['session_page'], 'mode=report_details') !== false)) + if ($action == 'delete' && strpos($user->data['session_page'], 'mode=report_details') !== false) { $redirect = request_var('redirect', build_url(array('mode')) . '&mode=reports'); } @@ -474,8 +475,6 @@ function close_report($post_id_list, $mode, $action) // Notify reporters if (sizeof($notify_reporters)) { - $email_sig = str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']); - foreach ($notify_reporters as $post_id => $reporter) { if ($reporter['user_id'] == ANONYMOUS) @@ -490,12 +489,10 @@ function close_report($post_id_list, $mode, $action) $messenger->im($reporter['user_jabber'], $reporter['username']); $messenger->assign_vars(array( - 'EMAIL_SIG' => $email_sig, - 'SITENAME' => $config['sitename'], - 'USERNAME' => html_entity_decode($reporter['username']), - 'CLOSER_NAME' => html_entity_decode($user->data['username']), - 'POST_SUBJECT' => html_entity_decode(censor_text($post_info[$post_id]['post_subject'])), - 'TOPIC_TITLE' => html_entity_decode(censor_text($post_info[$post_id]['topic_title']))) + 'USERNAME' => htmlspecialchars_decode($reporter['username']), + 'CLOSER_NAME' => htmlspecialchars_decode($user->data['username']), + 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_info[$post_id]['post_subject'])), + 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_info[$post_id]['topic_title']))) ); $messenger->send($reporter['user_notify_type']); diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 691b92bd36..3b674139e9 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -37,6 +37,8 @@ function mcp_topic_view($id, $mode, $action) $to_topic_id = request_var('to_topic_id', 0); $to_forum_id = request_var('to_forum_id', 0); $post_id_list = request_var('post_id_list', array(0)); + + utf8_normalize_nfc(&$subject); // Split Topic? if ($action == 'split_all' || $action == 'split_beyond') @@ -96,10 +98,10 @@ function mcp_topic_view($id, $mode, $action) } $db->sql_freeresult($result); - if ($bbcode_bitfield) + if ($bbcode_bitfield !== '') { include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); - $bbcode = new bbcode($bbcode_bitfield); + $bbcode = new bbcode(base64_encode($bbcode_bitfield)); } foreach ($rowset as $i => $row) @@ -110,6 +112,7 @@ function mcp_topic_view($id, $mode, $action) $message = $row['post_text']; $post_subject = ($row['post_subject'] != '') ? $row['post_subject'] : $topic_info['topic_title']; + $message = str_replace("\n", '<br />', $message); if ($row['bbcode_bitfield']) { @@ -117,7 +120,6 @@ function mcp_topic_view($id, $mode, $action) } $message = smiley_text($message); - $message = str_replace("\n", '<br />', $message); if (!$row['post_approved']) { @@ -180,7 +182,7 @@ function mcp_topic_view($id, $mode, $action) 'U_VIEWTOPIC' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $topic_info['forum_id'] . '&t=' . $topic_info['topic_id']), 'TO_TOPIC_ID' => $to_topic_id, - 'TO_TOPIC_INFO' => ($to_topic_id) ? sprintf($user->lang['YOU_SELECTED_TOPIC'], $to_topic_id, '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $to_topic_info['forum_id'] . '&t=' . $to_topic_id) . '" target="_new">' . $to_topic_info['topic_title'] . '</a>') : '', + 'TO_TOPIC_INFO' => ($to_topic_id) ? sprintf($user->lang['YOU_SELECTED_TOPIC'], $to_topic_id, '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $to_topic_info['forum_id'] . '&t=' . $to_topic_id) . '">' . $to_topic_info['topic_title'] . '</a>') : '', 'SPLIT_SUBJECT' => $subject, 'POSTS_PER_PAGE' => $posts_per_page, @@ -197,6 +199,7 @@ function mcp_topic_view($id, $mode, $action) 'S_CAN_APPROVE' => ($has_unapproved_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false, 'S_CAN_LOCK' => ($auth->acl_get('m_lock', $topic_info['forum_id'])) ? true : false, 'S_REPORT_VIEW' => ($action == 'reports') ? true : false, + 'S_MERGE_VIEW' => ($action == 'merge') ? true : false, 'S_SHOW_TOPIC_ICONS' => $s_topic_icons, 'S_TOPIC_ICON' => $icon_id, @@ -302,7 +305,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) $limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : ''; - if ($sort_order_sql{0} == 'u') + if ($sort_order_sql[0] == 'u') { $sql = 'SELECT p.post_id, p.forum_id, p.post_approved FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u diff --git a/phpBB/includes/mcp/mcp_warn.php b/phpBB/includes/mcp/mcp_warn.php index bc428570ab..da76dc8b58 100755 --- a/phpBB/includes/mcp/mcp_warn.php +++ b/phpBB/includes/mcp/mcp_warn.php @@ -247,6 +247,7 @@ function mcp_warn_post_view($id, $mode, $action) // We want to make the message available here as a reminder // Parse the message and subject $message = $userrow['post_text']; + $message = str_replace("\n", '<br />', censor_text($message)); // Second parse bbcode here if ($userrow['bbcode_bitfield']) @@ -260,9 +261,6 @@ function mcp_warn_post_view($id, $mode, $action) // Always process smilies after parsing bbcodes $message = smiley_text($message); - // Replace naughty words such as farty pants - $message = str_replace("\n", '<br />', censor_text($message)); - // Generate the appropriate user information for the user we are looking at $rank_title = $rank_img = ''; // get_user_rank($userrow['user_rank'], $userrow['user_posts'], $rank_title, $rank_img); @@ -312,11 +310,11 @@ function mcp_warn_user_view($id, $mode, $action) global $template, $db, $user, $auth; $user_id = request_var('u', 0); - $username = request_var('username', ''); + $username = request_var('username', '', true); $notify = (isset($_REQUEST['notify_user'])) ? true : false; $warning = request_var('warning', '', true); - $sql_where = ($user_id) ? "user_id = $user_id" : "username = '" . $db->sql_escape($username) . "'"; + $sql_where = ($user_id) ? "user_id = $user_id" : "username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $sql = 'SELECT * FROM ' . USERS_TABLE . ' @@ -405,7 +403,7 @@ function add_warning($userrow, $warning, $send_pm = true, $post_id = 0) $message_parser = new parse_message(); $message_parser->message = sprintf($lang['WARNING_PM_BODY'], $warning); - $message_parser->parse(true, true, true, false, false, true); + $message_parser->parse(true, true, true, false, false, true, true); $pm_data = array( 'from_user_id' => $user->data['user_id'], diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index 6aa78d091f..6538bd7721 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -47,7 +47,6 @@ class bbcode_firstpass extends bbcode $this->bbcode_bitfield = ''; $bitfield = new bitfield(); - $size = strlen($this->message); foreach ($this->bbcodes as $bbcode_name => $bbcode_data) { if (isset($bbcode_data['disabled']) && $bbcode_data['disabled']) @@ -65,18 +64,15 @@ class bbcode_firstpass extends bbcode { foreach ($bbcode_data['regexp'] as $regexp => $replacement) { - $this->message = preg_replace($regexp, $replacement, $this->message); + // The pattern gets compiled and cached by the PCRE extension, + // it should not demand recompilation + if (preg_match($regexp, $this->message)) + { + $this->message = preg_replace($regexp, $replacement, $this->message); + $bitfield->set($bbcode_data['bbcode_id']); + } } } - - // Because we add bbcode_uid to all tags, the message length - // will increase whenever a tag is found - $new_size = strlen($this->message); - if ($size != $new_size) - { - $bitfield->set($bbcode_data['bbcode_id']); - $size = $new_size; - } } $this->bbcode_bitfield = $bitfield->get_base64(); @@ -368,15 +364,11 @@ class bbcode_firstpass extends bbcode // We remove the hardcoded elements from the code block here because it is not used in code blocks // Having it here saves us one preg_replace per message containing [code] blocks // Additionally, magic url parsing should go after parsing bbcodes, but for safety those are stripped out too... - $htm_match = array( - '#<!\-\- e \-\-><a href="mailto:(.*?)">.*?</a><!\-\- e \-\->#', - '#<!\-\- m \-\-><a href="(.*?)" target="_blank">.*?</a><!\-\- m \-\->#', - '#<!\-\- w \-\-><a href="http:\/\/(.*?)" target="_blank">.*?</a><!\-\- w \-\->#', - '#<!\-\- l \-\-><a href="(.*?)">.*?</a><!\-\- l \-\->#', - '#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#', - '#&\#([0-9]+);#', - ); - $htm_replace = array('\1', '\1', '\1', '\1', '\1', '&#\1;'); + $htm_match = get_preg_expression('bbcode_htm'); +// $htm_match[3] = '/&#([0-9]+);/'; + unset($htm_match[3], $htm_match[4]); + + $htm_replace = array('\1', '\2', '\1'); //, '&#\1;'); $out = ''; @@ -427,7 +419,7 @@ class bbcode_firstpass extends bbcode } // Because highlight_string is specialcharing the text (but we already did this before), we have to reverse this in order to get correct results - $code = html_entity_decode($code); + $code = htmlspecialchars_decode($code); $code = highlight_string($code, true); $str_from = array('<span style="color: ', '<font color="syntax', '</font>', '<code>', '</code>','[', ']', '.', ':'); @@ -507,13 +499,15 @@ class bbcode_firstpass extends bbcode $tok = ']'; $out = '['; + // First character is [ $in = substr($in, 1); $list_end_tags = array(); do { $pos = strlen($in); - for ($i = 0; $i < strlen($tok); ++$i) + + for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i) { $tmp_pos = strpos($in, $tok{$i}); @@ -531,7 +525,7 @@ class bbcode_firstpass extends bbcode if ($tok == ']') { // if $tok is ']' the buffer holds a tag - if ($buffer == '/list' && sizeof($list_end_tags)) + if (strtolower($buffer) == '/list' && sizeof($list_end_tags)) { $out .= array_pop($list_end_tags) . ']'; $tok = '['; @@ -547,6 +541,12 @@ class bbcode_firstpass extends bbcode { array_push($list_end_tags, '/list:o:' . $this->bbcode_uid); } + + if (strtolower(substr($buffer, 0, 4)) == 'list') + { + $buffer = 'list' . substr($buffer, 4, $pos); + } + $out .= $buffer . ':' . $this->bbcode_uid . ']'; $tok = '['; } @@ -598,7 +598,7 @@ class bbcode_firstpass extends bbcode do { $pos = strlen($in); - for ($i = 0; $i < strlen($tok); ++$i) + for ($i = 0, $tok_len = strlen($tok); $i < $tok_len; ++$i) { $tmp_pos = strpos($in, $tok{$i}); if ($tmp_pos !== false && $tmp_pos < $pos) @@ -649,7 +649,7 @@ class bbcode_firstpass extends bbcode preg_match_all('#\[((?:/)?(?:[a-z]+))#i', $username, $tags); foreach ($tags[1] as $tag) { - if ($tag{0} != '/') + if ($tag[0] != '/') { $end_tags[] = '/' . $tag; } @@ -807,7 +807,7 @@ class bbcode_firstpass extends bbcode * @param string $url the url to check * @return true if the url is pointing to this domain/script_path/php-file, false if not * - * @access: private + * @access private */ function path_in_domain($url) { @@ -857,6 +857,7 @@ class parse_message extends bbcode_firstpass var $allow_img_bbcode = true; var $allow_flash_bbcode = true; var $allow_quote_bbcode = true; + var $allow_url_bbcode = true; var $mode; @@ -877,7 +878,7 @@ class parse_message extends bbcode_firstpass /** * Parse Message */ - function parse($allow_bbcode, $allow_magic_url, $allow_smilies, $allow_img_bbcode = true, $allow_flash_bbcode = true, $allow_quote_bbcode = true, $update_this_message = true, $mode = 'post') + function parse($allow_bbcode, $allow_magic_url, $allow_smilies, $allow_img_bbcode = true, $allow_flash_bbcode = true, $allow_quote_bbcode = true, $allow_url_bbcode = true, $update_this_message = true, $mode = 'post') { global $config, $db, $user; @@ -888,6 +889,7 @@ class parse_message extends bbcode_firstpass $this->allow_img_bbcode = $allow_img_bbcode; $this->allow_flash_bbcode = $allow_flash_bbcode; $this->allow_quote_bbcode = $allow_quote_bbcode; + $this->allow_url_bbcode = $allow_url_bbcode; // If false, then $this->message won't be altered, the text will be returned instead. if (!$update_this_message) @@ -911,7 +913,7 @@ class parse_message extends bbcode_firstpass // Message length check. -1 disables this check completely. if ($config['max_' . $mode . '_chars'] != -1) { - $msg_len = ($mode == 'post') ? strlen($this->message) : strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#is', ' ', $this->message)); + $msg_len = ($mode == 'post') ? utf8_strlen($this->message) : utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#is', ' ', $this->message)); if ((!$msg_len && $mode !== 'sig') || $config['max_' . $mode . '_chars'] && $msg_len > $config['max_' . $mode . '_chars']) { @@ -924,7 +926,7 @@ class parse_message extends bbcode_firstpass if ($allow_bbcode && strpos($this->message, '[') !== false) { $this->bbcode_init(); - $disallow = array('img', 'flash', 'quote'); + $disallow = array('img', 'flash', 'quote', 'url'); foreach ($disallow as $bool) { if (!${'allow_' . $bool . '_bbcode'}) @@ -995,7 +997,7 @@ class parse_message extends bbcode_firstpass if ($this->message_status == 'plain') { // Force updating message - of course. - $this->parse($allow_bbcode, $allow_magic_url, $allow_smilies, $this->allow_img_bbcode, $this->allow_flash_bbcode, $this->allow_quote_bbcode, true); + $this->parse($allow_bbcode, $allow_magic_url, $allow_smilies, $this->allow_img_bbcode, $this->allow_flash_bbcode, $this->allow_quote_bbcode, $this->allow_url_bbcode, true); } // Parse BBcode @@ -1076,7 +1078,7 @@ class parse_message extends bbcode_firstpass // NOTE: obtain_* function? chaching the table contents? // For now setting the ttl to 10 minutes - switch (SQL_LAYER) + switch ($db->sql_layer) { case 'mssql': case 'mssql_odbc': @@ -1088,7 +1090,7 @@ class parse_message extends bbcode_firstpass case 'firebird': $sql = 'SELECT * FROM ' . SMILIES_TABLE . ' - ORDER BY STRLEN(code) DESC'; + ORDER BY CHAR_LENGTH(code) DESC'; break; // LENGTH supported by MySQL, IBM DB2, Oracle and Access for sure... @@ -1104,7 +1106,7 @@ class parse_message extends bbcode_firstpass { // (assertion) $match[] = '#(?<=^|[\n ]|\.)' . preg_quote($row['code'], '#') . '#'; - $replace[] = '<!-- s' . $row['code'] . ' --><img src="{SMILIES_PATH}/' . $row['smiley_url'] . '" border="0" alt="' . $row['emotion'] . '" title="' . $row['emotion'] . '" /><!-- s' . $row['code'] . ' -->'; + $replace[] = '<!-- s' . $row['code'] . ' --><img src="{SMILIES_PATH}/' . $row['smiley_url'] . '" alt="' . $row['emotion'] . '" title="' . $row['emotion'] . '" /><!-- s' . $row['code'] . ' -->'; } $db->sql_freeresult($result); } @@ -1131,12 +1133,13 @@ class parse_message extends bbcode_firstpass */ function parse_attachments($form_name, $mode, $forum_id, $submit, $preview, $refresh, $is_message = false) { - global $config, $auth, $user, $phpbb_root_path, $phpEx; + global $config, $auth, $user, $phpbb_root_path, $phpEx, $db; $error = array(); $num_attachments = sizeof($this->attachment_data); $this->filename_data['filecomment'] = request_var('filecomment', '', true); + utf8_normalize_nfc(&$this->filename_data['filecomment']); $upload_file = (isset($_FILES[$form_name]) && $_FILES[$form_name]['name'] != 'none' && trim($_FILES[$form_name]['name'])) ? true : false; $add_file = (isset($_POST['add_file'])) ? true : false; @@ -1156,7 +1159,7 @@ class parse_message extends bbcode_firstpass if ($filedata['post_attach'] && !sizeof($error)) { - $new_entry = array( + $sql_ary = array( 'physical_filename' => $filedata['physical_filename'], 'attach_comment' => $this->filename_data['filecomment'], 'real_filename' => $filedata['real_filename'], @@ -1164,8 +1167,19 @@ class parse_message extends bbcode_firstpass 'mimetype' => $filedata['mimetype'], 'filesize' => $filedata['filesize'], 'filetime' => $filedata['filetime'], - 'attach_id' => 0, - 'thumbnail' => $filedata['thumbnail'] + 'thumbnail' => $filedata['thumbnail'], + 'is_orphan' => 1, + 'in_message' => ($is_message) ? 1 : 0, + 'poster_id' => $user->data['user_id'], + ); + + $db->sql_query('INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); + + $new_entry = array( + 'attach_id' => $db->sql_nextid(), + 'is_orphan' => 1, + 'real_filename' => $filedata['real_filename'], + 'attach_comment'=> $this->filename_data['filecomment'], ); $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data); @@ -1199,32 +1213,51 @@ class parse_message extends bbcode_firstpass $index = (int) key($_POST['delete_file']); - // delete selected attachment - if (!$this->attachment_data[$index]['attach_id']) + if (!empty($this->attachment_data[$index])) { - phpbb_unlink($this->attachment_data[$index]['physical_filename'], 'file'); - if ($this->attachment_data[$index]['thumbnail']) + // delete selected attachment + if ($this->attachment_data[$index]['is_orphan']) { - phpbb_unlink($this->attachment_data[$index]['physical_filename'], 'thumbnail'); + $sql = 'SELECT attach_id, physical_filename, thumbnail + FROM ' . ATTACHMENTS_TABLE . ' + WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id'] . ' + AND is_orphan = 1 + AND poster_id = ' . $user->data['user_id']; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if ($row) + { + phpbb_unlink($row['physical_filename'], 'file'); + + if ($row['thumbnail']) + { + phpbb_unlink($row['physical_filename'], 'thumbnail'); + } + + $db->sql_query('DELETE FROM ' . ATTACHMENTS_TABLE . ' WHERE attach_id = ' . (int) $this->attachment_data[$index]['attach_id']); + } + } + else + { + delete_attachments('attach', array(intval($this->attachment_data[$index]['attach_id']))); } - } - else - { - delete_attachments('attach', array(intval($this->attachment_data[$index]['attach_id']))); - } - unset($this->attachment_data[$index]); - $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "(\\1 == \$index) ? '' : ((\\1 > \$index) ? '[attachment=' . (\\1 - 1) . ']\\2[/attachment]' : '\\0')", $this->message); + unset($this->attachment_data[$index]); + $this->message = preg_replace('#\[attachment=([0-9]+)\](.*?)\[\/attachment\]#e', "(\\1 == \$index) ? '' : ((\\1 > \$index) ? '[attachment=' . (\\1 - 1) . ']\\2[/attachment]' : '\\0')", $this->message); - // Reindex Array - $this->attachment_data = array_values($this->attachment_data); + // Reindex Array + $this->attachment_data = array_values($this->attachment_data); + } } else if ($edit_comment || $add_file || $preview) { if ($edit_comment) { $actual_comment_list = request_var('comment_list', array(''), true); + utf8_normalize_nfc(&$actual_comment_list); $edit_comment = request_var('edit_comment', array(0 => '')); $edit_comment = key($edit_comment); @@ -1233,14 +1266,14 @@ class parse_message extends bbcode_firstpass if (($add_file || $preview) && $upload_file) { - if ($num_attachments < $cfg['max_attachments'] || $auth->acl_gets('m_', 'a_')) + if ($num_attachments < $cfg['max_attachments'] || $auth->acl_gets('m_', 'a_', $forum_id)) { $filedata = upload_attachment($form_name, $forum_id, false, '', $is_message); $error = array_merge($error, $filedata['error']); if (!sizeof($error)) { - $new_entry = array( + $sql_ary = array( 'physical_filename' => $filedata['physical_filename'], 'attach_comment' => $this->filename_data['filecomment'], 'real_filename' => $filedata['real_filename'], @@ -1248,8 +1281,19 @@ class parse_message extends bbcode_firstpass 'mimetype' => $filedata['mimetype'], 'filesize' => $filedata['filesize'], 'filetime' => $filedata['filetime'], - 'attach_id' => 0, - 'thumbnail' => $filedata['thumbnail'] + 'thumbnail' => $filedata['thumbnail'], + 'is_orphan' => 1, + 'in_message' => ($is_message) ? 1 : 0, + 'poster_id' => $user->data['user_id'], + ); + + $db->sql_query('INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); + + $new_entry = array( + 'attach_id' => $db->sql_nextid(), + 'is_orphan' => 1, + 'real_filename' => $filedata['real_filename'], + 'attach_comment'=> $this->filename_data['filecomment'], ); $this->attachment_data = array_merge(array(0 => $new_entry), $this->attachment_data); @@ -1279,99 +1323,84 @@ class parse_message extends bbcode_firstpass global $user, $db, $phpbb_root_path, $phpEx, $config; $this->filename_data['filecomment'] = request_var('filecomment', '', true); - $this->attachment_data = (isset($_POST['attachment_data'])) ? $_POST['attachment_data'] : array(); + utf8_normalize_nfc(&$this->filename_data['filecomment']); + $attachment_data = (isset($_POST['attachment_data'])) ? $_POST['attachment_data'] : array(); + $this->attachment_data = array(); $check_user_id = ($check_user_id === false) ? $user->data['user_id'] : $check_user_id; - // Regenerate data array... - $attach_ids = $filenames = array(); + if (!sizeof($attachment_data)) + { + return; + } - foreach ($this->attachment_data as $pos => $var_ary) + $not_orphan = $orphan = array(); + + foreach ($attachment_data as $pos => $var_ary) { - if ($var_ary['attach_id']) + if ($var_ary['is_orphan']) { - $attach_ids[(int) $this->attachment_data[$pos]['attach_id']] = $pos; + $orphan[(int) $var_ary['attach_id']] = $pos; } else { - $filenames[$pos] = ''; - set_var($filenames[$pos], $this->attachment_data[$pos]['physical_filename'], 'string'); - $filenames[$pos] = basename($filenames[$pos]); + $not_orphan[(int) $var_ary['attach_id']] = $pos; } } - $this->attachment_data = array(); - - // Regenerate already posted attachments... - if (sizeof($attach_ids)) + // Regenerate already posted attachments + if (sizeof($not_orphan)) { - // Get the data from the attachments - $sql = 'SELECT attach_id, physical_filename, real_filename, extension, mimetype, filesize, filetime, thumbnail + // Get the attachment data, based on the poster id... + $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('attach_id', array_keys($attach_ids)) . ' + WHERE ' . $db->sql_in_set('attach_id', array_keys($not_orphan)) . ' AND poster_id = ' . $check_user_id; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { - if (isset($attach_ids[$row['attach_id']])) - { - $pos = $attach_ids[$row['attach_id']]; - $this->attachment_data[$pos] = $row; - set_var($this->attachment_data[$pos]['attach_comment'], $_POST['attachment_data'][$pos]['attach_comment'], 'string', true); + $pos = $not_orphan[$row['attach_id']]; + $this->attachment_data[$pos] = $row; + set_var($this->attachment_data[$pos]['attach_comment'], $_POST['attachment_data'][$pos]['attach_comment'], 'string', true); - unset($attach_ids[$row['attach_id']]); - } + unset($not_orphan[$row['attach_id']]); } $db->sql_freeresult($result); + } - if (sizeof($attach_ids)) - { - trigger_error($user->lang['NO_ACCESS_ATTACHMENT'], E_USER_ERROR); - } + if (sizeof($not_orphan)) + { + trigger_error($user->lang['NO_ACCESS_ATTACHMENT'], E_USER_ERROR); } // Regenerate newly uploaded attachments - if (sizeof($filenames)) + if (sizeof($orphan)) { - include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx); - - $sql = 'SELECT attach_id + $sql = 'SELECT attach_id, is_orphan, real_filename, attach_comment FROM ' . ATTACHMENTS_TABLE . ' - WHERE ' . $db->sql_in_set('LOWER(physical_filename)', array_map('strtolower', $filenames)); - $result = $db->sql_query_limit($sql, 1); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - trigger_error($user->lang['NO_ACCESS_ATTACHMENT'], E_USER_ERROR); - } + WHERE ' . $db->sql_in_set('attach_id', array_keys($orphan)) . ' + AND poster_id = ' . $user->data['user_id'] . ' + AND is_orphan = 1'; + $result = $db->sql_query($sql); - foreach ($filenames as $pos => $physical_filename) + while ($row = $db->sql_fetchrow($result)) { - $this->attachment_data[$pos] = array( - 'physical_filename' => $physical_filename, - 'extension' => strtolower(filespec::get_extension($phpbb_root_path . $config['upload_path'] . '/' . $physical_filename)), - 'filesize' => filespec::get_filesize($phpbb_root_path . $config['upload_path'] . '/' . $physical_filename), - 'attach_id' => 0, - 'thumbnail' => (file_exists($phpbb_root_path . $config['upload_path'] . '/thumb_' . $physical_filename)) ? 1 : 0, - ); - + $pos = $orphan[$row['attach_id']]; + $this->attachment_data[$pos] = $row; set_var($this->attachment_data[$pos]['attach_comment'], $_POST['attachment_data'][$pos]['attach_comment'], 'string', true); - set_var($this->attachment_data[$pos]['real_filename'], $_POST['attachment_data'][$pos]['real_filename'], 'string', true); - set_var($this->attachment_data[$pos]['filetime'], $_POST['attachment_data'][$pos]['filetime'], 'int'); - if (strpos($_POST['attachment_data'][$pos]['mimetype'], 'image/') !== false) - { - set_var($this->attachment_data[$pos]['mimetype'], $_POST['attachment_data'][$pos]['mimetype'], 'string'); - } - else - { - $this->attachment_data[$pos]['mimetype'] = filespec::get_mimetype($phpbb_root_path . $config['upload_path'] . '/' . $physical_filename); - } + unset($orphan[$row['attach_id']]); } + $db->sql_freeresult($result); + } + + if (sizeof($orphan)) + { + trigger_error($user->lang['NO_ACCESS_ATTACHMENT'], E_USER_ERROR); } + + ksort($this->attachment_data); } /** @@ -1388,8 +1417,7 @@ class parse_message extends bbcode_firstpass $this->message = $poll['poll_option_text']; - $poll['poll_option_text'] = $this->parse($poll['enable_bbcode'], $poll['enable_urls'], $poll['enable_smilies'], $poll['img_status'], false, false, false); - + $poll['poll_option_text'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false); $this->message = $tmp_message; @@ -1398,8 +1426,7 @@ class parse_message extends bbcode_firstpass $this->message = $poll['poll_title']; - $poll['poll_title'] = $this->parse($poll['enable_bbcode'], $poll['enable_urls'], $poll['enable_smilies'], $poll['img_status'], false, false, false); - + $poll['poll_title'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false); $this->message = $tmp_message; diff --git a/phpBB/includes/search/fulltext_mysql.php b/phpBB/includes/search/fulltext_mysql.php index 4a9a57df34..755bd5b814 100644 --- a/phpBB/includes/search/fulltext_mysql.php +++ b/phpBB/includes/search/fulltext_mysql.php @@ -49,7 +49,7 @@ class fulltext_mysql extends search_backend { global $db, $user; - if (strpos(SQL_LAYER, 'mysql') === false) + if (strpos($db->sql_layer, 'mysql') === false) { return $user->lang['FULLTEXT_MYSQL_INCOMPATIBLE_VERSION']; } @@ -153,7 +153,7 @@ class fulltext_mysql extends search_backend $clean_word = preg_replace('#^[+\-|]#', '', $word); // check word length - $clean_len = strlen(str_replace('*', '', $clean_word)); + $clean_len = utf8_strlen(str_replace('*', '', $clean_word)); if (($clean_len < $config['fulltext_mysql_min_word_len']) || ($clean_len > $config['fulltext_mysql_max_word_len'])) { $this->common_words[] = $word; @@ -203,7 +203,7 @@ class fulltext_mysql extends search_backend for ($i = 0, $n = sizeof($text); $i < $n; $i++) { $text[$i] = trim($text[$i]); - if (strlen($text[$i]) < $config['fulltext_mysql_min_word_len'] || strlen($text[$i]) > $config['fulltext_mysql_max_word_len']) + if (utf8_strlen($text[$i]) < $config['fulltext_mysql_min_word_len'] || utf8_strlen($text[$i]) > $config['fulltext_mysql_max_word_len']) { unset($text[$i]); } @@ -561,7 +561,7 @@ class fulltext_mysql extends search_backend * * @param string $mode contains the post mode: edit, post, reply, quote ... */ - function index($mode, $post_id, &$message, &$subject, $encoding, $poster_id, $forum_id) + function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) { global $db; @@ -732,7 +732,7 @@ class fulltext_mysql extends search_backend { global $db; - if (strpos(SQL_LAYER, 'mysql') === false) + if (strpos($db->sql_layer, 'mysql') === false) { $this->stats = array(); return; diff --git a/phpBB/includes/search/fulltext_native.php b/phpBB/includes/search/fulltext_native.php index bc11d2ed20..b47076228a 100755 --- a/phpBB/includes/search/fulltext_native.php +++ b/phpBB/includes/search/fulltext_native.php @@ -56,10 +56,6 @@ class fulltext_native extends search_backend { include($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx); } - if (!function_exists('utf8_strlen')) - { - include($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); - } $error = false; @@ -86,38 +82,89 @@ class fulltext_native extends search_backend { global $db, $config, $user; - // Clean up the query search - $match = array( - // Replace multiple spaces with a single space - '# +#', + $keywords = trim($this->cleanup($keywords, '+-|()*')); - // Strip spaces after: +-|( - '#([+\\-|(]) #', + // allow word|word|word without brackets + if ((strpos($keywords, ' ') === false) && (strpos($keywords, '|') !== false) && (strpos($keywords, '(') === false)) + { + $keywords = '(' . $keywords . ')'; + } - // Strip spaces before: |*) - '# ([|*)])#', + $open_bracket = $space = false; + for ($i = 0, $n = strlen($keywords); $i < $n; $i++) + { + if ($open_bracket !== false) + { + switch ($keywords[$i]) + { + case ')': + if ($open_bracket + 1 == $i) + { + $keywords[$i - 1] = '|'; + $keywords[$i] = '|'; + } + $open_bracket = false; + break; + case '(': + $keywords[$i] = '|'; + break; + case '+': + case '-': + case ' ': + $keywords[$i] = '|'; + break; + } + } + else + { + switch ($keywords[$i]) + { + case ')': + $keywords[$i] = ' '; + break; + case '(': + $open_bracket = $i; + break; + case '|': + $keywords[$i] = ' '; + break; + case '-': + case '+': + $space = $keywords[$i]; + break; + case ' ': + if ($space !== false) + { + $keywords[$i] = $space; + } + break; + default: + $space = false; + } + } + } - // Make word|word|word work without brackets - '#^[^()]*\\|[^()]*$#', + if ($open_bracket) + { + $keywords .= ')'; + } - // Remove nested brackets - '#(\\([^()]*)(?=\\()#', - '#\\)([^()]*)(?=\\))#', + $match = array( + '# +#', + '#\|\|+#', + '#(\+|\-)(?:\+|\-)+#', + '#\(\|#', + '#\|\)#', ); - $replace = array( ' ', + '|', '$1', - '$1', - '($0)', - '$1)', - '$1', + '(', + ')', ); - $keywords = trim(preg_replace($match, $replace, $this->cleanup($keywords, '+-|()*', $user->lang['ENCODING']))); - - // remove some useless bracket combinations which might be created by the previous regexps - $keywords = str_replace(array('()', ')|('), array('', '|'), $keywords); + $keywords = preg_replace($match, $replace, $keywords); // $keywords input format: each word seperated by a space, words in a bracket are not seperated @@ -134,7 +181,7 @@ class fulltext_native extends search_backend } // set the search_query which is shown to the user - $this->search_query = utf8_encode_ncr($keywords, ENT_QUOTES); + $this->search_query = $keywords; $exact_words = array(); preg_match_all('#([^\\s+\\-|*()]+)(?:$|[\\s+\\-|()])#', $keywords, $exact_words); @@ -152,7 +199,7 @@ class fulltext_native extends search_backend { if ($row['word_common']) { - $this->common_words[] = $row['wort_text']; + $this->common_words[] = $row['word_text']; continue; } @@ -187,7 +234,7 @@ class fulltext_native extends search_backend // a group of which at least one may not be in the resulting posts if ($word[0] == '(') { - $word = explode('|', substr($word, 1, -1)); + $word = array_unique(explode('|', substr($word, 1, -1))); $mode = 'must_exclude_one'; } // one word which should not be in the resulting posts @@ -209,12 +256,17 @@ class fulltext_native extends search_backend // a group of words of which at least one word should be in every resulting post if ($word[0] == '(') { - $word = explode('|', substr($word, 1, -1)); + $word = array_unique(explode('|', substr($word, 1, -1))); } $ignore_no_id = false; $mode = 'must_contain'; } + if (empty($word)) + { + continue; + } + // if this is an array of words then retrieve an id for each if (is_array($word)) { @@ -246,7 +298,7 @@ class fulltext_native extends search_backend // throw an error if we shall not ignore unexistant words else if (!$ignore_no_id) { - trigger_error(sprintf($user->lang['WORDS_IN_NO_POST'], utf8_encode_ncr(implode(', ', $word)))); + trigger_error(sprintf($user->lang['WORDS_IN_NO_POST'], implode(', ', $word))); } } // else we only need one id @@ -264,7 +316,7 @@ class fulltext_native extends search_backend // throw an error if we shall not ignore unexistant words else if (!$ignore_no_id) { - trigger_error(sprintf($user->lang['WORD_IN_NO_POST'], utf8_encode_ncr($word))); + trigger_error(sprintf($user->lang['WORD_IN_NO_POST'], $word)); } } @@ -357,12 +409,6 @@ class fulltext_native extends search_backend ); $sql_where[] = 'm0.post_id = p.post_id'; - if ($type == 'topics') - { - $sql_array['FROM'][TOPICS_TABLE] = 't'; - $group_by = true; - } - $title_match = ''; $group_by = true; // Build some display specific sql strings @@ -383,6 +429,16 @@ class fulltext_native extends search_backend break; } + if ($type == 'topics') + { + if (!isset($sql_array['FROM'][TOPICS_TABLE])) + { + $sql_array['FROM'][TOPICS_TABLE] = 't'; + $sql_where[] = 'p.topic_id = t.topic_id'; + } + $group_by = true; + } + /** * @todo Add a query optimizer (handle stuff like "+(4|3) +4") */ @@ -540,20 +596,24 @@ class fulltext_native extends search_backend $sql = ''; $sql_array_count = $sql_array; - switch (SQL_LAYER) + switch ($db->sql_layer) { - case 'mysql': case 'mysql4': case 'mysqli': + + // 3.x does not support SQL_CALC_FOUND_ROWS $sql_array['SELECT'] = 'SQL_CALC_FOUND_ROWS ' . $sql_array['SELECT']; $is_mysql = true; + break; case 'sqlite': $sql_array_count['SELECT'] = ($type == 'posts') ? 'DISTINCT p.post_id' : 'DISTINCT p.topic_id'; $sql = 'SELECT COUNT(' . (($type == 'posts') ? 'post_id' : 'topic_id') . ') as total_results FROM (' . $db->sql_build_query('SELECT', $sql_array_count) . ')'; + // no break + default: $sql_array_count['SELECT'] = ($type == 'posts') ? 'COUNT(DISTINCT p.post_id) AS total_results' : 'COUNT(DISTINCT p.topic_id) AS total_results'; $sql = (!$sql) ? $db->sql_build_query('SELECT', $sql_array_count) : $sql; @@ -735,9 +795,8 @@ class fulltext_native extends search_backend // If the cache was completely empty count the results if (!$total_results) { - switch (SQL_LAYER) + switch ($db->sql_layer) { - case 'mysql': case 'mysql4': case 'mysqli': $select = 'SQL_CALC_FOUND_ROWS ' . $select; @@ -757,7 +816,7 @@ class fulltext_native extends search_backend } else { - if (SQL_LAYER == 'sqlite') + if ($db->sql_layer == 'sqlite') { $sql = 'SELECT COUNT(topic_id) as total_results FROM (SELECT DISTINCT t.topic_id'; @@ -773,7 +832,7 @@ class fulltext_native extends search_backend $m_approve_fid_sql $sql_fora AND t.topic_id = p.topic_id - $sql_time" . ((SQL_LAYER == 'sqlite') ? ')' : ''); + $sql_time" . (($db->sql_layer == 'sqlite') ? ')' : ''); } $result = $db->sql_query($sql); @@ -858,7 +917,7 @@ class fulltext_native extends search_backend * * NOTE: duplicates are NOT removed from the return array * - * @param string $text Text to split, encoded in user's encoding + * @param string $text Text to split, encoded in UTF-8 * @return array Array of UTF-8 words * * @access private @@ -876,7 +935,7 @@ class fulltext_native extends search_backend // Do not index code $match[] = '#\[code(?:=.*?)?(\:?[0-9a-z]{5,})\].*?\[\/code(\:?[0-9a-z]{5,})\]#is'; // BBcode - $match[] = '#\[\/?[a-z\*\+\-]+(?:=.*?)?(\:?[0-9a-z]{5,})\]#'; + $match[] = '#\[\/?[a-z0-9\*\+\-]+(?:=.*?)?(?::[a-z])?(\:?[0-9a-z]{5,})\]#'; $min = $config['fulltext_native_min_chars']; $max = $config['fulltext_native_max_chars']; @@ -886,15 +945,15 @@ class fulltext_native extends search_backend /** * Clean up the string, remove HTML tags, remove BBCodes */ - $word = strtok($this->cleanup(preg_replace($match, ' ', strip_tags($text)), '', $user->lang['ENCODING']), ' '); + $word = strtok($this->cleanup(preg_replace($match, ' ', strip_tags($text)), -1), ' '); while (isset($word[0])) { - if (isset($word[252]) + if (isset($word[255]) || !isset($word[$isset_min])) { /** - * Words longer than 252 bytes are ignored. This will have to be + * Words longer than 255 bytes are ignored. This will have to be * changed whenever we change the length of search_wordlist.word_text * * Words shorter than $isset_min bytes are ignored, too @@ -939,13 +998,12 @@ class fulltext_native extends search_backend * @param int $post_id The id of the post which is modified/created * @param string $message New or updated post content * @param string $subject New or updated post subject - * @param string $encoding The post content's encoding * @param int $poster_id Post author's user id * @param int $forum_id The id of the forum in which the post is located * * @access public */ - function index($mode, $post_id, &$message, &$subject, $encoding, $poster_id, $forum_id) + function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id) { global $config, $db, $user; @@ -1024,26 +1082,16 @@ class fulltext_native extends search_backend if (sizeof($new_words)) { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $sql = 'INSERT INTO ' . SEARCH_WORDLIST_TABLE . " (word_text) - VALUES ('" . implode("'),('", array_map(array(&$db, 'sql_escape'), $new_words)) . "')"; - $db->sql_query($sql); - break; + $sql_ary = array(); - default: - foreach ($new_words as $word) - { - $sql = 'INSERT INTO ' . SEARCH_WORDLIST_TABLE . " (word_text) - VALUES ('" . $db->sql_escape($word) . "')"; - $db->sql_query($sql); - } + foreach ($new_words as $word) + { + $sql_ary[] = array('word_text' => $word); } + + $db->sql_multi_insert(SEARCH_WORDLIST_TABLE, $sql_ary); } - unset($new_words); + unset($new_words, $sql_ary); } // now update the search match table, remove links to removed words and add links to new words @@ -1091,22 +1139,6 @@ class fulltext_native extends search_backend } /** - * Used by index() to sort strings by string length, longest first - */ - function strlencmp($a, $b) - { - $len_a = strlen($a); - $len_b = strlen($b); - - if ($len_a == $len_b) - { - return 0; - } - - return ($len_a > $len_b) ? -1 : 1; - } - - /** * Removes entries from the wordmatch table for the specified post_ids */ function index_remove($post_ids, $author_ids, $forum_ids) @@ -1142,14 +1174,14 @@ class fulltext_native extends search_backend $destroy_cache_words = array(); - // Remove common (> 60% of posts ) words + // Remove common (> 20% of posts ) words if ($config['num_posts'] >= 100) { // First, get the IDs of common words $sql = 'SELECT word_id FROM ' . SEARCH_WORDMATCH_TABLE . ' GROUP BY word_id - HAVING COUNT(word_id) > ' . floor($config['num_posts'] * 0.6); + HAVING COUNT(word_id) > ' . floor($config['num_posts'] * 0.2); $result = $db->sql_query($sql); $sql_in = array(); @@ -1200,9 +1232,9 @@ class fulltext_native extends search_backend { global $db; - $db->sql_query(((SQL_LAYER != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . SEARCH_WORDLIST_TABLE); - $db->sql_query(((SQL_LAYER != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . SEARCH_WORDMATCH_TABLE); - $db->sql_query(((SQL_LAYER != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . SEARCH_RESULTS_TABLE); + $db->sql_query((($db->sql_layer != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . SEARCH_WORDLIST_TABLE); + $db->sql_query((($db->sql_layer != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . SEARCH_WORDMATCH_TABLE); + $db->sql_query((($db->sql_layer != 'sqlite') ? 'TRUNCATE TABLE ' : 'DELETE FROM ') . SEARCH_RESULTS_TABLE); } /** @@ -1265,7 +1297,7 @@ class fulltext_native extends search_backend * @param string $encoding Text encoding * @return string Cleaned up text, only alphanumeric chars are left */ - function cleanup($text, $allowed_chars = null, $encoding = 'iso-8859-1') + function cleanup($text, $allowed_chars = null, $encoding = 'utf-8') { global $phpbb_root_path, $phpEx; static $conv = array(), $conv_loaded = array(); @@ -1290,7 +1322,7 @@ class fulltext_native extends search_backend /** * Replace HTML entities and NCRs */ - $text = html_entity_decode(utf8_decode_ncr($text), ENT_QUOTES); + $text = htmlspecialchars_decode(utf8_decode_ncr($text), ENT_QUOTES); /** * Load the UTF-8 normalizer @@ -1524,7 +1556,7 @@ class fulltext_native extends search_backend // These are fields required in the config table return array( 'tpl' => $tpl, - 'config' => array('fulltext_native_load_upd' => 'bool', 'fulltext_native_min_chars' => 'integer:0:252', 'fulltext_native_max_chars' => 'integer:0:252') + 'config' => array('fulltext_native_load_upd' => 'bool', 'fulltext_native_min_chars' => 'integer:0:255', 'fulltext_native_max_chars' => 'integer:0:255') ); } } diff --git a/phpBB/includes/search/search.php b/phpBB/includes/search/search.php index fa91b9eef5..4c8387bd22 100755 --- a/phpBB/includes/search/search.php +++ b/phpBB/includes/search/search.php @@ -285,7 +285,7 @@ class search_backend { $cache->destroy('_search_results_' . $row['search_key']); } - $db->sql_freeresult(); + $db->sql_freeresult($result); } // clear all searches that searched for the specified authors @@ -306,7 +306,7 @@ class search_backend { $cache->destroy('_search_results_' . $row['search_key']); } - $db->sql_freeresult(); + $db->sql_freeresult($result); } $sql = 'DELETE diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index 64a203e0bf..b69bcc5f44 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -64,7 +64,8 @@ class session $query_string = trim(implode('&', $args)); // basenamed page name (for example: index.php) - $page_name = htmlspecialchars(basename($script_name)); + $page_name = basename($script_name); + $page_name = urlencode(htmlspecialchars($page_name)); // current directory within the phpBB root (for example: adm) $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($root_path))); @@ -112,6 +113,13 @@ class session 'page' => $page ); +/* + if (!file_exists($page_name)) + { + trigger_error('You are on a page that does not exist!', E_USER_ERROR); + } +*/ + return $page_array; } @@ -127,9 +135,6 @@ class session * * @param bool $update_session_page if true the session page gets updated. * This can be set to circumvent certain scripts to update the users last visited page. - * - * @todo Introduce further user types, bot, guest - * @todo Change user_type (as above) to a bitfield? user_type & USER_FOUNDER for example */ function session_begin($update_session_page = true) { @@ -148,12 +153,9 @@ class session if (isset($_COOKIE[$config['cookie_name'] . '_sid']) || isset($_COOKIE[$config['cookie_name'] . '_u'])) { - // Switch to request_var ... can this cause issues, can a _GET/_POST param - // be used to poison this? Not sure that it makes any difference in terms of - // the end result, be it a cookie or param. - $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0); - $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', ''); - $this->session_id = request_var($config['cookie_name'] . '_sid', ''); + $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true); + $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true); + $this->session_id = request_var($config['cookie_name'] . '_sid', '', false, true); $SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid='; $_SID = (defined('NEED_SID')) ? $this->session_id : ''; @@ -265,7 +267,6 @@ class session $db->sql_query($sql); } - // Ultimately to be removed $this->data['is_registered'] = ($this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; $this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false; @@ -275,7 +276,10 @@ class session else { // Added logging temporarly to help debug bugs... - add_log('critical', 'LOG_IP_BROWSER_CHECK', $u_ip, $s_ip, $u_browser, $s_browser); + if (defined('DEBUG_EXTRA')) + { + add_log('critical', 'LOG_IP_BROWSER_CHECK', $u_ip, $s_ip, $u_browser, $s_browser); + } } } } @@ -320,8 +324,7 @@ class session * bot, act accordingly */ $bot = false; - $active_bots = array(); - $cache->obtain_bots($active_bots); + $active_bots = $cache->obtain_bots(); foreach ($active_bots as $row) { @@ -374,7 +377,7 @@ class session $sql = 'SELECT u.* FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k WHERE u.user_id = ' . (int) $this->cookie_data['u'] . ' - AND u.user_type <> ' . USER_INACTIVE . " + AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ") AND k.user_id = u.user_id AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'"; $result = $db->sql_query($sql); @@ -389,7 +392,7 @@ class session $sql = 'SELECT * FROM ' . USERS_TABLE . ' WHERE user_id = ' . (int) $this->cookie_data['u'] . ' - AND user_type <> ' . USER_INACTIVE; + AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; $result = $db->sql_query($sql); $this->data = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -405,9 +408,21 @@ class session $this->cookie_data['k'] = ''; $this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS; - $sql = 'SELECT * - FROM ' . USERS_TABLE . ' - WHERE user_id = ' . (int) $this->cookie_data['u']; + if (!$bot) + { + $sql = 'SELECT * + FROM ' . USERS_TABLE . ' + WHERE user_id = ' . (int) $this->cookie_data['u']; + } + else + { + // We give bots always the same session if it is not yet expired. + $sql = 'SELECT u.*, s.* + FROM ' . USERS_TABLE . ' u + LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id) + WHERE u.user_id = ' . (int) $bot; + } + $result = $db->sql_query($sql); $this->data = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -422,26 +437,66 @@ class session $this->data['session_last_visit'] = $this->time_now; } + // Force user id to be integer... + $this->data['user_id'] = (int) $this->data['user_id']; + // At this stage we should have a filled data array, defined cookie u and k data. // data array should contain recent session info if we're a real user and a recent // session exists in which case session_id will also be set // Is user banned? Are they excluded? Won't return on ban, exists within method - // @todo Change to !$this->data['user_type'] & USER_FOUNDER && !$this->data['user_type'] & USER_BOT in time if ($this->data['user_type'] != USER_FOUNDER) { $this->check_ban($this->data['user_id'], $this->ip); } - // - // Do away with ultimately? - $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS) ? true : false; + + $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; $this->data['is_bot'] = ($bot) ? true : false; - // - // - // @todo Change this ... check for "... && user_type & USER_NORMAL" ? + // If our friend is a bot, we re-assign a previously assigned session + if ($this->data['is_bot'] && $bot == $this->data['user_id'] && $this->data['session_id']) + { + // Only assign the current session if the ip and browser match... + $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check'])); + $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check'])); + + $s_browser = ($config['browser_check']) ? strtolower(substr($this->data['session_browser'], 0, 149)) : ''; + $u_browser = ($config['browser_check']) ? strtolower(substr($this->browser, 0, 149)) : ''; + + if ($u_ip === $s_ip && $s_browser === $u_browser) + { + $this->session_id = $this->data['session_id']; + + // Only update session DB a minute or so after last update or if page changes + if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page'])) + { + $sql_ary = array('session_time' => $this->time_now, 'session_last_visit' => $this->time_now, 'session_admin' => 0); + + if ($this->update_session_page) + { + $sql_ary['session_page'] = substr($this->page['page'], 0, 199); + } + + $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " + WHERE session_id = '" . $db->sql_escape($this->session_id) . "'"; + $db->sql_query($sql); + } + + $SID = '?sid='; + $_SID = ''; + + return true; + } + else + { + // If the ip and browser does not match make sure we only have one bot assigned to one session + $db->sql_query('DELETE FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . $this->data['user_id']); + } + } + $session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false; + $set_admin = ($set_admin && $this->data['is_registered']) ? true : false; // Create or update the session $sql_ary = array( @@ -516,6 +571,11 @@ class session unset($cookie_expire); } + else + { + $SID = '?sid='; + $_SID = ''; + } return true; } @@ -588,6 +648,9 @@ class session $SID = '?sid='; $this->session_id = $_SID = ''; + // To make sure a valid session is created we create one for the anonymous user + $this->session_create(ANONYMOUS); + return true; } @@ -610,88 +673,48 @@ class session $this->time_now = time(); } - switch (SQL_LAYER) - { - case 'mysql4': - case 'mysqli': - // Firstly, delete guest sessions - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE session_user_id = ' . ANONYMOUS . ' - AND session_time < ' . (int) ($this->time_now - $config['session_length']); - $db->sql_query($sql); - - // Keep only the most recent session for each user - // Note: if the user is currently browsing the board, his - // last_visit field won't be updated, which I believe should be - // the normal behavior anyway - $db->sql_return_on_error(true); - - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - USING ' . SESSIONS_TABLE . ' s1, ' . SESSIONS_TABLE . ' s2 - WHERE s1.session_user_id = s2.session_user_id - AND s1.session_time < s2.session_time'; - $db->sql_query($sql); - - $db->sql_return_on_error(false); - - // Update last visit time - $sql = 'UPDATE ' . USERS_TABLE. ' u, ' . SESSIONS_TABLE . ' s - SET u.user_lastvisit = s.session_time, u.user_lastpage = s.session_page - WHERE s.session_time < ' . (int) ($this->time_now - $config['session_length']) . ' - AND u.user_id = s.session_user_id'; - $db->sql_query($sql); - - // Delete everything else now - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE session_time < ' . (int) ($this->time_now - $config['session_length']); - $db->sql_query($sql); - - set_config('session_last_gc', $this->time_now, true); - break; - - default: + // Firstly, delete guest sessions + $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' + WHERE session_user_id = ' . ANONYMOUS . ' + AND session_time < ' . (int) ($this->time_now - $config['session_length']); + $db->sql_query($sql); - // Get expired sessions, only most recent for each user - $sql = 'SELECT session_user_id, session_page, MAX(session_time) AS recent_time - FROM ' . SESSIONS_TABLE . ' - WHERE session_time < ' . ($this->time_now - $config['session_length']) . ' - GROUP BY session_user_id, session_page'; - $result = $db->sql_query_limit($sql, 5); + // Get expired sessions, only most recent for each user + $sql = 'SELECT session_user_id, session_page, MAX(session_time) AS recent_time + FROM ' . SESSIONS_TABLE . ' + WHERE session_time < ' . ($this->time_now - $config['session_length']) . ' + GROUP BY session_user_id, session_page'; + $result = $db->sql_query_limit($sql, 10); - $del_user_id = array(); - $del_sessions = 0; + $del_user_id = array(); + $del_sessions = 0; - while ($row = $db->sql_fetchrow($result)); - { - if ($row['session_user_id'] != ANONYMOUS) - { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' - WHERE user_id = " . (int) $row['session_user_id']; - $db->sql_query($sql); - } + while ($row = $db->sql_fetchrow($result)) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' + WHERE user_id = " . (int) $row['session_user_id']; + $db->sql_query($sql); - $del_user_id[] = (int) $row['session_user_id']; - $del_sessions++; - } - $db->sql_freeresult($result); + $del_user_id[] = (int) $row['session_user_id']; + $del_sessions++; + } + $db->sql_freeresult($result); - if (sizeof($del_user_id)) - { - // Delete expired sessions - $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' - WHERE ' . $db->sql_in_set('session_user_id', $del_user_id) . ' - AND session_time < ' . ($this->time_now - $config['session_length']); - $db->sql_query($sql); - } + if (sizeof($del_user_id)) + { + // Delete expired sessions + $sql = 'DELETE FROM ' . SESSIONS_TABLE . ' + WHERE ' . $db->sql_in_set('session_user_id', $del_user_id) . ' + AND session_time < ' . ($this->time_now - $config['session_length']); + $db->sql_query($sql); + } - if ($del_sessions < 5) - { - // Less than 5 sessions, update gc timer ... else we want gc - // called again to delete other sessions - set_config('session_last_gc', $this->time_now, true); - } - break; + if ($del_sessions < 10) + { + // Less than 10 sessions, update gc timer ... else we want gc + // called again to delete other sessions + set_config('session_last_gc', $this->time_now, true); } if ($config['max_autologin_time']) @@ -713,20 +736,11 @@ class session { global $config; - if (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') - { - @setcookie($config['cookie_name'] . '_' . $name, $cookiedata, $cookietime, $config['cookie_path']); - } - else - { - // Firefox does not allow setting cookies with a domain containing no periods. - if (strpos($config['cookie_domain'], '.') === false) - { - $config['cookie_domain'] = '.' . $config['cookie_domain']; - } + $name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata); + $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime); + $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain']; - @setcookie($config['cookie_name'] . '_' . $name, $cookiedata, $cookietime, $config['cookie_path'], $config['cookie_domain'], $config['cookie_secure']); - } + header('Set-Cookie: ' . $name_data . '; expires=' . $expire . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false); } /** @@ -781,6 +795,7 @@ class session $result = $db->sql_query($sql); + $ban_triggered_by = 'user'; while ($row = $db->sql_fetchrow($result)) { if ((!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) || @@ -796,6 +811,20 @@ class session { $banned = true; $ban_row = $row; + + if (!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) + { + $ban_triggered_by = 'user'; + } + else if (!empty($row['ban_ip']) && preg_match('#^' . str_replace('*', '.*?', $row['ban_ip']) . '$#i', $user_ip)) + { + $ban_triggered_by = 'ip'; + } + else + { + $ban_triggered_by = 'email'; + } + // Don't break. Check if there is an exclude rule for this user } } @@ -819,6 +848,8 @@ class session $message = sprintf($this->lang[$message], $till_date, '<a href="mailto:' . $config['board_contact'] . '">', '</a>'); $message .= ($ban_row['ban_give_reason']) ? '<br /><br />' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : ''; + $message .= '<br /><br /><em>' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . '</em>'; + trigger_error($message); } @@ -826,6 +857,45 @@ class session } /** + * Check if ip is blacklisted + * This should be called only where absolutly necessary + * + * Only IPv4 (rbldns does not support AAAA records/IPv6 lookups) + * + * @author satmd (from the php manual) + * @return false if ip is not blacklisted, else an array([checked server], [lookup]) + */ + function check_dnsbl($ip = false) + { + if ($ip === false) + { + $ip = $this->ip; + } + + $dnsbl_check = array( + 'bl.spamcop.net' => 'http://spamcop.net/bl.shtml?', + 'list.dsbl.org' => 'http://dsbl.org/listing?', + 'sbl-xbl.spamhaus.org' => 'http://www.spamhaus.org/query/bl?ip=', + ); + + if ($ip) + { + $quads = explode('.', $ip); + $reverse_ip = $quads[3] . '.' . $quads[2] . '.' . $quads[1] . '.' . $quads[0]; + + foreach ($dnsbl_check as $dnsbl => $lookup) + { + if (phpbb_checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true) + { + return array($dnsbl, $lookup . $ip); + } + } + } + + return false; + } + + /** * Set/Update a persistent login key * * This method creates or updates a persistent session key. When a user makes @@ -960,15 +1030,20 @@ class user extends session $this->timezone = $config['board_timezone'] * 3600; $this->dst = $config['board_dst'] * 3600; -/* Browser-specific language setting removed - might re-appear later + /** + * If a guest user is surfing, we try to guess his/her language first by obtaining the browser language + * @todo if re-enabled we need to make sure only those languages installed are checked if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { $accept_lang_ary = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); + foreach ($accept_lang_ary as $accept_lang) { // Set correct format ... guess full xx_YY form $accept_lang = substr($accept_lang, 0, 2) . '_' . strtoupper(substr($accept_lang, 3, 2)); + $accept_lang = basename($accept_lang); + if (file_exists($phpbb_root_path . 'language/' . $accept_lang . "/common.$phpEx")) { $this->lang_name = $config['default_lang'] = $accept_lang; @@ -979,6 +1054,8 @@ class user extends session { // No match on xx_YY so try xx $accept_lang = substr($accept_lang, 0, 2); + $accept_lang = basename($accept_lang); + if (file_exists($phpbb_root_path . 'language/' . $accept_lang . "/common.$phpEx")) { $this->lang_name = $config['default_lang'] = $accept_lang; @@ -988,7 +1065,7 @@ class user extends session } } } -*/ + */ } // We include common language file here to not load it every time a custom language file is included @@ -1141,7 +1218,7 @@ class user extends session // Does the user need to change their password? If so, redirect to the // ucp profile reg_details page ... of course do not redirect if we're already in the ucp - if (!defined('IN_ADMIN') && $config['chg_passforce'] && $this->data['is_registered'] && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) + if (!defined('IN_ADMIN') && !defined('ADMIN_START') && $config['chg_passforce'] && $this->data['is_registered'] && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) { if (strpos($this->page['query_string'], 'mode=reg_details') === false && $this->page['page_name'] != "ucp.$phpEx") { @@ -1207,7 +1284,7 @@ class user extends session /** * Set language entry (called by add_lang) - * @access: private + * @access private */ function set_lang(&$lang, &$help, $lang_file, $use_db = false, $use_help = false) { @@ -1263,12 +1340,17 @@ class user extends session $midnight = gmmktime(0, 0, 0, $m, $d, $y) - $this->timezone - $this->dst; } - if (strpos($format, '|') === false || (!($gmepoch > $midnight && !$forcedate) && !($gmepoch > $midnight - 86400 && !$forcedate))) + if (strpos($format, '|') === false || ($gmepoch < $midnight - 86400 && !$forcedate) || ($gmepoch > $midnight + 172800 && !$forcedate)) { return strtr(@gmdate(str_replace('|', '', $format), $gmepoch + $this->timezone + $this->dst), $lang_dates); } - if ($gmepoch > $midnight && !$forcedate) + if ($gmepoch > $midnight + 86400 && !$forcedate) + { + $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1); + return str_replace('||', $this->lang['datetime']['TOMORROW'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates)); + } + else if ($gmepoch > $midnight && !$forcedate) { $format = substr($format, 0, strpos($format, '|')) . '||' . substr(strrchr($format, '|'), 1); return str_replace('||', $this->lang['datetime']['TODAY'], strtr(@gmdate($format, $gmepoch + $this->timezone + $this->dst), $lang_dates)); @@ -1337,13 +1419,15 @@ class user extends session static $imgs; global $phpbb_root_path; - if (empty($imgs[$img . $suffix]) || $width !== false) + $img_data = &$imgs[$img . $suffix]; + + if (empty($img_data) || $width !== false) { if (!isset($this->theme[$img]) || !$this->theme[$img]) { // Do not fill the image to let designers decide what to do if the image is empty - $imgs[$img . $suffix] = ''; - return $imgs[$img . $suffix]; + $img_data = ''; + return $img_data; } // Do not include dimensions? @@ -1369,9 +1453,9 @@ class user extends session $imgsrc = str_replace('{SUFFIX}', $suffix, $imgsrc); } - $imgs[$img . $suffix]['src'] = $phpbb_root_path . 'styles/' . $this->theme['imageset_path'] . '/imageset/' . str_replace('{LANG}', $this->img_lang, $imgsrc); - $imgs[$img . $suffix]['width'] = $width; - $imgs[$img . $suffix]['height'] = $height; + $img_data['src'] = $phpbb_root_path . 'styles/' . $this->theme['imageset_path'] . '/imageset/' . str_replace('{LANG}', $this->img_lang, $imgsrc); + $img_data['width'] = $width; + $img_data['height'] = $height; } $alt = (!empty($this->lang[$alt])) ? $this->lang[$alt] : $alt; @@ -1379,19 +1463,19 @@ class user extends session switch ($type) { case 'src': - return $imgs[$img . $suffix]['src']; + return $img_data['src']; break; case 'width': - return $imgs[$img . $suffix]['width']; + return $img_data['width']; break; case 'height': - return $imgs[$img . $suffix]['height']; + return $img_data['height']; break; default: - return '<img src="' . $imgs[$img . $suffix]['src'] . '"' . (($imgs[$img . $suffix]['width']) ? ' width="' . $imgs[$img . $suffix]['width'] . '"' : '') . (($imgs[$img . $suffix]['height']) ? ' height="' . $imgs[$img . $suffix]['height'] . '"' : '') . ' alt="' . $alt . '" title="' . $alt . '" />'; + return '<img src="' . $img_data['src'] . '"' . (($img_data['width']) ? ' width="' . $img_data['width'] . '"' : '') . (($img_data['height']) ? ' height="' . $img_data['height'] . '"' : '') . ' alt="' . $alt . '" title="' . $alt . '" />'; break; } } diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 5281860ac5..36a0b8920b 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -39,11 +39,11 @@ class template /** * Set template location - * @access: public + * @access public */ function set_template() { - global $phpbb_root_path, $config, $user; + global $phpbb_root_path, $user; if (file_exists($phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template')) { @@ -60,7 +60,7 @@ class template /** * Set custom template location (able to use directory outside of phpBB) - * @access: public + * @access public */ function set_custom_template($template_path, $template_name) { @@ -75,7 +75,7 @@ class template /** * Sets the template filenames for handles. $filename_array * should be a hash of handle => filename pairs. - * @access: public + * @access public */ function set_filenames($filename_array) { @@ -100,7 +100,7 @@ class template /** * Destroy template data set - * @access: public + * @access public */ function destroy() { @@ -109,7 +109,7 @@ class template /** * Reset/empty complete block - * @access: public + * @access public */ function destroy_block_vars($blockname) { @@ -139,7 +139,7 @@ class template /** * Display handle - * @access: public + * @access public */ function display($handle, $include_once = true) { @@ -159,7 +159,7 @@ class template /** * Display the handle and assign the output to a template variable or return the compiled result. - * @access: public + * @access public */ function assign_display($handle, $template_var = '', $return_content = true, $include_once = false) { @@ -179,7 +179,7 @@ class template /** * Load a compiled template if possible, if not, recompile it - * @access: private + * @access private */ function _tpl_load(&$handle) { @@ -197,7 +197,11 @@ class template global $db, $phpbb_root_path; - include_once($phpbb_root_path . 'includes/functions_template.' . $phpEx); + if (!class_exists('template_compile')) + { + include($phpbb_root_path . 'includes/functions_template.' . $phpEx); + } + $compile = new template_compile($this); // If the file for this handle is already loaded and compiled, do nothing. @@ -271,7 +275,7 @@ class template /** * Assign key variable pairs from an array - * @access: public + * @access public */ function assign_vars($vararray) { @@ -285,7 +289,7 @@ class template /** * Assign a single variable to a single key - * @access: public + * @access public */ function assign_var($varname, $varval) { @@ -296,7 +300,7 @@ class template /** * Assign key variable pairs from an array to a specified block - * @access: public + * @access public */ function assign_block_vars($blockname, $vararray) { @@ -398,7 +402,7 @@ class template * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars) * * @return false on error, true on success - * @access: public + * @access public */ function alter_block_array($blockname, $vararray, $key = false, $mode = 'insert') { @@ -484,7 +488,7 @@ class template /** * Include a seperate template - * @access: private + * @access private */ function _tpl_include($filename, $include = true) { @@ -500,7 +504,7 @@ class template if ($filename) { - include_once($filename); + include($filename); return; } eval(' ?>' . $this->compiled_code[$handle] . '<?php '); diff --git a/phpBB/includes/ucp/info/ucp_attachments.php b/phpBB/includes/ucp/info/ucp_attachments.php index 6028b5922a..a6aa393da5 100644 --- a/phpBB/includes/ucp/info/ucp_attachments.php +++ b/phpBB/includes/ucp/info/ucp_attachments.php @@ -20,7 +20,7 @@ class ucp_attachments_info 'title' => 'UCP_ATTACHMENTS', 'version' => '1.0.0', 'modes' => array( - 'attachments' => array('title' => 'UCP_ATTACHMENTS', 'auth' => 'acl_u_attach', 'cat' => array('UCP_ATTACHMENTS')), + 'attachments' => array('title' => 'UCP_MAIN_ATTACHMENTS', 'auth' => 'acl_u_attach', 'cat' => array('UCP_MAIN')), ), ); } diff --git a/phpBB/includes/ucp/info/ucp_prefs.php b/phpBB/includes/ucp/info/ucp_prefs.php index 4700ebc43a..53a012ea3c 100644 --- a/phpBB/includes/ucp/info/ucp_prefs.php +++ b/phpBB/includes/ucp/info/ucp_prefs.php @@ -21,8 +21,8 @@ class ucp_prefs_info 'version' => '1.0.0', 'modes' => array( 'personal' => array('title' => 'UCP_PREFS_PERSONAL', 'auth' => '', 'cat' => array('UCP_PREFS')), - 'view' => array('title' => 'UCP_PREFS_VIEW', 'auth' => '', 'cat' => array('UCP_PREFS')), 'post' => array('title' => 'UCP_PREFS_POST', 'auth' => '', 'cat' => array('UCP_PREFS')), + 'view' => array('title' => 'UCP_PREFS_VIEW', 'auth' => '', 'cat' => array('UCP_PREFS')), ), ); } diff --git a/phpBB/includes/ucp/info/ucp_profile.php b/phpBB/includes/ucp/info/ucp_profile.php index 61daccda45..86b731c280 100644 --- a/phpBB/includes/ucp/info/ucp_profile.php +++ b/phpBB/includes/ucp/info/ucp_profile.php @@ -20,10 +20,10 @@ class ucp_profile_info 'title' => 'UCP_PROFILE', 'version' => '1.0.0', 'modes' => array( - 'reg_details' => array('title' => 'UCP_PROFILE_REG_DETAILS', 'auth' => '', 'cat' => array('UCP_PROFILE')), 'profile_info' => array('title' => 'UCP_PROFILE_PROFILE_INFO', 'auth' => '', 'cat' => array('UCP_PROFILE')), 'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => '', 'cat' => array('UCP_PROFILE')), 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => '', 'cat' => array('UCP_PROFILE')), + 'reg_details' => array('title' => 'UCP_PROFILE_REG_DETAILS', 'auth' => '', 'cat' => array('UCP_PROFILE')), ), ); } diff --git a/phpBB/includes/ucp/ucp_activate.php b/phpBB/includes/ucp/ucp_activate.php index 5f7ba150f4..b3cb27223a 100644 --- a/phpBB/includes/ucp/ucp_activate.php +++ b/phpBB/includes/ucp/ucp_activate.php @@ -53,7 +53,6 @@ class ucp_activate if ($update_password) { $sql_ary = array( - 'user_type' => USER_NORMAL, 'user_actkey' => '', 'user_password' => $user_row['user_newpasswd'], 'user_newpasswd' => '' @@ -69,12 +68,12 @@ class ucp_activate { include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx); - // Now we need to demote the user from the inactive group and add him to the registered group - user_active_flip($user_row['user_id'], $user_row['user_type'], '', $user_row['username'], true); + user_active_flip('activate', $user_row['user_id']); - // Update last username - update_last_username(); - set_config('num_users', $config['num_users'] + 1, true); + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_actkey = '' + WHERE user_id = {$user_row['user_id']}"; + $db->sql_query($sql); } if ($config['require_activation'] == USER_ACTIVATION_ADMIN && !$update_password) @@ -94,10 +93,7 @@ class ucp_activate $messenger->headers('X-AntiAbuse: User IP - ' . $user->ip); $messenger->assign_vars(array( - 'SITENAME' => $config['sitename'], - 'USERNAME' => html_entity_decode($user_row['username']), - - 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . $config['board_email_sig'])) + 'USERNAME' => htmlspecialchars_decode($user_row['username'])) ); $messenger->send($user_row['user_notify_type']); diff --git a/phpBB/includes/ucp/ucp_attachments.php b/phpBB/includes/ucp/ucp_attachments.php index 549e3a11b2..2312d1f30d 100644 --- a/phpBB/includes/ucp/ucp_attachments.php +++ b/phpBB/includes/ucp/ucp_attachments.php @@ -78,11 +78,17 @@ class ucp_attachments $s_sort_dir .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>'; } + if (!isset($sort_key_sql[$sort_key])) + { + $sort_key = 'a'; + } + $order_by = $sort_key_sql[$sort_key] . ' ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'); $sql = 'SELECT COUNT(attach_id) as num_attachments FROM ' . ATTACHMENTS_TABLE . ' - WHERE poster_id = ' . $user->data['user_id']; + WHERE poster_id = ' . $user->data['user_id'] . ' + AND is_orphan = 0'; $result = $db->sql_query($sql); $num_attachments = $db->sql_fetchfield('num_attachments'); $db->sql_freeresult($result); @@ -92,6 +98,7 @@ class ucp_attachments LEFT JOIN ' . TOPICS_TABLE . ' t ON (a.topic_id = t.topic_id AND a.in_message = 0) LEFT JOIN ' . PRIVMSGS_TABLE . ' p ON (a.post_msg_id = p.msg_id AND a.in_message = 1) WHERE a.poster_id = ' . $user->data['user_id'] . " + AND a.is_orphan = 0 ORDER BY $order_by"; $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); diff --git a/phpBB/includes/ucp/ucp_confirm.php b/phpBB/includes/ucp/ucp_confirm.php index 2c83306e5e..087a186fa7 100644 --- a/phpBB/includes/ucp/ucp_confirm.php +++ b/phpBB/includes/ucp/ucp_confirm.php @@ -54,37 +54,9 @@ class ucp_confirm exit; } - // Some people might want the olde style CAPTCHA even if they have GD enabled, this also saves us from people who have GD but no TTF - $policy_modules = array('policy_entropy', 'policy_3dbitmap'); - - if (function_exists('imagettfbbox') && function_exists('imagettftext')) - { - $policy_modules = array_merge($policy_modules, array('policy_overlap', 'policy_shape', 'policy_cells', 'policy_stencil', 'policy_composite')); - } - - foreach ($policy_modules as $key => $name) + if ($config['captcha_gd']) { - if ($config[$name] === '0') - { - unset($policy_modules[$key]); - } - } - - $policy = ''; - if (@extension_loaded('gd') && sizeof($policy_modules)) - { - $change_lang = request_var('change_lang', ''); - - if ($change_lang) - { - $lang = $change_lang; - $user->lang_name = $lang = $change_lang; - $user->lang_path = $phpbb_root_path . 'language/' . $lang . '/'; - $user->lang = array(); - $user->add_lang(array('common', 'ucp')); - } include($phpbb_root_path . 'includes/captcha/captcha_gd.' . $phpEx); - $policy = $policy_modules[array_rand($policy_modules)]; } else { @@ -92,7 +64,7 @@ class ucp_confirm } $captcha = new captcha(); - $captcha->execute($row['code'], $policy); + $captcha->execute($row['code']); exit; } } diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php index 47403c83da..ad6bde9be7 100644 --- a/phpBB/includes/ucp/ucp_groups.php +++ b/phpBB/includes/ucp/ucp_groups.php @@ -172,8 +172,6 @@ class ucp_groups include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); $messenger = new messenger(); - $email_sig = str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']); - $sql = 'SELECT u.username, u.user_email, u.user_notify_type, u.user_jabber, u.user_lang FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u WHERE ug.user_id = u.user_id @@ -190,10 +188,8 @@ class ucp_groups $messenger->im($row['user_jabber'], $row['username']); $messenger->assign_vars(array( - 'EMAIL_SIG' => $email_sig, - 'SITENAME' => $config['sitename'], - 'USERNAME' => html_entity_decode($row['username']), - 'GROUP_NAME' => html_entity_decode($group_row[$group_id]['group_name']), + 'USERNAME' => htmlspecialchars_decode($row['username']), + 'GROUP_NAME' => htmlspecialchars_decode($group_row[$group_id]['group_name']), 'U_PENDING' => generate_board_url() . "/ucp.$phpEx?i=groups&mode=manage&action=list&g=$group_id", 'U_GROUP' => generate_board_url() . "/memberlist.$phpEx?mode=group&g=$group_id") @@ -496,7 +492,7 @@ class ucp_groups { if (isset($group_row['group_avatar']) && $group_row['group_avatar']) { - avatar_delete($group_row['group_avatar']); + avatar_delete('group', $group_row); } } @@ -723,7 +719,8 @@ class ucp_groups 'PAGINATION' => generate_pagination($this->u_action . "&action=$action&g=$group_id", $total_members, $config['topics_per_page'], $start, true), 'U_ACTION' => $this->u_action . "&g=$group_id", - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=ucp&field=usernames')) + 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=ucp&field=usernames'), + 'UA_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=ucp&field=usernames', false)) ); break; @@ -862,7 +859,7 @@ class ucp_groups $user->add_lang(array('acp/groups', 'acp/common')); - $name_ary = request_var('usernames', ''); + $name_ary = request_var('usernames', '', true); if (!$group_id) { diff --git a/phpBB/includes/ucp/ucp_main.php b/phpBB/includes/ucp/ucp_main.php index 8936a7728b..67e1c4d155 100644 --- a/phpBB/includes/ucp/ucp_main.php +++ b/phpBB/includes/ucp/ucp_main.php @@ -65,7 +65,7 @@ class ucp_main if (sizeof($forum_ary)) { - $sql .= ' AND ' . $db->sql_in_set('forum_id', $forum_ary); + $sql .= ' AND ' . $db->sql_in_set('forum_id', $forum_ary, true); } $result = $db->sql_query_limit($sql, 1); $g_forum_id = (int) $db->sql_fetchfield('forum_id'); @@ -76,15 +76,20 @@ class ucp_main WHERE t.forum_id = 0 AND t.topic_type = " . POST_GLOBAL . ' ORDER BY t.topic_last_post_time DESC'; - $result = $db->sql_query($sql); $topic_list = $rowset = array(); - while ($row = $db->sql_fetchrow($result)) + // If the user can't see any forums, he can't read any posts because fid of 0 is invalid + if ($g_forum_id) { - $topic_list[] = $row['topic_id']; - $rowset[$row['topic_id']] = $row; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $topic_list[] = $row['topic_id']; + $rowset[$row['topic_id']] = $row; + } + $db->sql_freeresult($result); } - $db->sql_freeresult($result); $topic_tracking_info = array(); if ($config['load_db_lastread']) @@ -122,8 +127,10 @@ class ucp_main $template->assign_block_vars('topicrow', array( 'FORUM_ID' => $forum_id, 'TOPIC_ID' => $topic_id, + 'LAST_POST_SUBJECT' => $row['topic_last_post_subject'], 'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']), 'LAST_POST_AUTHOR' => ($row['topic_last_poster_id'] == ANONYMOUS) ? (($row['topic_last_poster_name'] != '') ? $row['topic_last_poster_name'] . ' ' : $user->lang['GUEST'] . ' ') : $row['topic_last_poster_name'], + 'LAST_POST_AUTHOR_COLOUR' => ($row['topic_last_poster_colour']) ? '#' . $row['topic_last_poster_colour'] : '', 'TOPIC_TITLE' => censor_text($row['topic_title']), 'TOPIC_TYPE' => $topic_type, @@ -131,7 +138,7 @@ class ucp_main 'NEWEST_POST_IMG' => $user->img('icon_topic_newest', 'VIEW_NEWEST_POST'), 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt), 'TOPIC_FOLDER_IMG_SRC' => $user->img($folder_img, $folder_alt, false, '', 'src'), - 'ATTACH_ICON_IMG' => ($auth->acl_gets('f_download', 'u_download', $forum_id) && $row['topic_attachment']) ? $user->img('icon_topic_attach', '') : '', + 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id) && $row['topic_attachment']) ? $user->img('icon_topic_attach', '') : '', 'S_USER_POSTED' => (!empty($row['topic_posted']) && $row['topic_posted']) ? true : false, 'S_UNREAD' => $unread_topic, @@ -170,7 +177,6 @@ class ucp_main 'INTERESTS' => (!empty($row['user_interests'])) ? $row['user_interests'] : '', // 'S_GROUP_OPTIONS' => $group_options, - 'S_SHOW_ACTIVITY' => ($config['load_user_activity']) ? true : false, 'U_SEARCH_USER' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", 'author_id=' . $user->data['user_id'] . '&sr=posts') : '') ); @@ -286,6 +292,7 @@ class ucp_main $last_post_time = $user->format_date($row['forum_last_post_time']); $last_poster = ($row['forum_last_poster_name'] != '') ? $row['forum_last_poster_name'] : $user->lang['GUEST']; + $last_poster_colour = ($row['forum_last_poster_colour']) ? '#' . $row['forum_last_poster_colour'] : ''; $last_poster_url = ($row['forum_last_poster_id'] == ANONYMOUS) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['forum_last_poster_id']); $last_post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&p=" . $row['forum_last_post_id']) . '#p' . $row['forum_last_post_id']; @@ -299,10 +306,14 @@ class ucp_main 'FORUM_ID' => $forum_id, 'FORUM_FOLDER_IMG' => $user->img($folder_image, $folder_alt), 'FORUM_FOLDER_IMG_SRC' => $user->img($folder_image, $folder_alt, false, '', 'src'), + 'FORUM_IMAGE' => ($row['forum_image']) ? '<img src="' . $phpbb_root_path . $row['forum_image'] . '" alt="' . $user->lang[$folder_alt] . '" />' : '', + 'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '', 'FORUM_NAME' => $row['forum_name'], 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'), + 'LAST_POST_SUBJECT' => $row['forum_last_post_subject'], 'LAST_POST_TIME' => $last_post_time, 'LAST_POST_AUTHOR' => $last_poster, + 'LAST_POST_AUTHOR_COLOUR' => $last_poster_colour, 'U_LAST_POST_AUTHOR' => $last_poster_url, 'U_LAST_POST' => $last_post_url, @@ -417,13 +428,17 @@ class ucp_main // Send vars to template $template->assign_block_vars('topicrow', array( - 'FORUM_ID' => $forum_id, - 'TOPIC_ID' => $topic_id, - 'TOPIC_AUTHOR' => topic_topic_author($row), - 'FIRST_POST_TIME' => $user->format_date($row['topic_time']), - 'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']), - 'LAST_VIEW_TIME' => $user->format_date($row['topic_last_view_time']), - 'LAST_POST_AUTHOR' => ($row['topic_last_poster_name'] != '') ? $row['topic_last_poster_name'] : $user->lang['GUEST'], + 'FORUM_ID' => $forum_id, + 'TOPIC_ID' => $topic_id, + 'TOPIC_AUTHOR' => ($row['topic_first_poster_name']) ? $row['topic_first_poster_name'] : $user->lang['GUEST'], + 'TOPIC_AUTHOR_COLOUR' => ($row['topic_first_poster_colour']) ? '#' . $row['topic_first_poster_colour'] : '', + 'FIRST_POST_TIME' => $user->format_date($row['topic_time']), + 'LAST_POST_SUBJECT' => $row['topic_last_post_subject'], + 'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']), + 'LAST_VIEW_TIME' => $user->format_date($row['topic_last_view_time']), + 'LAST_POST_AUTHOR' => ($row['topic_last_poster_name'] != '') ? $row['topic_last_poster_name'] : $user->lang['GUEST'], + 'LAST_POST_AUTHOR_COLOUR' => ($row['topic_last_poster_colour']) ? '#' . $row['topic_last_poster_colour'] : '', + 'PAGINATION' => topic_generate_pagination($replies, append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . (($row['forum_id']) ? $row['forum_id'] : $forum_id) . "&t=$topic_id")), 'REPLIES' => $replies, 'VIEWS' => $row['topic_views'], @@ -437,7 +452,7 @@ class ucp_main 'TOPIC_ICON_IMG' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['img'] : '', 'TOPIC_ICON_IMG_WIDTH' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['width'] : '', 'TOPIC_ICON_IMG_HEIGHT' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['height'] : '', - 'ATTACH_ICON_IMG' => ($auth->acl_gets('f_download', 'u_download', $forum_id) && $row['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', + 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id) && $row['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', 'S_TOPIC_TYPE' => $row['topic_type'], 'S_USER_POSTED' => (!empty($row['topic_posted'])) ? true : false, @@ -446,6 +461,7 @@ class ucp_main 'U_NEWEST_POST' => append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&view=unread") . '#unread', 'U_LAST_POST' => $view_topic_url . '&p=' . $row['topic_last_post_id'] . '#p' . $row['topic_last_post_id'], 'U_LAST_POST_AUTHOR' => ($row['topic_last_poster_id'] != ANONYMOUS && $row['topic_last_poster_id']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['topic_last_poster_id']) : '', + 'U_TOPIC_AUTHOR' => ($row['topic_poster'] != ANONYMOUS && $row['topic_poster']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['topic_poster']) : '', 'U_VIEW_TOPIC' => $view_topic_url) ); } @@ -578,22 +594,26 @@ class ucp_main 'S_DELETED_TOPIC' => (!$row['topic_id']) ? true : false, 'S_GLOBAL_TOPIC' => (!$forum_id) ? true : false, - 'TOPIC_AUTHOR' => topic_topic_author($row), - 'FIRST_POST_TIME' => $user->format_date($row['topic_time']), - 'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']), - 'LAST_VIEW_TIME' => $user->format_date($row['topic_last_view_time']), - 'LAST_POST_AUTHOR' => ($row['topic_last_poster_name'] != '') ? $row['topic_last_poster_name'] : $user->lang['GUEST'], - 'PAGINATION' => topic_generate_pagination($replies, append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . (($row['forum_id']) ? $row['forum_id'] : $forum_id) . "&t=$topic_id")), + 'TOPIC_AUTHOR' => ($row['topic_first_poster_name']) ? $row['topic_first_poster_name'] : $user->lang['GUEST'], + 'TOPIC_AUTHOR_COLOUR' => ($row['topic_first_poster_colour']) ? '#' . $row['topic_first_poster_colour'] : '', + 'FIRST_POST_TIME' => $user->format_date($row['topic_time']), + 'LAST_POST_SUBJECT' => $row['topic_last_post_subject'], + 'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']), + 'LAST_VIEW_TIME' => $user->format_date($row['topic_last_view_time']), + 'LAST_POST_AUTHOR' => ($row['topic_last_poster_name'] != '') ? $row['topic_last_poster_name'] : $user->lang['GUEST'], + 'LAST_POST_AUTHOR_COLOUR' => ($row['topic_last_poster_colour']) ? '#' . $row['topic_last_poster_colour'] : '', + 'PAGINATION' => topic_generate_pagination($replies, append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . (($row['forum_id']) ? $row['forum_id'] : $forum_id) . "&t=$topic_id")), 'POSTED_AT' => $user->format_date($row['topic_time']), 'TOPIC_FOLDER_IMG' => $user->img($folder_img, $folder_alt), 'TOPIC_FOLDER_IMG_SRC' => $user->img($folder_img, $folder_alt, false, '', 'src'), - 'ATTACH_ICON_IMG' => ($auth->acl_gets('f_download', 'u_download', $forum_id) && $row['topic_attachment']) ? $user->img('icon_topic_attach', '') : '', + 'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $forum_id) && $row['topic_attachment']) ? $user->img('icon_topic_attach', '') : '', 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'), 'U_LAST_POST' => $view_topic_url . '&p=' . $row['topic_last_post_id'] . '#p' . $row['topic_last_post_id'], 'U_LAST_POST_AUTHOR' => ($row['topic_last_poster_id'] != ANONYMOUS && $row['topic_last_poster_id']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['topic_last_poster_id']) : '', + 'U_TOPIC_AUTHOR' => ($row['topic_poster'] != ANONYMOUS && $row['topic_poster']) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['topic_poster']) : '', 'U_VIEW_TOPIC' => $view_topic_url, 'U_VIEW_FORUM' => append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id), 'U_MOVE_UP' => ($row['order_id'] != 1) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=main&mode=bookmarks&move_up=' . $row['order_id']) : '', @@ -642,6 +662,8 @@ class ucp_main { $draft_subject = request_var('subject', '', true); $draft_message = request_var('message', '', true); + + utf8_normalize_nfc(array(&$draft_subject, &$draft_message)); if ($draft_message && $draft_subject) { diff --git a/phpBB/includes/ucp/ucp_pm.php b/phpBB/includes/ucp/ucp_pm.php index 5d1a4297ee..14afc81686 100644 --- a/phpBB/includes/ucp/ucp_pm.php +++ b/phpBB/includes/ucp/ucp_pm.php @@ -96,7 +96,7 @@ class ucp_pm $template->assign_vars(array( 'MESSAGE' => $l_new_message, 'S_NOT_LOGGED_IN' => ($user->data['user_id'] == ANONYMOUS) ? true : false, - 'CLICK_TO_VIEW' => sprintf($user->lang['CLICK_VIEW_PRIVMSG'], '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox') . '" onclick="jump_to_inbox();return false;" target="_new">', '</a>'), + 'CLICK_TO_VIEW' => sprintf($user->lang['CLICK_VIEW_PRIVMSG'], '<a href="' . append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox') . '" onclick="jump_to_inbox(); return false;">', '</a>'), 'U_INBOX' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox'), 'UA_INBOX' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&folder=inbox', false)) ); @@ -246,6 +246,17 @@ class ucp_pm { place_pm_into_folder($global_privmsgs_rules, request_var('release', 0)); $num_not_moved = $user->data['user_new_privmsg']; + + // Make sure num_not_moved is valid. + if ($num_not_moved < 0) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_new_privmsg = 0, user_unread_privmsg = 0 + WHERE user_id = ' . $user->data['user_id']; + $db->sql_query($sql); + + $num_not_moved = $user->data['user_new_privmsg'] = $user->data['user_unread_privmsg'] = 0; + } } if (!$msg_id && $folder_id == PRIVMSGS_NO_BOX) @@ -392,7 +403,7 @@ class ucp_pm break; default: - trigger_error('NO_ACTION_MODE'); + trigger_error('NO_ACTION_MODE', E_USER_ERROR); break; } diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index ff95bfc307..98aa35117b 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -66,6 +66,34 @@ function compose_pm($id, $mode, $action) redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm')); } + // Output PM_TO box if message composing + if ($action != 'edit') + { + if ($config['allow_mass_pm'] && $auth->acl_get('u_masspm')) + { + $sql = 'SELECT group_id, group_name, group_type + FROM ' . GROUPS_TABLE . ' + WHERE group_type NOT IN (' . GROUP_HIDDEN . ', ' . GROUP_CLOSED . ') + AND group_receive_pm = 1 + ORDER BY group_type DESC'; + $result = $db->sql_query($sql); + + $group_options = ''; + while ($row = $db->sql_fetchrow($result)) + { + $group_options .= '<option' . (($row['group_type'] == GROUP_SPECIAL) ? ' class="blue"' : '') . ' value="' . $row['group_id'] . '">' . (($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name']) . '</option>'; + } + $db->sql_freeresult($result); + } + + $template->assign_vars(array( + 'S_SHOW_PM_BOX' => true, + 'S_ALLOW_MASS_PM' => ($config['allow_mass_pm'] && $auth->acl_get('u_masspm')) ? true : false, + 'S_GROUP_OPTIONS' => ($config['allow_mass_pm'] && $auth->acl_get('u_masspm')) ? $group_options : '', + 'U_SEARCH_USER' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=post&field=username_list')) + ); + } + $sql = ''; // What is all this following SQL for? Well, we need to know @@ -149,7 +177,7 @@ function compose_pm($id, $mode, $action) break; default: - trigger_error('NO_ACTION_MODE'); + trigger_error('NO_ACTION_MODE', E_USER_ERROR); } if ($action == 'forward' && (!$config['forward_pm'] || !$auth->acl_get('u_pm_forward'))) @@ -177,7 +205,7 @@ function compose_pm($id, $mode, $action) $folder_id = (isset($post['folder_id'])) ? $post['folder_id'] : 0; $message_text = (isset($post['message_text'])) ? $post['message_text'] : ''; - if (!$post['author_id'] && $msg_id) + if ((!$post['author_id'] || ($post['author_id'] == ANONYMOUS && $action != 'delete')) && $msg_id) { trigger_error('NO_AUTHOR'); } @@ -307,19 +335,21 @@ function compose_pm($id, $mode, $action) $error[] = $user->lang['TOO_MANY_RECIPIENTS']; } + // Always check if the submitted attachment data is valid and belongs to the user. + // Further down (especially in submit_post()) we do not check this again. $message_parser->get_submitted_attachment_data(); if ($message_attachment && !$submit && !$refresh && !$preview && $action == 'edit') { - $sql = 'SELECT attach_id, physical_filename, attach_comment, real_filename, extension, mimetype, filesize, filetime, thumbnail + // Do not change to SELECT * + $sql = 'SELECT attach_id, is_orphan, attach_comment, real_filename FROM ' . ATTACHMENTS_TABLE . " WHERE post_msg_id = $msg_id AND in_message = 1 - ORDER BY filetime " . ((!$config['display_order']) ? 'DESC' : 'ASC'); + AND is_orphan = 0 + ORDER BY filetime " . ((!$config['display_order']) ? 'DESC' : 'ASC'); $result = $db->sql_query($sql); - $message_parser->attachment_data = array_merge($message_parser->attachment_data, $db->sql_fetchrowset($result)); - $db->sql_freeresult($result); } @@ -361,6 +391,7 @@ function compose_pm($id, $mode, $action) $smilies_status = ($config['allow_smilies'] && $config['auth_smilies_pm'] && $auth->acl_get('u_pm_smilies')) ? true : false; $img_status = ($config['auth_img_pm'] && $auth->acl_get('u_pm_img')) ? true : false; $flash_status = ($config['auth_flash_pm'] && $auth->acl_get('u_pm_flash')) ? true : false; + $url_status = ($config['allow_post_links']) ? true : false; // Save Draft if ($save && $auth->acl_get('u_savedrafts')) @@ -368,6 +399,8 @@ function compose_pm($id, $mode, $action) $subject = request_var('subject', '', true); $subject = (!$subject && $action != 'post') ? $user->lang['NEW_MESSAGE'] : $subject; $message = request_var('message', '', true); + + utf8_normalize_nfc(array(&$subject, &$message)); if ($subject && $message) { @@ -444,13 +477,9 @@ function compose_pm($id, $mode, $action) if ($submit || $preview || $refresh) { $subject = request_var('subject', '', true); - - if (strcmp($subject, strtoupper($subject)) == 0 && $subject) - { - $subject = strtolower($subject); - } - $message_parser->message = request_var('message', '', true); + + utf8_normalize_nfc(array(&$subject, &$message_parser->message)); $icon_id = request_var('icon', 0); @@ -473,7 +502,7 @@ function compose_pm($id, $mode, $action) $message_parser->parse_attachments('fileupload', $action, 0, $submit, $preview, $refresh, true); // Parse message - $message_parser->parse($enable_bbcode, $enable_urls, $enable_smilies, $img_status, $flash_status, true); + $message_parser->parse($enable_bbcode, ($config['allow_post_links']) ? $enable_urls : false, $enable_smilies, $img_status, $flash_status, true, $config['allow_sig_links']); if ($action != 'edit' && !$preview && !$refresh && $config['flood_interval'] && !$auth->acl_get('u_ignoreflood')) { @@ -604,7 +633,14 @@ function compose_pm($id, $mode, $action) if ($action == 'quotepost') { $post_id = request_var('p', 0); - $message_link = "[url=" . generate_board_url() . "/viewtopic.$phpEx?p={$post_id}#p{$post_id}]{$message_subject}[/url]\n"; + if ($config['allow_post_links']) + { + $message_link = "[url=" . generate_board_url() . "/viewtopic.$phpEx?p={$post_id}#p{$post_id}]{$message_subject}[/url]\n\n"; + } + else + { + $message_link = $user->lang['SUBJECT'] . ': ' . $message_subject . " (" . generate_board_url() . "/viewtopic.$phpEx?p={$post_id}#p{$post_id})\n\n"; + } } else { @@ -622,14 +658,23 @@ function compose_pm($id, $mode, $action) { $fwd_to_field = write_pm_addresses(array('to' => $post['to_address']), 0, true); + if ($config['allow_post_links']) + { + $quote_username_text = '[url=' . generate_board_url() . "/memberlist.$phpEx?mode=viewprofile&u={$post['author_id']}]{$quote_username}[/url]"; + } + else + { + $quote_username_text = $quote_username . ' (' . generate_board_url() . "/memberlist.$phpEx?mode=viewprofile&u={$post['author_id']})"; + } + $forward_text = array(); $forward_text[] = $user->lang['FWD_ORIGINAL_MESSAGE']; $forward_text[] = sprintf($user->lang['FWD_SUBJECT'], censor_text($message_subject)); $forward_text[] = sprintf($user->lang['FWD_DATE'], $user->format_date($message_time)); - $forward_text[] = sprintf($user->lang['FWD_FROM'], $quote_username); + $forward_text[] = sprintf($user->lang['FWD_FROM'], $quote_username_text); $forward_text[] = sprintf($user->lang['FWD_TO'], implode(', ', $fwd_to_field['to'])); - $message_parser->message = implode("\n", $forward_text) . "\n\n[quote=\"[url=" . generate_board_url() . "/memberlist.$phpEx?mode=viewprofile&u={$post['author_id']}]{$quote_username}[/url]\"]\n" . censor_text(trim($message_parser->message)) . "\n[/quote]"; + $message_parser->message = implode("\n", $forward_text) . "\n\n[quote=\"{$quote_username}\"]\n" . censor_text(trim($message_parser->message)) . "\n[/quote]"; $message_subject = ((!preg_match('/^Fwd:/', $message_subject)) ? 'Fwd: ' : '') . censor_text($message_subject); } @@ -783,10 +828,11 @@ function compose_pm($id, $mode, $action) 'SUBJECT' => (isset($message_subject)) ? $message_subject : '', 'MESSAGE' => $message_text, - 'BBCODE_STATUS' => ($bbcode_status) ? sprintf($user->lang['BBCODE_IS_ON'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '" onclick="target=\'_phpbbcode\';">', '</a>') : sprintf($user->lang['BBCODE_IS_OFF'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '" onclick="target=\'_phpbbcode\';">', '</a>'), + 'BBCODE_STATUS' => ($bbcode_status) ? sprintf($user->lang['BBCODE_IS_ON'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>') : sprintf($user->lang['BBCODE_IS_OFF'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>'), 'IMG_STATUS' => ($img_status) ? $user->lang['IMAGES_ARE_ON'] : $user->lang['IMAGES_ARE_OFF'], 'FLASH_STATUS' => ($flash_status) ? $user->lang['FLASH_IS_ON'] : $user->lang['FLASH_IS_OFF'], 'SMILIES_STATUS' => ($smilies_status) ? $user->lang['SMILIES_ARE_ON'] : $user->lang['SMILIES_ARE_OFF'], + 'URL_STATUS' => ($url_status) ? $user->lang['URL_IS_ON'] : $user->lang['URL_IS_OFF'], 'MINI_POST_IMG' => $user->img('icon_post_target', $user->lang['PM']), 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '', @@ -798,6 +844,7 @@ function compose_pm($id, $mode, $action) 'S_SMILIES_CHECKED' => ($smilies_checked) ? ' checked="checked"' : '', 'S_SIG_ALLOWED' => ($config['allow_sig'] && $auth->acl_get('u_sig')), 'S_SIGNATURE_CHECKED' => ($sig_checked) ? ' checked="checked"' : '', + 'S_LINKS_ALLOWED' => $url_status, 'S_MAGIC_URL_CHECKED' => ($urls_checked) ? ' checked="checked"' : '', 'S_SAVE_ALLOWED' => $auth->acl_get('u_savedrafts'), 'S_HAS_DRAFTS' => ($auth->acl_get('u_savedrafts') && $drafts), @@ -806,6 +853,7 @@ function compose_pm($id, $mode, $action) 'S_BBCODE_IMG' => $img_status, 'S_BBCODE_FLASH' => $flash_status, 'S_BBCODE_QUOTE' => true, + 'S_BBCODE_URL' => $url_status, 'S_POST_ACTION' => $s_action, 'S_HIDDEN_ADDRESS_FIELD' => $s_hidden_address_field, @@ -868,8 +916,8 @@ function handle_message_list_actions(&$address_list, $remove_u, $remove_g, $add_ $user_id_ary = array(); // Build usernames to add - $usernames = (isset($_REQUEST['username'])) ? array(request_var('username', '')) : array(); - $username_list = request_var('username_list', ''); + $usernames = (isset($_REQUEST['username'])) ? array(request_var('username', '', true)) : array(); + $username_list = request_var('username_list', '', true); if ($username_list) { $usernames = array_merge($usernames, explode("\n", $username_list)); @@ -900,6 +948,11 @@ function handle_message_list_actions(&$address_list, $remove_u, $remove_g, $add_ while ($row = $db->sql_fetchrow($result)) { + if ($row['user_id'] == ANONYMOUS) + { + continue; + } + $address_list['u'][$row['user_id']] = $type; } $db->sql_freeresult($result); @@ -908,6 +961,11 @@ function handle_message_list_actions(&$address_list, $remove_u, $remove_g, $add_ { foreach ($user_id_ary as $user_id) { + if ($user_id == ANONYMOUS) + { + continue; + } + $address_list['u'][$user_id] = $type; } } diff --git a/phpBB/includes/ucp/ucp_pm_options.php b/phpBB/includes/ucp/ucp_pm_options.php index c9e911b5f4..9b86553569 100644 --- a/phpBB/includes/ucp/ucp_pm_options.php +++ b/phpBB/includes/ucp/ucp_pm_options.php @@ -250,6 +250,8 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit $rule_string = ($cond_option != 'none') ? request_var('rule_string', '', true) : ''; $rule_user_id = ($cond_option != 'none') ? request_var('rule_user_id', 0) : 0; $rule_group_id = ($cond_option != 'none') ? request_var('rule_group_id', 0) : 0; + + utf8_normalize_nfc(&$rule_string); $action = (int) $action_option[0]; $folder_id = (int) $action_option[1]; @@ -433,7 +435,8 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit 'DEFAULT_ACTION' => ($config['full_folder_action'] == 1) ? $user->lang['DELETE_OLDEST_MESSAGES'] : $user->lang['HOLD_NEW_MESSAGES'], - 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=ucp&field=rule_string')) + 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=ucp&field=rule_string'), + 'UA_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=ucp&field=rule_string', true)) ); $rule_lang = $action_lang = $check_lang = array(); @@ -478,6 +481,11 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit } // Check + if (!isset($global_privmsgs_rules[$check_option])) + { + $check_option = 0; + } + define_check_option(($check_option && !isset($back['rule'])) ? true : false, $check_option, $check_lang); if ($check_option && !isset($back['rule'])) @@ -633,6 +641,8 @@ function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule { case 'text': $rule_string = request_var('rule_string', '', true); + + utf8_normalize_nfc(&$rule_string); $template->assign_vars(array( 'S_TEXT_CONDITION' => true, @@ -647,12 +657,14 @@ function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule case 'user': $rule_user_id = request_var('rule_user_id', 0); $rule_string = request_var('rule_string', '', true); + + utf8_normalize_nfc(&$rule_string); if ($rule_string && !$rule_user_id) { $sql = 'SELECT user_id FROM ' . USERS_TABLE . " - WHERE LOWER(username) = '" . $db->sql_escape(strtolower($rule_string)) . "'"; + WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($rule_string)) . "'"; $result = $db->sql_query($sql); $rule_user_id = (int) $db->sql_fetchfield('user_id'); $db->sql_freeresult($result); @@ -690,6 +702,8 @@ function define_cond_option($hardcoded, $cond_option, $rule_option, $global_rule case 'group': $rule_group_id = request_var('rule_group_id', 0); $rule_string = request_var('rule_string', '', true); + + utf8_normalize_nfc(&$rule_string); $sql_and = ($auth->acl_gets('a_group', 'a_groupadd', 'a_groupdel')) ? '<> ' . GROUP_SPECIAL : 'NOT IN (' . GROUP_SPECIAL . ', ' . GROUP_HIDDEN . ')'; $sql = 'SELECT group_id, group_name, group_type diff --git a/phpBB/includes/ucp/ucp_pm_viewfolder.php b/phpBB/includes/ucp/ucp_pm_viewfolder.php index 91a44c31c1..862702d7fc 100644 --- a/phpBB/includes/ucp/ucp_pm_viewfolder.php +++ b/phpBB/includes/ucp/ucp_pm_viewfolder.php @@ -26,8 +26,7 @@ function view_folder($id, $mode, $folder_id, $folder) $user->add_lang('viewforum'); // Grab icons - $icons = array(); - $cache->obtain_icons($icons); + $icons = $cache->obtain_icons(); $color_rows = array('marked', 'replied'); @@ -164,7 +163,18 @@ function view_folder($id, $mode, $folder_id, $folder) { foreach ($id_ary as $ug_id => $_id) { - $address_list[$message_id][] = (($type == 'u') ? '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $ug_id) . '">' : '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $ug_id) . '">') . (($recipient_list[$type][$ug_id]['colour']) ? '<span style="color:#' . $recipient_list[$type][$ug_id]['colour'] . '">' : '<span>') . $recipient_list[$type][$ug_id]['name'] . '</span></a>'; + $user_colour = ($recipient_list[$type][$ug_id]['colour']) ? ' style="color:#' . $recipient_list[$type][$ug_id]['colour'] . '"' : ''; + + if ($type == 'u') + { + $link = ($ug_id != ANONYMOUS) ? '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $ug_id) . '"' . $user_colour . '>' : ''; + } + else + { + $link = '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&g=' . $ug_id) . '"' . $user_colour . '>'; + } + + $address_list[$message_id][] = $link . $recipient_list[$type][$ug_id]['name'] . (($link) ? '</a>' : ''); } } } @@ -181,7 +191,7 @@ function view_folder($id, $mode, $folder_id, $folder) $folder_alt = ($row['pm_unread']) ? 'NEW_MESSAGES' : 'NO_NEW_MESSAGES'; // Generate all URIs ... - $message_author = '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['author_id']) . '">' . $row['username'] . '</a>'; + $message_author = ($row['author_id'] != ANONYMOUS) ? '<a href="' . append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $row['author_id']) . '">' . $row['username'] . '</a>' : $row['username']; $view_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=view&f=$folder_id&p=$message_id"); $remove_message_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=compose&action=delete&p=$message_id"); @@ -215,6 +225,7 @@ function view_folder($id, $mode, $folder_id, $folder) 'ATTACH_ICON_IMG' => ($auth->acl_get('u_pm_download') && $row['message_attachment'] && $config['allow_pm_attach']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '', 'S_PM_DELETED' => ($row['pm_deleted']) ? true : false, + 'S_AUTHOR_DELETED' => ($row['author_id'] == ANONYMOUS) ? true : false, 'U_VIEW_PM' => ($row['pm_deleted']) ? '' : $view_message_url, 'U_REMOVE_PM' => ($row['pm_deleted']) ? $remove_message_url : '', @@ -428,8 +439,6 @@ function get_pm_from($folder_id, $folder, $user_id) $sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); $sort_by_sql = array('a' => 'u.username', 't' => 'p.message_time', 's' => 'p.message_subject'); - $sort_key = (!in_array($sort_key, array('a', 't', 's'))) ? 't' : $sort_key; - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php index 4a399d847d..8da8f0bd18 100644 --- a/phpBB/includes/ucp/ucp_pm_viewmessage.php +++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php @@ -35,8 +35,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) } // Grab icons - $icons = array(); - $cache->obtain_icons($icons); + $icons = $cache->obtain_icons(); $bbcode = false; @@ -54,6 +53,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) // Parse the message and subject $message = $message_row['message_text']; + $message = str_replace("\n", '<br />', censor_text($message)); // Second parse bbcode here if ($message_row['bbcode_bitfield']) @@ -66,7 +66,6 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) // Replace naughty words such as farty pants $message_row['message_subject'] = censor_text($message_row['message_subject']); - $message = str_replace("\n", '<br />', censor_text($message)); // Editing information if ($message_row['message_edit_count'] && $config['display_last_edited']) @@ -146,6 +145,9 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) // End signature parsing, only if needed if ($signature) { + $signature = censor_text($signature); + $signature = str_replace("\n", '<br />', censor_text($signature)); + if ($user_info['user_sig_bbcode_bitfield']) { if ($bbcode === false) @@ -158,7 +160,6 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) } $signature = smiley_text($signature); - $signature = str_replace("\n", '<br />', censor_text($signature)); } $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm'); @@ -191,16 +192,17 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) 'U_INFO' => ($auth->acl_get('m_info') && $message_row['pm_forwarded']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'mode=pm_details&p=' . $message_row['msg_id'], true, $user->session_id) : '', 'U_DELETE' => ($auth->acl_get('u_pm_delete')) ? "$url&mode=compose&action=delete&f=$folder_id&p=" . $message_row['msg_id'] : '', - 'U_AUTHOR_PROFILE' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $author_id), + 'U_AUTHOR_PROFILE' => ($author_id != ANONYMOUS) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . $author_id) : '', 'U_EMAIL' => $user_info['email'], - 'U_QUOTE' => ($auth->acl_get('u_sendpm')) ? "$url&mode=compose&action=quote&f=$folder_id&p=" . $message_row['msg_id'] : '', + 'U_QUOTE' => ($auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&mode=compose&action=quote&f=$folder_id&p=" . $message_row['msg_id'] : '', 'U_EDIT' => (($message_row['message_time'] > time() - ($config['pm_edit_time'] * 60) || !$config['pm_edit_time']) && $folder_id == PRIVMSGS_OUTBOX && $auth->acl_get('u_pm_edit')) ? "$url&mode=compose&action=edit&f=$folder_id&p=" . $message_row['msg_id'] : '', - 'U_POST_REPLY_PM' => ($auth->acl_get('u_sendpm')) ? "$url&mode=compose&action=reply&f=$folder_id&p=" . $message_row['msg_id'] : '', + 'U_POST_REPLY_PM' => ($auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&mode=compose&action=reply&f=$folder_id&p=" . $message_row['msg_id'] : '', 'U_PREVIOUS_PM' => "$url&f=$folder_id&p=" . $message_row['msg_id'] . "&view=previous", 'U_NEXT_PM' => "$url&f=$folder_id&p=" . $message_row['msg_id'] . "&view=next", 'S_HAS_ATTACHMENTS' => (sizeof($attachments)) ? true : false, 'S_DISPLAY_NOTICE' => $display_notice && $message_row['message_attachment'], + 'S_AUTHOR_DELETED' => ($author_id == ANONYMOUS) ? true : false, 'U_PRINT_PM' => ($config['print_pm'] && $auth->acl_get('u_pm_printpm')) ? "$url&f=$folder_id&p=" . $message_row['msg_id'] . "&view=print" : '', 'U_FORWARD_PM' => ($config['forward_pm'] && $auth->acl_get('u_pm_forward')) ? "$url&mode=compose&action=forward&f=$folder_id&p=" . $message_row['msg_id'] : '') @@ -295,13 +297,13 @@ function message_history($msg_id, $user_id, $message_row, $folder) } // Instantiate BBCode class - if ((empty($bbcode) || $bbcode === false) && $bbcode_bitfield) + if ((empty($bbcode) || $bbcode === false) && $bbcode_bitfield !== '') { if (!class_exists('bbcode')) { include($phpbb_root_path . 'includes/bbcode.' . $phpEx); } - $bbcode = new bbcode($bbcode_bitfield); + $bbcode = new bbcode(base64_encode($bbcode_bitfield)); } $title = censor_text($title); @@ -318,6 +320,9 @@ function message_history($msg_id, $user_id, $message_row, $folder) $subject = $row['message_subject']; $message = $row['message_text']; + $message = censor_text($message); + $message = str_replace("\n", '<br />', $message); + if ($row['bbcode_bitfield']) { $bbcode->bbcode_second_pass($message, $row['bbcode_uid'], $row['bbcode_bitfield']); @@ -326,7 +331,6 @@ function message_history($msg_id, $user_id, $message_row, $folder) $message = smiley_text($message, !$row['enable_smilies']); $subject = censor_text($subject); - $message = censor_text($message); if ($id == $msg_id) { @@ -339,16 +343,17 @@ function message_history($msg_id, $user_id, $message_row, $folder) 'AUTHOR_NAME' => $author, 'SUBJECT' => $subject, 'SENT_DATE' => $user->format_date($row['message_time']), - 'MESSAGE' => str_replace("\n", '<br />', $message), + 'MESSAGE' => $message, 'FOLDER' => implode(', ', $row['folder']), - 'S_CURRENT_MSG' => ($row['msg_id'] == $msg_id), - + 'S_CURRENT_MSG' => ($row['msg_id'] == $msg_id), + 'S_AUTHOR_DELETED' => ($author_id == ANONYMOUS) ? true : false, + 'U_MSG_ID' => $row['msg_id'], 'U_VIEW_MESSAGE' => "$url&f=$folder_id&p=" . $row['msg_id'], - 'U_AUTHOR_PROFILE' => append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=viewprofile&u=$author_id"), - 'U_QUOTE' => ($auth->acl_get('u_sendpm') && $author_id != $user->data['user_id']) ? "$url&mode=compose&action=quote&f=" . $folder_id . "&p=" . $row['msg_id'] : '', - 'U_POST_REPLY_PM' => ($author_id != $user->data['user_id'] && $auth->acl_get('u_sendpm')) ? "$url&mode=compose&action=reply&f=$folder_id&p=" . $row['msg_id'] : '') + 'U_AUTHOR_PROFILE' => ($author_id != ANONYMOUS) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=viewprofile&u=$author_id") : '', + 'U_QUOTE' => ($auth->acl_get('u_sendpm') && $author_id != ANONYMOUS && $author_id != $user->data['user_id']) ? "$url&mode=compose&action=quote&f=" . $folder_id . "&p=" . $row['msg_id'] : '', + 'U_POST_REPLY_PM' => ($author_id != $user->data['user_id'] && $author_id != ANONYMOUS && $auth->acl_get('u_sendpm')) ? "$url&mode=compose&action=reply&f=$folder_id&p=" . $row['msg_id'] : '') ); unset($rowset[$id]); $prev_id = $id; @@ -389,8 +394,7 @@ function get_user_informations($user_id, $user_row) } // Grab ranks - $ranks = array(); - $cache->obtain_ranks($ranks); + $ranks = $cache->obtain_ranks(); // Generate online information for user if ($config['load_onlinetrack']) @@ -429,7 +433,7 @@ function get_user_informations($user_id, $user_row) } $avatar_img .= $user_row['user_avatar']; - $user_row['avatar'] = '<img src="' . $avatar_img . '" width="' . $user_row['user_avatar_width'] . '" height="' . $user_row['user_avatar_height'] . '" border="0" alt="" />'; + $user_row['avatar'] = '<img src="' . $avatar_img . '" width="' . $user_row['user_avatar_width'] . '" height="' . $user_row['user_avatar_height'] . '" alt="' . $user->lang['USER_AVATAR'] . '" />'; } $user_row['rank_title'] = $user_row['rank_image'] = ''; @@ -437,7 +441,7 @@ function get_user_informations($user_id, $user_row) if (!empty($user_row['user_rank'])) { $user_row['rank_title'] = (isset($ranks['special'][$user_row['user_rank']])) ? $ranks['special'][$user_row['user_rank']]['rank_title'] : ''; - $user_row['rank_image'] = (!empty($ranks['special'][$user_row['user_rank']]['rank_image'])) ? '<img src="' . $config['ranks_path'] . '/' . $ranks['special'][$user_row['user_rank']]['rank_image'] . '" border="0" alt="' . $ranks['special'][$user_row['user_rank']]['rank_title'] . '" title="' . $ranks['special'][$user_row['user_rank']]['rank_title'] . '" /><br />' : ''; + $user_row['rank_image'] = (!empty($ranks['special'][$user_row['user_rank']]['rank_image'])) ? '<img src="' . $config['ranks_path'] . '/' . $ranks['special'][$user_row['user_rank']]['rank_image'] . '" alt="' . $ranks['special'][$user_row['user_rank']]['rank_title'] . '" title="' . $ranks['special'][$user_row['user_rank']]['rank_title'] . '" /><br />' : ''; } else { @@ -448,7 +452,7 @@ function get_user_informations($user_id, $user_row) if ($user_row['user_posts'] >= $rank['rank_min']) { $user_row['rank_title'] = $rank['rank_title']; - $user_row['rank_image'] = (!empty($rank['rank_image'])) ? '<img src="' . $config['ranks_path'] . '/' . $rank['rank_image'] . '" border="0" alt="' . $rank['rank_title'] . '" title="' . $rank['rank_title'] . '" /><br />' : ''; + $user_row['rank_image'] = (!empty($rank['rank_image'])) ? '<img src="' . $config['ranks_path'] . '/' . $rank['rank_image'] . '" alt="' . $rank['rank_title'] . '" title="' . $rank['rank_title'] . '" /><br />' : ''; break; } } diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php index ff8df44148..378562a2dd 100644 --- a/phpBB/includes/ucp/ucp_prefs.php +++ b/phpBB/includes/ucp/ucp_prefs.php @@ -30,42 +30,30 @@ class ucp_prefs case 'personal': $data = array( - 'notifymethod' => $user->data['user_notify_type'], - 'dateformat' => $user->data['user_dateformat'], - 'lang' => $user->data['user_lang'], - 'style' => $user->data['user_style'], - 'tz' => $user->data['user_timezone'], + 'notifymethod' => request_var('notifymethod', $user->data['user_notify_type']), + 'dateformat' => request_var('dateformat', $user->data['user_dateformat']), + 'lang' => request_var('lang', $user->data['user_lang']), + 'style' => request_var('style', (int) $user->data['user_style']), + 'tz' => request_var('tz', (float) $user->data['user_timezone']), + + 'dst' => request_var('dst', (bool) $user->data['user_dst']), + 'viewemail' => request_var('viewemail', (bool) $user->data['user_allow_viewemail']), + 'massemail' => request_var('massemail', (bool) $user->data['user_allow_massemail']), + 'hideonline' => request_var('hideonline', (bool) !$user->data['user_allow_viewonline']), + 'notifypm' => request_var('notifypm', (bool) $user->data['user_notify_pm']), + 'popuppm' => request_var('popuppm', (bool) $user->optionget('popuppm')), + 'allowpm' => request_var('allowpm', (bool) $user->data['user_allow_pm']), ); if ($submit) { - $var_ary = array( - 'dateformat' => (string) $config['default_dateformat'], - 'lang' => (string) $config['default_lang'], - 'tz' => (float) $config['board_timezone'], - 'style' => (int) $config['default_style'], - 'dst' => (bool) $config['board_dst'], - 'viewemail' => false, - 'massemail' => true, - 'hideonline' => false, - 'notifymethod' => 0, - 'notifypm' => true, - 'popuppm' => false, - 'allowpm' => true, - ); + $data['style'] = ($config['override_user_style']) ? $config['default_style'] : $data['style']; - foreach ($var_ary as $var => $default) - { - $data[$var] = request_var($var, $default); - } - - $var_ary = array( + $error = validate_data($data, array( 'dateformat' => array('string', false, 3, 30), - 'lang' => array('match', false, '#^[a-z_\-]{2,}$#i'), + 'lang' => array('match', false, '#^[a-z0-9_\-]{2,}$#i'), 'tz' => array('num', false, -14, 14), - ); - - $error = validate_data($data, $var_ary); + )); if (!sizeof($error)) { @@ -126,13 +114,13 @@ class ucp_prefs 'S_NOTIFY_EMAIL' => ($data['notifymethod'] == NOTIFY_EMAIL) ? true : false, 'S_NOTIFY_IM' => ($data['notifymethod'] == NOTIFY_IM) ? true : false, 'S_NOTIFY_BOTH' => ($data['notifymethod'] == NOTIFY_BOTH) ? true : false, - 'S_VIEW_EMAIL' => (isset($data['viewemail'])) ? $data['viewemail'] : $user->data['user_allow_viewemail'], - 'S_MASS_EMAIL' => (isset($data['massemail'])) ? $data['massemail'] : $user->data['user_allow_massemail'], - 'S_ALLOW_PM' => (isset($data['allowpm'])) ? $data['allowpm'] : $user->data['user_allow_pm'], - 'S_HIDE_ONLINE' => (isset($data['hideonline'])) ? $data['hideonline'] : !$user->data['user_allow_viewonline'], - 'S_NOTIFY_PM' => (isset($data['notifypm'])) ? $data['notifypm'] : $user->data['user_notify_pm'], - 'S_POPUP_PM' => (isset($data['popuppm'])) ? $data['popuppm'] : $user->optionget('popuppm'), - 'S_DST' => (isset($data['dst'])) ? $data['dst'] : $user->data['user_dst'], + 'S_VIEW_EMAIL' => $data['viewemail'], + 'S_MASS_EMAIL' => $data['massemail'], + 'S_ALLOW_PM' => $data['allowpm'], + 'S_HIDE_ONLINE' => $data['hideonline'], + 'S_NOTIFY_PM' => $data['notifypm'], + 'S_POPUP_PM' => $data['popuppm'], + 'S_DST' => $data['dst'], 'DATE_FORMAT' => $data['dateformat'], 'S_DATEFORMAT_OPTIONS' => $dateformat_options, @@ -141,7 +129,7 @@ class ucp_prefs 'A_DEFAULT_DATEFORMAT' => addslashes($config['default_dateformat']), 'S_LANG_OPTIONS' => language_select($data['lang']), - 'S_STYLE_OPTIONS' => style_select($data['style']), + 'S_STYLE_OPTIONS' => ($config['override_user_style']) ? '' : style_select($data['style']), 'S_TZ_OPTIONS' => tz_select($data['tz']), 'S_CAN_HIDE_ONLINE' => ($auth->acl_get('u_hideonline')) ? true : false, 'S_SELECT_NOTIFY' => ($config['jab_enable'] && $user->data['user_jabber'] && @extension_loaded('xml')) ? true : false) @@ -159,32 +147,23 @@ class ucp_prefs 'post_sk' => (!empty($user->data['user_post_sortby_type'])) ? $user->data['user_post_sortby_type'] : 't', 'post_sd' => (!empty($user->data['user_post_sortby_dir'])) ? $user->data['user_post_sortby_dir'] : 'a', 'post_st' => (!empty($user->data['user_post_show_days'])) ? $user->data['user_post_show_days'] : 0, + + 'images' => request_var('images', (bool) $user->optionget('viewimg')), + 'flash' => request_var('flash', (bool) $user->optionget('viewflash')), + 'smilies' => request_var('smilies', (bool) $user->optionget('viewsmilies')), + 'sigs' => request_var('sigs', (bool) $user->optionget('viewsigs')), + 'avatars' => request_var('avatars', (bool) $user->optionget('viewavatars')), + 'wordcensor' => request_var('wordcensor', (bool) $user->optionget('viewcensors')), ); if ($submit) { - $var_ary = array_merge($data, array( - 'images' => true, - 'flash' => false, - 'smilies' => true, - 'sigs' => true, - 'avatars' => true, - 'wordcensor'=> false, - )); - - foreach ($var_ary as $var => $default) - { - $data[$var] = request_var($var, $default); - } - - $var_ary = array( + $error = validate_data($data, array( 'topic_sk' => array('string', false, 1, 1), 'topic_sd' => array('string', false, 1, 1), 'post_sk' => array('string', false, 1, 1), 'post_sd' => array('string', false, 1, 1), - ); - - $error = validate_data($data, $var_ary); + )); if (!sizeof($error)) { @@ -269,12 +248,12 @@ class ucp_prefs $template->assign_vars(array( 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '', - 'S_IMAGES' => (isset($data['images'])) ? $data['images'] : $user->optionget('viewimg'), - 'S_FLASH' => (isset($data['flash'])) ? $data['flash'] : $user->optionget('viewflash'), - 'S_SMILIES' => (isset($data['smilies'])) ? $data['smilies'] : $user->optionget('viewsmilies'), - 'S_SIGS' => (isset($data['sigs'])) ? $data['sigs'] : $user->optionget('viewsigs'), - 'S_AVATARS' => (isset($data['avatars'])) ? $data['avatars'] : $user->optionget('viewavatars'), - 'S_DISABLE_CENSORS' => (isset($data['wordcensor'])) ? $data['wordcensor'] : $user->optionget('viewcensors'), + 'S_IMAGES' => $data['images'], + 'S_FLASH' => $data['flash'], + 'S_SMILIES' => $data['smilies'], + 'S_SIGS' => $data['sigs'], + 'S_AVATARS' => $data['avatars'], + 'S_DISABLE_CENSORS' => $data['wordcensor'], 'S_CHANGE_CENSORS' => ($auth->acl_get('u_chgcensors')) ? true : false, @@ -291,21 +270,14 @@ class ucp_prefs case 'post': $data = array( - 'bbcode' => $user->optionget('bbcode'), - 'smilies' => $user->optionget('smilies'), - 'sig' => $user->optionget('attachsig'), - 'notify' => $user->data['user_notify'], + 'bbcode' => request_var('bbcode', $user->optionget('bbcode')), + 'smilies' => request_var('smilies', $user->optionget('smilies')), + 'sig' => request_var('sig', $user->optionget('attachsig')), + 'notify' => request_var('notify', $user->data['user_notify']), ); if ($submit) { - $var_ary = $data; - - foreach ($var_ary as $var => $default) - { - $data[$var] = request_var($var, $default); - } - $user->optionset('bbcode', $data['bbcode']); $user->optionset('smilies', $data['smilies']); $user->optionset('attachsig', $data['sig']); diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index d757d6e14d..840f63ff48 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -33,25 +33,22 @@ class ucp_profile { case 'reg_details': + $data = array( + 'username' => request_var('username', $user->data['username'], true), + 'email' => request_var('email', $user->data['user_email']), + 'email_confirm' => request_var('email_confirm', ''), + 'new_password' => request_var('new_password', '', true), + 'cur_password' => request_var('cur_password', '', true), + 'password_confirm' => request_var('password_confirm', '', true), + ); + if ($submit) { - $var_ary = array( - 'username' => $user->data['username'], - 'email' => $user->data['user_email'], - 'email_confirm' => (string) '', - 'new_password' => (string) '', - 'cur_password' => (string) '', - 'password_confirm' => (string) '', - ); - - foreach ($var_ary as $var => $default) - { - $data[$var] = request_var($var, $default); - } - // Do not check cur_password, it is the old one. - $var_ary = array( - 'new_password' => array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), + $check_ary = array( + 'new_password' => array( + array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), + array('password')), 'password_confirm' => array('string', true, $config['min_pass_chars'], $config['max_pass_chars']), 'email' => array( array('string', false, 6, 60), @@ -61,27 +58,31 @@ class ucp_profile if ($auth->acl_get('u_chgname') && $config['allow_namechange']) { - $var_ary['username'] = array( + $check_ary['username'] = array( array('string', false, $config['min_name_chars'], $config['max_name_chars']), array('username', $data['username']), ); } - $error = validate_data($data, $var_ary); - extract($data); - unset($data); + $error = validate_data($data, $check_ary); - if ($auth->acl_get('u_chgpasswd') && $new_password && $password_confirm != $new_password) + if ($auth->acl_get('u_chgpasswd') && $data['new_password'] && $data['password_confirm'] != $data['new_password']) { $error[] = 'NEW_PASSWORD_ERROR'; } - if (($new_password || ($auth->acl_get('u_chgemail') && $email != $user->data['user_email']) || ($username != $user->data['username'] && $auth->acl_get('u_chgname') && $config['allow_namechange'])) && md5($cur_password) != $user->data['user_password']) + if (($data['new_password'] || ($auth->acl_get('u_chgemail') && $data['email'] != $user->data['user_email']) || ($data['username'] != $user->data['username'] && $auth->acl_get('u_chgname') && $config['allow_namechange'])) && md5($data['cur_password']) != $user->data['user_password']) { $error[] = 'CUR_PASSWORD_ERROR'; } - if ($auth->acl_get('u_chgemail') && $email != $user->data['user_email'] && $email_confirm != $email) + // Only check the new password against the previous password if there have been no errors + if (!sizeof($error) && $auth->acl_get('u_chgpasswd') && $data['new_password'] && md5($data['new_password']) == $user->data['user_password']) + { + $error[] = 'SAME_PASSWORD_ERROR'; + } + + if ($auth->acl_get('u_chgemail') && $data['email'] != $user->data['user_email'] && $data['email_confirm'] != $data['email']) { $error[] = 'NEW_EMAIL_ERROR'; } @@ -89,32 +90,33 @@ class ucp_profile if (!sizeof($error)) { $sql_ary = array( - 'username' => ($auth->acl_get('u_chgname') && $config['allow_namechange']) ? $username : $user->data['username'], - 'user_email' => ($auth->acl_get('u_chgemail')) ? $email : $user->data['user_email'], - 'user_email_hash' => ($auth->acl_get('u_chgemail')) ? crc32(strtolower($email)) . strlen($email) : $user->data['user_email_hash'], - 'user_password' => ($auth->acl_get('u_chgpasswd') && $new_password) ? md5($new_password) : $user->data['user_password'], - 'user_passchg' => ($auth->acl_get('u_chgpasswd') && $new_password) ? time() : 0, + 'username' => ($auth->acl_get('u_chgname') && $config['allow_namechange']) ? $data['username'] : $user->data['username'], + 'username_clean' => ($auth->acl_get('u_chgname') && $config['allow_namechange']) ? utf8_clean_string($data['username']) : $user->data['username_clean'], + 'user_email' => ($auth->acl_get('u_chgemail')) ? $data['email'] : $user->data['user_email'], + 'user_email_hash' => ($auth->acl_get('u_chgemail')) ? crc32(strtolower($data['email'])) . strlen($data['email']) : $user->data['user_email_hash'], + 'user_password' => ($auth->acl_get('u_chgpasswd') && $data['new_password']) ? md5($data['new_password']) : $user->data['user_password'], + 'user_passchg' => ($auth->acl_get('u_chgpasswd') && $data['new_password']) ? time() : 0, ); - if ($auth->acl_get('u_chgname') && $config['allow_namechange'] && $username != $user->data['username']) + if ($auth->acl_get('u_chgname') && $config['allow_namechange'] && $data['username'] != $user->data['username']) { - add_log('user', $user->data['user_id'], 'LOG_USER_UPDATE_NAME', $user->data['username'], $username); + add_log('user', $user->data['user_id'], 'LOG_USER_UPDATE_NAME', $user->data['username'], $data['username']); } - if ($auth->acl_get('u_chgpasswd') && $new_password && md5($new_password) != $user->data['user_password']) + if ($auth->acl_get('u_chgpasswd') && $data['new_password'] && md5($data['new_password']) != $user->data['user_password']) { $user->reset_login_keys(); - add_log('user', $user->data['user_id'], 'LOG_USER_NEW_PASSWORD', $username); + add_log('user', $user->data['user_id'], 'LOG_USER_NEW_PASSWORD', $data['username']); } - if ($auth->acl_get('u_chgemail') && $email != $user->data['user_email']) + if ($auth->acl_get('u_chgemail') && $data['email'] != $user->data['user_email']) { - add_log('user', $user->data['user_id'], 'LOG_USER_UPDATE_EMAIL', $username, $user->data['user_email'], $email); + add_log('user', $user->data['user_id'], 'LOG_USER_UPDATE_EMAIL', $data['username'], $user->data['user_email'], $data['email']); } - if ($config['email_enable'] && $email != $user->data['user_email'] && ($config['require_activation'] == USER_ACTIVATION_SELF || $config['require_activation'] == USER_ACTIVATION_ADMIN)) + if ($config['email_enable'] && $data['email'] != $user->data['user_email'] && $user->data['user_type'] != USER_FOUNDER && ($config['require_activation'] == USER_ACTIVATION_SELF || $config['require_activation'] == USER_ACTIVATION_ADMIN)) { - include_once($phpbb_root_path . 'includes/functions_messenger.'.$phpEx); + include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); $server_url = generate_board_url(); @@ -129,7 +131,7 @@ class ucp_profile $messenger->template($template_file, $user->data['user_lang']); $messenger->replyto($config['board_contact']); - $messenger->to($email, $username); + $messenger->to($data['email'], $data['username']); $messenger->headers('X-AntiAbuse: Board servername - ' . $config['server_name']); $messenger->headers('X-AntiAbuse: User_id - ' . $user->data['user_id']); @@ -137,10 +139,7 @@ class ucp_profile $messenger->headers('X-AntiAbuse: User IP - ' . $user->ip); $messenger->assign_vars(array( - 'SITENAME' => $config['sitename'], - 'USERNAME' => html_entity_decode($username), - 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']), - + 'USERNAME' => htmlspecialchars_decode($username), 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user->data['user_id']}&k=$user_actkey") ); @@ -148,12 +147,21 @@ class ucp_profile if ($config['require_activation'] == USER_ACTIVATION_ADMIN) { - // Grab an array of user_id's with a_user permissions + // Grab an array of user_id's with a_user permissions ... these users can activate a user $admin_ary = $auth->acl_get_list(false, 'a_user', false); + $admin_ary = (!empty($admin_ary[0]['a_user'])) ? $admin_ary[0]['a_user'] : array(); + + // Also include founders + $where_sql = ' WHERE user_type = ' . USER_FOUNDER; + + if (sizeof($admin_ary)) + { + $where_sql .= ' OR ' . $db->sql_in_set('user_id', $admin_ary); + } $sql = 'SELECT user_id, username, user_email, user_lang, user_jabber, user_notify_type - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $admin_ary[0]['a_user']); + FROM ' . USERS_TABLE . ' ' . + $where_sql; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -164,9 +172,7 @@ class ucp_profile $messenger->im($row['user_jabber'], $row['username']); $messenger->assign_vars(array( - 'USERNAME' => html_entity_decode($username), - 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']), - + 'USERNAME' => htmlspecialchars_decode($username), 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user->data['user_id']}&k=$user_actkey") ); @@ -177,9 +183,10 @@ class ucp_profile $messenger->save_queue(); + user_active_flip('deactivate', $user->data['user_id'], INACTIVE_PROFILE); + $sql_ary += array( - 'user_type' => USER_INACTIVE, - 'user_actkey' => $user_actkey + 'user_actkey' => $user_actkey, ); } @@ -192,9 +199,9 @@ class ucp_profile } // Need to update config, forum, topic, posting, messages, etc. - if ($username != $user->data['username'] && $auth->acl_get('u_chgname') && $config['allow_namechange']) + if ($data['username'] != $user->data['username'] && $auth->acl_get('u_chgname') && $config['allow_namechange']) { - user_update_name($user->data['username'], $username); + user_update_name($user->data['username'], $data['username']); } meta_refresh(3, $this->u_action); @@ -207,18 +214,19 @@ class ucp_profile } $user_char_ary = array('.*' => 'USERNAME_CHARS_ANY', '[\w]+' => 'USERNAME_ALPHA_ONLY', '[\w_\+\. \-\[\]]+' => 'USERNAME_ALPHA_SPACERS'); + $pass_char_ary = array('.*' => 'PASS_TYPE_ANY', '[a-zA-Z]' => 'PASS_TYPE_CASE', '[a-zA-Z0-9]' => 'PASS_TYPE_ALPHA', '[a-zA-Z\W]' => 'PASS_TYPE_SYMBOL'); $template->assign_vars(array( 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '', - 'USERNAME' => (isset($username)) ? $username : $user->data['username'], - 'EMAIL' => (isset($email)) ? $email : $user->data['user_email'], - 'PASSWORD_CONFIRM' => (isset($password_confirm)) ? $password_confirm : '', - 'NEW_PASSWORD' => (isset($new_password)) ? $new_password : '', + 'USERNAME' => $data['username'], + 'EMAIL' => $data['email'], + 'PASSWORD_CONFIRM' => $data['password_confirm'], + 'NEW_PASSWORD' => $data['new_password'], 'CUR_PASSWORD' => '', 'L_USERNAME_EXPLAIN' => sprintf($user->lang[$user_char_ary[str_replace('\\\\', '\\', $config['allow_name_chars'])] . '_EXPLAIN'], $config['min_name_chars'], $config['max_name_chars']), - 'L_CHANGE_PASSWORD_EXPLAIN' => sprintf($user->lang['CHANGE_PASSWORD_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), + 'L_CHANGE_PASSWORD_EXPLAIN' => sprintf($user->lang[$pass_char_ary[str_replace('\\\\', '\\', $config['pass_complex'])] . '_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), 'S_FORCE_PASSWORD' => ($config['chg_passforce'] && $user->data['user_passchg'] < time() - $config['chg_passforce']) ? true : false, 'S_CHANGE_USERNAME' => ($config['allow_namechange'] && $auth->acl_get('u_chgname')) ? true : false, @@ -235,29 +243,35 @@ class ucp_profile $cp_data = $cp_error = array(); - if ($submit) + $data = array( + 'icq' => request_var('icq', $user->data['user_icq']), + 'aim' => request_var('aim', $user->data['user_aim']), + 'msn' => request_var('msn', $user->data['user_msnm']), + 'yim' => request_var('yim', $user->data['user_yim']), + 'jabber' => request_var('jabber', $user->data['user_jabber']), + 'website' => request_var('website', $user->data['user_website']), + 'location' => request_var('location', $user->data['user_from'], true), + 'occupation' => request_var('occupation', $user->data['user_occ'], true), + 'interests' => request_var('interests', $user->data['user_interests'], true), + 'bday_day' => 0, + 'bday_month' => 0, + 'bday_year' => 0, + ); + + utf8_normalize_nfc(array(&$data['location'], &$data['occupation'], &$data['interests'])); + + if ($user->data['user_birthday']) { - $var_ary = array( - 'icq' => (string) '', - 'aim' => (string) '', - 'msn' => (string) '', - 'yim' => (string) '', - 'jabber' => (string) '', - 'website' => (string) '', - 'location' => (string) '', - 'occupation' => (string) '', - 'interests' => (string) '', - 'bday_day' => 0, - 'bday_month' => 0, - 'bday_year' => 0, - ); + list($data['bday_day'], $data['bday_month'], $data['bday_year']) = explode('-', $user->data['user_birthday']); + } - foreach ($var_ary as $var => $default) - { - $data[$var] = (in_array($var, array('location', 'occupation', 'interests'))) ? request_var($var, $default, true) : request_var($var, $default); - } + $data['bday_day'] = request_var('bday_day', $data['bday_day']); + $data['bday_month'] = request_var('bday_month', $data['bday_month']); + $data['bday_year'] = request_var('bday_year', $data['bday_year']); - $var_ary = array( + if ($submit) + { + $error = validate_data($data, array( 'icq' => array( array('string', true, 3, 15), array('match', true, '#^[0-9]+$#i')), @@ -276,11 +290,7 @@ class ucp_profile 'bday_day' => array('num', true, 1, 31), 'bday_month' => array('num', true, 1, 12), 'bday_year' => array('num', true, 1901, gmdate('Y', time())), - ); - - $error = validate_data($data, $var_ary); - extract($data); - unset($data); + )); // validate custom profile fields $cp->submit_cp_field('profile', $user->get_iso_lang_id(), $cp_data, $cp_error); @@ -293,16 +303,16 @@ class ucp_profile if (!sizeof($error)) { $sql_ary = array( - 'user_icq' => $icq, - 'user_aim' => $aim, - 'user_msnm' => $msn, - 'user_yim' => $yim, - 'user_jabber' => $jabber, - 'user_website' => $website, - 'user_from' => $location, - 'user_occ' => $occupation, - 'user_interests'=> $interests, - 'user_birthday' => sprintf('%2d-%2d-%4d', $bday_day, $bday_month, $bday_year), + 'user_icq' => $data['icq'], + 'user_aim' => $data['aim'], + 'user_msnm' => $data['msn'], + 'user_yim' => $data['yim'], + 'user_jabber' => $data['jabber'], + 'user_website' => $data['website'], + 'user_from' => $data['location'], + 'user_occ' => $data['occupation'], + 'user_interests'=> $data['interests'], + 'user_birthday' => sprintf('%2d-%2d-%4d', $data['bday_day'], $data['bday_month'], $data['bday_year']), ); $sql = 'UPDATE ' . USERS_TABLE . ' @@ -340,38 +350,26 @@ class ucp_profile $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); } - if (!isset($bday_day)) - { - if ($user->data['user_birthday']) - { - list($bday_day, $bday_month, $bday_year) = explode('-', $user->data['user_birthday']); - } - else - { - $bday_day = $bday_month = $bday_year = 0; - } - } - - $s_birthday_day_options = '<option value="0"' . ((!$bday_day) ? ' selected="selected"' : '') . '>--</option>'; + $s_birthday_day_options = '<option value="0"' . ((!$data['bday_day']) ? ' selected="selected"' : '') . '>--</option>'; for ($i = 1; $i < 32; $i++) { - $selected = ($i == $bday_day) ? ' selected="selected"' : ''; + $selected = ($i == $data['bday_day']) ? ' selected="selected"' : ''; $s_birthday_day_options .= "<option value=\"$i\"$selected>$i</option>"; } - $s_birthday_month_options = '<option value="0"' . ((!$bday_month) ? ' selected="selected"' : '') . '>--</option>'; + $s_birthday_month_options = '<option value="0"' . ((!$data['bday_month']) ? ' selected="selected"' : '') . '>--</option>'; for ($i = 1; $i < 13; $i++) { - $selected = ($i == $bday_month) ? ' selected="selected"' : ''; + $selected = ($i == $data['bday_month']) ? ' selected="selected"' : ''; $s_birthday_month_options .= "<option value=\"$i\"$selected>$i</option>"; } $s_birthday_year_options = ''; $now = getdate(); - $s_birthday_year_options = '<option value="0"' . ((!$bday_year) ? ' selected="selected"' : '') . '>--</option>'; + $s_birthday_year_options = '<option value="0"' . ((!$data['bday_year']) ? ' selected="selected"' : '') . '>--</option>'; for ($i = $now['year'] - 100; $i < $now['year']; $i++) { - $selected = ($i == $bday_year) ? ' selected="selected"' : ''; + $selected = ($i == $data['bday_year']) ? ' selected="selected"' : ''; $s_birthday_year_options .= "<option value=\"$i\"$selected>$i</option>"; } unset($now); @@ -379,15 +377,15 @@ class ucp_profile $template->assign_vars(array( 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '', - 'ICQ' => (isset($icq)) ? $icq : $user->data['user_icq'], - 'YIM' => (isset($yim)) ? $yim : $user->data['user_yim'], - 'AIM' => (isset($aim)) ? $aim : $user->data['user_aim'], - 'MSN' => (isset($msn)) ? $msn : $user->data['user_msnm'], - 'JABBER' => (isset($jabber)) ? $jabber : $user->data['user_jabber'], - 'WEBSITE' => (isset($website)) ? $website : $user->data['user_website'], - 'LOCATION' => (isset($location)) ? $location : $user->data['user_from'], - 'OCCUPATION'=> (isset($occupation)) ? $occupation : $user->data['user_occ'], - 'INTERESTS' => (isset($interests)) ? $interests : $user->data['user_interests'], + 'ICQ' => $data['icq'], + 'YIM' => $data['yim'], + 'AIM' => $data['aim'], + 'MSN' => $data['msn'], + 'JABBER' => $data['jabber'], + 'WEBSITE' => $data['website'], + 'LOCATION' => $data['location'], + 'OCCUPATION'=> $data['occupation'], + 'INTERESTS' => $data['interests'], 'S_BIRTHDAY_DAY_OPTIONS' => $s_birthday_day_options, 'S_BIRTHDAY_MONTH_OPTIONS' => $s_birthday_month_options, @@ -416,6 +414,8 @@ class ucp_profile $enable_urls = request_var('enable_urls', true); $signature = request_var('signature', (string) $user->data['user_sig'], true); + utf8_normalize_nfc(&$signature); + if ($submit || $preview) { include($phpbb_root_path . 'includes/message_parser.'.$phpEx); @@ -425,7 +425,7 @@ class ucp_profile $message_parser = new parse_message($signature); // Allowing Quote BBCode - $message_parser->parse($enable_bbcode, $enable_urls, $enable_smilies, $config['allow_sig_img'], $config['allow_sig_flash'], true, true, 'sig'); + $message_parser->parse($enable_bbcode, ($config['allow_sig_links']) ? $enable_urls : false, $enable_smilies, $config['allow_sig_img'], $config['allow_sig_flash'], true, $config['allow_sig_links'], true, 'sig'); if (sizeof($message_parser->warn_msg)) { @@ -473,17 +473,19 @@ class ucp_profile 'S_SMILIES_CHECKED' => (!$enable_smilies) ? 'checked="checked"' : '', 'S_MAGIC_URL_CHECKED' => (!$enable_urls) ? 'checked="checked"' : '', - 'BBCODE_STATUS' => ($config['allow_sig_bbcode']) ? sprintf($user->lang['BBCODE_IS_ON'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '" onclick="target=\'_phpbbcode\';">', '</a>') : sprintf($user->lang['BBCODE_IS_OFF'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '" onclick="target=\'_phpbbcode\';">', '</a>'), + 'BBCODE_STATUS' => ($config['allow_sig_bbcode']) ? sprintf($user->lang['BBCODE_IS_ON'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>') : sprintf($user->lang['BBCODE_IS_OFF'], '<a href="' . append_sid("{$phpbb_root_path}faq.$phpEx", 'mode=bbcode') . '">', '</a>'), 'SMILIES_STATUS' => ($config['allow_sig_smilies']) ? $user->lang['SMILIES_ARE_ON'] : $user->lang['SMILIES_ARE_OFF'], 'IMG_STATUS' => ($config['allow_sig_img']) ? $user->lang['IMAGES_ARE_ON'] : $user->lang['IMAGES_ARE_OFF'], 'FLASH_STATUS' => ($config['allow_sig_flash']) ? $user->lang['FLASH_IS_ON'] : $user->lang['FLASH_IS_OFF'], + 'URL_STATUS' => ($config['allow_sig_links']) ? $user->lang['URL_IS_ON'] : $user->lang['URL_IS_OFF'], 'L_SIGNATURE_EXPLAIN' => sprintf($user->lang['SIGNATURE_EXPLAIN'], $config['max_sig_chars']), 'S_BBCODE_ALLOWED' => $config['allow_sig_bbcode'], 'S_SMILIES_ALLOWED' => $config['allow_sig_smilies'], 'S_BBCODE_IMG' => ($config['allow_sig_img']) ? true : false, - 'S_BBCODE_FLASH' => ($config['allow_sig_flash']) ? true : false) + 'S_BBCODE_FLASH' => ($config['allow_sig_flash']) ? true : false, + 'S_LINKS_ALLOWED' => ($config['allow_sig_links']) ? true : false) ); // Build custom bbcodes array @@ -504,26 +506,19 @@ class ucp_profile if ($submit) { - $var_ary = array( - 'uploadurl' => (string) '', - 'remotelink' => (string) '', - 'width' => (string) '', - 'height' => (string) '', + $data = array( + 'uploadurl' => request_var('uploadurl', ''), + 'remotelink' => request_var('remotelink', ''), + 'width' => request_var('width', ''), + 'height' => request_var('height', ''), ); - foreach ($var_ary as $var => $default) - { - $data[$var] = request_var($var, $default); - } - - $var_ary = array( + $error = validate_data($data, array( 'uploadurl' => array('string', true, 5, 255), 'remotelink' => array('string', true, 5, 255), 'width' => array('string', true, 1, 3), 'height' => array('string', true, 1, 3), - ); - - $error = validate_data($data, $var_ary); + )); if (!sizeof($error)) { @@ -585,11 +580,7 @@ class ucp_profile // Delete old avatar if present if ($user->data['user_avatar'] && $filename != $user->data['user_avatar'] && $user->data['user_avatar_type'] != AVATAR_GALLERY) { - // Check if the users avatar is actually a group avatar - if (strpos($user->data['user_avatar'], 'g' . $user->data['group_id'] . '_') !== 0 && strpos($user->data['user_avatar'], $user->data['user_id'] . '_') === 0) - { - avatar_delete($user->data['user_avatar']); - } + avatar_delete('user', $user->data); } } @@ -598,9 +589,6 @@ class ucp_profile trigger_error($message); } - extract($data); - unset($data); - // Replace "error" strings with their real, localised form $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); } @@ -644,8 +632,8 @@ class ucp_profile $template->assign_vars(array( 'AVATAR' => $avatar_img, 'AVATAR_SIZE' => $config['avatar_filesize'], - 'WIDTH' => (isset($width)) ? $width : $user->data['user_avatar_width'], - 'HEIGHT' => (isset($height)) ? $height : $user->data['user_avatar_height'], + 'WIDTH' => (isset($data['width'])) ? $data['width'] : $user->data['user_avatar_width'], + 'HEIGHT' => (isset($data['height'])) ? $data['height'] : $user->data['user_avatar_height'], 'S_UPLOAD_AVATAR_FILE' => $can_upload, 'S_UPLOAD_AVATAR_URL' => $can_upload, diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index 01b92125ac..1e8ff69733 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -37,21 +37,35 @@ class ucp_register if ($change_lang) { - $submit = false; - $lang = $change_lang; - $user->lang_name = $lang = $change_lang; - $user->lang_path = $phpbb_root_path . 'language/' . $lang . '/'; - $user->lang = array(); - $user->add_lang(array('common', 'ucp')); + $change_lang = basename($change_lang); + + if (file_exists($phpbb_root_path . 'language/' . $change_lang . '/')) + { + $submit = false; + + $user->lang_name = $lang = $change_lang; + $user->lang_path = $phpbb_root_path . 'language/' . $lang . '/'; + $user->lang = array(); + $user->add_lang(array('common', 'ucp')); + + // Setting back agreed to let the user view the agreement in his/her language + $agreed = (empty($_GET['change_lang'])) ? 0 : $agreed; + } + else + { + $change_lang = ''; + } } $cp = new custom_profile(); - $error = $data = $cp_data = $cp_error = array(); + $error = $cp_data = $cp_error = array(); // if (!$agreed) { + $add_lang = ($change_lang) ? '&change_lang=' . urlencode($change_lang) : ''; + if ($coppa === false && $config['coppa_enable']) { $now = getdate(); @@ -62,11 +76,12 @@ class ucp_register 'L_COPPA_NO' => sprintf($user->lang['UCP_COPPA_BEFORE'], $coppa_birthday), 'L_COPPA_YES' => sprintf($user->lang['UCP_COPPA_ON_AFTER'], $coppa_birthday), - 'U_COPPA_NO' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=0'), - 'U_COPPA_YES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=1'), + 'U_COPPA_NO' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=0' . $add_lang), + 'U_COPPA_YES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&coppa=1' . $add_lang), 'S_SHOW_COPPA' => true, - 'S_REGISTER_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register')) + 'S_HIDDEN_FIELDS' => ($confirm_id) ? '<input type="hidden" name="confirm_id" value="' . $confirm_id . '" />' : '', + 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_lang)) ); } else @@ -76,7 +91,8 @@ class ucp_register 'S_SHOW_COPPA' => false, 'S_REGISTRATION' => true, - 'S_REGISTER_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register')) + 'S_HIDDEN_FIELDS' => ($confirm_id) ? '<input type="hidden" name="confirm_id" value="' . $confirm_id . '" />' : '', + 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_lang)) ); } @@ -84,40 +100,38 @@ class ucp_register return; } - $var_ary = array( - 'username' => (string) '', - 'password_confirm' => (string) '', - 'new_password' => (string) '', - 'cur_password' => (string) '', - 'email' => (string) '', - 'email_confirm' => (string) '', - 'confirm_code' => (string) '', - 'lang' => (string) $config['default_lang'], - 'tz' => (float) $config['board_timezone'], - ); + // Try to manually determine the timezone + $timezone = date('Z') / 3600; + $is_dst = date('I'); + $timezone = ($is_dst) ? $timezone - 1 : $timezone; - // If we change the language inline, we do not want to display errors, but pre-fill already filled out values - if ($change_lang) + if (!isset($user->lang['tz_zones'][(string) $timezone])) { - foreach ($var_ary as $var => $default) - { - $$var = request_var($var, $default, true); - } + $timezone = $config['board_timezone']; } + $data = array( + 'username' => request_var('username', '', true), + 'password_confirm' => request_var('password_confirm', '', true), + 'new_password' => request_var('new_password', '', true), + 'cur_password' => request_var('cur_password', '', true), + 'email' => request_var('email', ''), + 'email_confirm' => request_var('email_confirm', ''), + 'confirm_code' => request_var('confirm_code', ''), + 'lang' => request_var('lang', $user->lang_name), + 'tz' => request_var('tz', (float) $timezone), + ); + // Check and initialize some variables if needed if ($submit) { - foreach ($var_ary as $var => $default) - { - $data[$var] = request_var($var, $default, true); - } - - $var_ary = array( + $error = validate_data($data, array( 'username' => array( array('string', false, $config['min_name_chars'], $config['max_name_chars']), array('username')), - 'new_password' => array('string', false, $config['min_pass_chars'], $config['max_pass_chars']), + 'new_password' => array( + array('string', false, $config['min_pass_chars'], $config['max_pass_chars']), + array('password')), 'password_confirm' => array('string', false, $config['min_pass_chars'], $config['max_pass_chars']), 'email' => array( array('string', false, 6, 60), @@ -126,15 +140,20 @@ class ucp_register 'confirm_code' => array('string', !$config['enable_confirm'], 5, 8), 'tz' => array('num', false, -14, 14), 'lang' => array('match', false, '#^[a-z_\-]{2,}$#i'), - ); - - $error = validate_data($data, $var_ary); - extract($data); - unset($data); + )); // Replace "error" strings with their real, localised form $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + // DNSBL check + if ($config['check_dnsbl']) + { + if (($dnsbl = $user->check_dnsbl()) !== false) + { + $error[] = sprintf($user->lang['IP_BLACKLISTED'], $user->ip, $dnsbl[1]); + } + } + // validate custom profile fields $cp->submit_cp_field('register', $user->get_iso_lang_id(), $cp_data, $error); @@ -160,7 +179,7 @@ class ucp_register if ($row) { - if (strcasecmp($row['code'], $confirm_code) === 0) + if (strcasecmp($row['code'], $data['confirm_code']) === 0) { $sql = 'DELETE FROM ' . CONFIRM_TABLE . " WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' @@ -184,12 +203,12 @@ class ucp_register if (!sizeof($error)) { - if ($new_password != $password_confirm) + if ($data['new_password'] != $data['password_confirm']) { $error[] = $user->lang['NEW_PASSWORD_ERROR']; } - if ($email != $email_confirm) + if ($data['email'] != $data['email_confirm']) { $error[] = $user->lang['NEW_EMAIL_ERROR']; } @@ -200,9 +219,7 @@ class ucp_register $server_url = generate_board_url(); // Which group by default? - $group_reg = ($coppa) ? 'REGISTERED_COPPA' : 'REGISTERED'; - $group_inactive = ($coppa) ? 'INACTIVE_COPPA' : 'INACTIVE'; - $group_name = ($config['require_activation'] == USER_ACTIVATION_NONE || !$config['email_enable']) ? $group_reg : $group_inactive; + $group_name = ($coppa) ? 'REGISTERED_COPPA' : 'REGISTERED'; $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " @@ -227,25 +244,33 @@ class ucp_register $key_len = 54 - (strlen($server_url)); $key_len = ($key_len < 6) ? 6 : $key_len; $user_actkey = substr($user_actkey, 0, $key_len); + $user_type = USER_INACTIVE; + $user_inactive_reason = INACTIVE_REGISTER; + $user_inactive_time = time(); } else { $user_type = USER_NORMAL; $user_actkey = ''; + $user_inactive_reason = 0; + $user_inactive_time = 0; } $user_row = array( - 'username' => $username, - 'user_password' => md5($new_password), - 'user_email' => $email, - 'group_id' => (int) $group_id, - 'user_timezone' => (float) $tz, - 'user_lang' => $lang, - 'user_type' => $user_type, - 'user_actkey' => $user_actkey, - 'user_ip' => $user->ip, - 'user_regdate' => time(), + 'username' => $data['username'], + 'user_password' => md5($data['new_password']), + 'user_email' => $data['email'], + 'group_id' => (int) $group_id, + 'user_timezone' => (float) $data['tz'], + 'user_dst' => $is_dst, + 'user_lang' => $data['lang'], + 'user_type' => $user_type, + 'user_actkey' => $user_actkey, + 'user_ip' => $user->ip, + 'user_regdate' => time(), + 'user_inactive_reason' => $user_inactive_reason, + 'user_inactive_time' => $user_inactive_time, ); // Register user... @@ -284,10 +309,10 @@ class ucp_register $messenger = new messenger(false); - $messenger->template($email_template, $lang); + $messenger->template($email_template, $data['lang']); $messenger->replyto($config['board_contact']); - $messenger->to($email, $username); + $messenger->to($data['email'], $data['username']); $messenger->headers('X-AntiAbuse: Board servername - ' . $config['server_name']); $messenger->headers('X-AntiAbuse: User_id - ' . $user->data['user_id']); @@ -295,12 +320,9 @@ class ucp_register $messenger->headers('X-AntiAbuse: User IP - ' . $user->ip); $messenger->assign_vars(array( - 'SITENAME' => $config['sitename'], - 'WELCOME_MSG' => sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename']), - 'USERNAME' => html_entity_decode($username), - 'PASSWORD' => html_entity_decode($password_confirm), - 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']), - + 'WELCOME_MSG' => htmlspecialchars_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename'])), + 'USERNAME' => htmlspecialchars_decode($data['username']), + 'PASSWORD' => htmlspecialchars_decode($data['new_password']), 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u=$user_id&k=$user_actkey") ); @@ -309,8 +331,7 @@ class ucp_register $messenger->assign_vars(array( 'FAX_INFO' => $config['coppa_fax'], 'MAIL_INFO' => $config['coppa_mail'], - 'EMAIL_ADDRESS' => $email, - 'SITENAME' => $config['sitename']) + 'EMAIL_ADDRESS' => $data['email']) ); } @@ -320,10 +341,19 @@ class ucp_register { // Grab an array of user_id's with a_user permissions ... these users can activate a user $admin_ary = $auth->acl_get_list(false, 'a_user', false); + $admin_ary = (!empty($admin_ary[0]['a_user'])) ? $admin_ary[0]['a_user'] : array(); + + // Also include founders + $where_sql = ' WHERE user_type = ' . USER_FOUNDER; + + if (sizeof($admin_ary)) + { + $where_sql .= ' OR ' . $db->sql_in_set('user_id', $admin_ary); + } $sql = 'SELECT user_id, username, user_email, user_lang, user_jabber, user_notify_type - FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $admin_ary[0]['a_user']); + FROM ' . USERS_TABLE . ' ' . + $where_sql; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -334,9 +364,7 @@ class ucp_register $messenger->im($row['user_jabber'], $row['username']); $messenger->assign_vars(array( - 'USERNAME' => html_entity_decode($username), - 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']), - + 'USERNAME' => htmlspecialchars_decode($data['username']), 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u=$user_id&k=$user_actkey") ); @@ -345,7 +373,6 @@ class ucp_register $db->sql_freeresult($result); } } - unset($data); $message = $message . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . append_sid("{$phpbb_root_path}index.$phpEx") . '">', '</a>'); trigger_error($message); @@ -379,10 +406,13 @@ class ucp_register } while ($row = $db->sql_fetchrow($result)); - $sql = 'DELETE FROM ' . CONFIRM_TABLE . ' - WHERE ' . $db->sql_in_set('session_id', $sql_in, true) . ' - AND confirm_type = ' . CONFIRM_REG; - $db->sql_query($sql); + if (sizeof($sql_in)) + { + $sql = 'DELETE FROM ' . CONFIRM_TABLE . ' + WHERE ' . $db->sql_in_set('session_id', $sql_in, true) . ' + AND confirm_type = ' . CONFIRM_REG; + $db->sql_query($sql); + } } $db->sql_freeresult($result); @@ -433,27 +463,25 @@ class ucp_register } $user_char_ary = array('.*' => 'USERNAME_CHARS_ANY', '[\w]+' => 'USERNAME_ALPHA_ONLY', '[\w_\+\. \-\[\]]+' => 'USERNAME_ALPHA_SPACERS'); - - $lang = (isset($lang)) ? $lang : $config['default_lang']; - $tz = (isset($tz)) ? $tz : $config['board_timezone']; + $pass_char_ary = array('.*' => 'PASS_TYPE_ANY', '[a-zA-Z]' => 'PASS_TYPE_CASE', '[a-zA-Z0-9]' => 'PASS_TYPE_ALPHA', '[a-zA-Z\W]' => 'PASS_TYPE_SYMBOL'); // $template->assign_vars(array( 'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '', - 'USERNAME' => (isset($username)) ? $username : '', - 'PASSWORD' => (isset($new_password)) ? $new_password : '', - 'PASSWORD_CONFIRM' => (isset($password_confirm)) ? $password_confirm : '', - 'EMAIL' => (isset($email)) ? $email : '', - 'EMAIL_CONFIRM' => (isset($email_confirm)) ? $email_confirm : '', + 'USERNAME' => $data['username'], + 'PASSWORD' => $data['new_password'], + 'PASSWORD_CONFIRM' => $data['password_confirm'], + 'EMAIL' => $data['email'], + 'EMAIL_CONFIRM' => $data['email_confirm'], 'CONFIRM_IMG' => $confirm_image, - 'L_CONFIRM_EXPLAIN' => sprintf($user->lang['CONFIRM_EXPLAIN'], '<a href="mailto:' . htmlentities($config['board_contact']) . '">', '</a>'), + 'L_CONFIRM_EXPLAIN' => sprintf($user->lang['CONFIRM_EXPLAIN'], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'), 'L_REG_COND' => $l_reg_cond, 'L_USERNAME_EXPLAIN' => sprintf($user->lang[$user_char_ary[str_replace('\\\\', '\\', $config['allow_name_chars'])] . '_EXPLAIN'], $config['min_name_chars'], $config['max_name_chars']), - 'L_NEW_PASSWORD_EXPLAIN' => sprintf($user->lang['NEW_PASSWORD_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), + 'L_NEW_PASSWORD_EXPLAIN' => sprintf($user->lang[$pass_char_ary[str_replace('\\\\', '\\', $config['pass_complex'])] . '_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), - 'S_LANG_OPTIONS' => language_select($lang), - 'S_TZ_OPTIONS' => tz_select($tz), + 'S_LANG_OPTIONS' => language_select($data['lang']), + 'S_TZ_OPTIONS' => tz_select($data['tz']), 'S_CONFIRM_CODE' => ($config['enable_confirm']) ? true : false, 'S_COPPA' => $coppa, 'S_HIDDEN_FIELDS' => $s_hidden_fields, diff --git a/phpBB/includes/ucp/ucp_remind.php b/phpBB/includes/ucp/ucp_remind.php index 11edb54b95..7ce82093ca 100644 --- a/phpBB/includes/ucp/ucp_remind.php +++ b/phpBB/includes/ucp/ucp_remind.php @@ -22,7 +22,7 @@ class ucp_remind global $config, $phpbb_root_path, $phpEx; global $db, $user, $auth, $template; - $username = request_var('username', ''); + $username = request_var('username', '', true); $email = request_var('email', ''); $submit = (isset($_POST['submit'])) ? true : false; @@ -31,7 +31,7 @@ class ucp_remind $sql = 'SELECT user_id, username, user_email, user_jabber, user_notify_type, user_type, user_lang FROM ' . USERS_TABLE . " WHERE user_email = '" . $db->sql_escape($email) . "' - AND LOWER(username) = '" . $db->sql_escape(strtolower($username)) . "'"; + AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $result = $db->sql_query($sql); $user_row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -69,11 +69,8 @@ class ucp_remind $messenger->im($user_row['user_jabber'], $user_row['username']); $messenger->assign_vars(array( - 'SITENAME' => $config['sitename'], - 'USERNAME' => html_entity_decode($user_row['username']), - 'PASSWORD' => html_entity_decode($user_password), - 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']), - + 'USERNAME' => htmlspecialchars_decode($user_row['username']), + 'PASSWORD' => htmlspecialchars_decode($user_password), 'U_ACTIVATE' => "$server_url/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k=$user_actkey") ); diff --git a/phpBB/includes/ucp/ucp_resend.php b/phpBB/includes/ucp/ucp_resend.php index 84ce3fe9b7..62e796bc4b 100644 --- a/phpBB/includes/ucp/ucp_resend.php +++ b/phpBB/includes/ucp/ucp_resend.php @@ -22,7 +22,7 @@ class ucp_resend global $config, $phpbb_root_path, $phpEx; global $db, $user, $auth, $template; - $username = request_var('username', ''); + $username = request_var('username', '', true); $email = request_var('email', ''); $submit = (isset($_POST['submit'])) ? true : false; @@ -31,7 +31,7 @@ class ucp_resend $sql = 'SELECT user_id, group_id, username, user_email, user_type, user_lang, user_actkey FROM ' . USERS_TABLE . " WHERE user_email = '" . $db->sql_escape($email) . "' - AND LOWER(username) = '" . $db->sql_escape(strtolower($username)) . "'"; + AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $result = $db->sql_query($sql); $user_row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -46,7 +46,7 @@ class ucp_resend trigger_error('ACCOUNT_ALREADY_ACTIVATED'); } - // Determine coppa status on group (INACTIVE(_COPPA)) + // Determine coppa status on group (REGISTERED(_COPPA)) $sql = 'SELECT group_name, group_type FROM ' . GROUPS_TABLE . ' WHERE group_id = ' . $user_row['group_id']; @@ -59,7 +59,7 @@ class ucp_resend trigger_error('NO_GROUP'); } - $coppa = ($row['group_name'] == 'INACTIVE_COPPA' && $row['group_type'] == GROUP_SPECIAL) ? true : false; + $coppa = ($row['group_name'] == 'REGISTERED_COPPA' && $row['group_type'] == GROUP_SPECIAL) ? true : false; include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); $messenger = new messenger(false); @@ -77,11 +77,8 @@ class ucp_resend $messenger->headers('X-AntiAbuse: User IP - ' . $user->ip); $messenger->assign_vars(array( - 'SITENAME' => $config['sitename'], - 'WELCOME_MSG' => sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename']), - 'USERNAME' => html_entity_decode($user_row['username']), - 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']), - + 'WELCOME_MSG' => htmlspecialchars_decode(sprintf($user->lang['WELCOME_SUBJECT'], $config['sitename'])), + 'USERNAME' => htmlspecialchars_decode($user_row['username']), 'U_ACTIVATE' => generate_board_url() . "/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k={$user_row['user_actkey']}") ); @@ -90,8 +87,7 @@ class ucp_resend $messenger->assign_vars(array( 'FAX_INFO' => $config['coppa_fax'], 'MAIL_INFO' => $config['coppa_mail'], - 'EMAIL_ADDRESS' => $user_row['user_email'], - 'SITENAME' => $config['sitename']) + 'EMAIL_ADDRESS' => $user_row['user_email']) ); } @@ -116,9 +112,7 @@ class ucp_resend $messenger->im($row['user_jabber'], $row['username']); $messenger->assign_vars(array( - 'USERNAME' => html_entity_decode($user_row['username']), - 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']), - + 'USERNAME' => htmlspecialchars_decode($user_row['username']), 'U_ACTIVATE' => generate_board_url() . "/ucp.$phpEx?mode=activate&u={$user_row['user_id']}&k={$user_row['user_actkey']}") ); diff --git a/phpBB/includes/ucp/ucp_zebra.php b/phpBB/includes/ucp/ucp_zebra.php index 2cf6edcac4..2548037b10 100644 --- a/phpBB/includes/ucp/ucp_zebra.php +++ b/phpBB/includes/ucp/ucp_zebra.php @@ -20,7 +20,7 @@ class ucp_zebra { global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx; - $submit = (isset($_POST['submit']) || isset($_GET['add'])) ? true : false; + $submit = (isset($_POST['submit']) || isset($_GET['add']) || isset($_GET['remove'])) ? true : false; $s_hidden_fields = ''; $l_mode = strtoupper($mode); @@ -32,17 +32,17 @@ class ucp_zebra $var_ary = array( 'usernames' => array(0), - 'add' => '', + 'add' => '', ); foreach ($var_ary as $var => $default) { - $data[$var] = request_var($var, $default); + $data[$var] = request_var($var, $default, true); } if ($data['add']) { - $data['add'] = array_map('trim', array_map('strtolower', explode("\n", $data['add']))); + $data['add'] = array_map('trim', array_map('utf8_clean_string', explode("\n", $data['add']))); // Do these name/s exist on a list already? If so, ignore ... we could be // 'nice' and automatically handle names added to one list present on @@ -59,11 +59,11 @@ class ucp_zebra { if ($row['friend']) { - $friends[] = strtolower($row['username']); + $friends[] = utf8_clean_string($row['username']); } else { - $foes[] = strtolower($row['username']); + $foes[] = utf8_clean_string($row['username']); } } $db->sql_freeresult($result); @@ -88,7 +88,7 @@ class ucp_zebra // remove the user himself from the username array $n = sizeof($data['add']); - $data['add'] = array_diff($data['add'], array(strtolower($user->data['username']))); + $data['add'] = array_diff($data['add'], array(utf8_clean_string($user->data['username']))); if (sizeof($data['add']) < $n) { @@ -101,7 +101,7 @@ class ucp_zebra { $sql = 'SELECT user_id, user_type FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('LOWER(username)', $data['add']) . ' + WHERE ' . $db->sql_in_set('username_clean', $data['add']) . ' AND user_type <> ' . USER_INACTIVE; $result = $db->sql_query($sql); @@ -159,24 +159,7 @@ class ucp_zebra ); } - if (sizeof($sql_ary)) - { - switch (SQL_LAYER) - { - case 'mysql': - case 'mysql4': - case 'mysqli': - $db->sql_query('INSERT INTO ' . ZEBRA_TABLE . ' ' . $db->sql_build_array('MULTI_INSERT', $sql_ary)); - break; - - default: - foreach ($sql_ary as $ary) - { - $db->sql_query('INSERT INTO ' . ZEBRA_TABLE . ' ' . $db->sql_build_array('INSERT', $ary)); - } - break; - } - } + $db->sql_multi_insert(ZEBRA_TABLE, $sql_ary); $updated = true; } @@ -197,6 +180,8 @@ class ucp_zebra WHERE user_id = ' . $user->data['user_id'] . ' AND ' . $db->sql_in_set('zebra_id', $data['usernames']); $db->sql_query($sql); + + $updated = true; } if ($updated) diff --git a/phpBB/includes/utf/data/case_fold_c.php b/phpBB/includes/utf/data/case_fold_c.php new file mode 100644 index 0000000000..00de1ba349 --- /dev/null +++ b/phpBB/includes/utf/data/case_fold_c.php @@ -0,0 +1 @@ +<?php return array('A'=>'a','B'=>'b','C'=>'c','D'=>'d','E'=>'e','F'=>'f','G'=>'g','H'=>'h','I'=>'i','J'=>'j','K'=>'k','L'=>'l','M'=>'m','N'=>'n','O'=>'o','P'=>'p','Q'=>'q','R'=>'r','S'=>'s','T'=>'t','U'=>'u','V'=>'v','W'=>'w','X'=>'x','Y'=>'y','Z'=>'z','µ'=>'μ','À'=>'à','Á'=>'á','Â'=>'â','Ã'=>'ã','Ä'=>'ä','Å'=>'å','Æ'=>'æ','Ç'=>'ç','È'=>'è','É'=>'é','Ê'=>'ê','Ë'=>'ë','Ì'=>'ì','Í'=>'í','Î'=>'î','Ï'=>'ï','Ð'=>'ð','Ñ'=>'ñ','Ò'=>'ò','Ó'=>'ó','Ô'=>'ô','Õ'=>'õ','Ö'=>'ö','Ø'=>'ø','Ù'=>'ù','Ú'=>'ú','Û'=>'û','Ü'=>'ü','Ý'=>'ý','Þ'=>'þ','Ā'=>'ā','Ă'=>'ă','Ą'=>'ą','Ć'=>'ć','Ĉ'=>'ĉ','Ċ'=>'ċ','Č'=>'č','Ď'=>'ď','Đ'=>'đ','Ē'=>'ē','Ĕ'=>'ĕ','Ė'=>'ė','Ę'=>'ę','Ě'=>'ě','Ĝ'=>'ĝ','Ğ'=>'ğ','Ġ'=>'ġ','Ģ'=>'ģ','Ĥ'=>'ĥ','Ħ'=>'ħ','Ĩ'=>'ĩ','Ī'=>'ī','Ĭ'=>'ĭ','Į'=>'į','IJ'=>'ij','Ĵ'=>'ĵ','Ķ'=>'ķ','Ĺ'=>'ĺ','Ļ'=>'ļ','Ľ'=>'ľ','Ŀ'=>'ŀ','Ł'=>'ł','Ń'=>'ń','Ņ'=>'ņ','Ň'=>'ň','Ŋ'=>'ŋ','Ō'=>'ō','Ŏ'=>'ŏ','Ő'=>'ő','Œ'=>'œ','Ŕ'=>'ŕ','Ŗ'=>'ŗ','Ř'=>'ř','Ś'=>'ś','Ŝ'=>'ŝ','Ş'=>'ş','Š'=>'š','Ţ'=>'ţ','Ť'=>'ť','Ŧ'=>'ŧ','Ũ'=>'ũ','Ū'=>'ū','Ŭ'=>'ŭ','Ů'=>'ů','Ű'=>'ű','Ų'=>'ų','Ŵ'=>'ŵ','Ŷ'=>'ŷ','Ÿ'=>'ÿ','Ź'=>'ź','Ż'=>'ż','Ž'=>'ž','ſ'=>'s','Ɓ'=>'ɓ','Ƃ'=>'ƃ','Ƅ'=>'ƅ','Ɔ'=>'ɔ','Ƈ'=>'ƈ','Ɖ'=>'ɖ','Ɗ'=>'ɗ','Ƌ'=>'ƌ','Ǝ'=>'ǝ','Ə'=>'ə','Ɛ'=>'ɛ','Ƒ'=>'ƒ','Ɠ'=>'ɠ','Ɣ'=>'ɣ','Ɩ'=>'ɩ','Ɨ'=>'ɨ','Ƙ'=>'ƙ','Ɯ'=>'ɯ','Ɲ'=>'ɲ','Ɵ'=>'ɵ','Ơ'=>'ơ','Ƣ'=>'ƣ','Ƥ'=>'ƥ','Ʀ'=>'ʀ','Ƨ'=>'ƨ','Ʃ'=>'ʃ','Ƭ'=>'ƭ','Ʈ'=>'ʈ','Ư'=>'ư','Ʊ'=>'ʊ','Ʋ'=>'ʋ','Ƴ'=>'ƴ','Ƶ'=>'ƶ','Ʒ'=>'ʒ','Ƹ'=>'ƹ','Ƽ'=>'ƽ','DŽ'=>'dž','Dž'=>'dž','LJ'=>'lj','Lj'=>'lj','NJ'=>'nj','Nj'=>'nj','Ǎ'=>'ǎ','Ǐ'=>'ǐ','Ǒ'=>'ǒ','Ǔ'=>'ǔ','Ǖ'=>'ǖ','Ǘ'=>'ǘ','Ǚ'=>'ǚ','Ǜ'=>'ǜ','Ǟ'=>'ǟ','Ǡ'=>'ǡ','Ǣ'=>'ǣ','Ǥ'=>'ǥ','Ǧ'=>'ǧ','Ǩ'=>'ǩ','Ǫ'=>'ǫ','Ǭ'=>'ǭ','Ǯ'=>'ǯ','DZ'=>'dz','Dz'=>'dz','Ǵ'=>'ǵ','Ƕ'=>'ƕ','Ƿ'=>'ƿ','Ǹ'=>'ǹ','Ǻ'=>'ǻ','Ǽ'=>'ǽ','Ǿ'=>'ǿ','Ȁ'=>'ȁ','Ȃ'=>'ȃ','Ȅ'=>'ȅ','Ȇ'=>'ȇ','Ȉ'=>'ȉ','Ȋ'=>'ȋ','Ȍ'=>'ȍ','Ȏ'=>'ȏ','Ȑ'=>'ȑ','Ȓ'=>'ȓ','Ȕ'=>'ȕ','Ȗ'=>'ȗ','Ș'=>'ș','Ț'=>'ț','Ȝ'=>'ȝ','Ȟ'=>'ȟ','Ƞ'=>'ƞ','Ȣ'=>'ȣ','Ȥ'=>'ȥ','Ȧ'=>'ȧ','Ȩ'=>'ȩ','Ȫ'=>'ȫ','Ȭ'=>'ȭ','Ȯ'=>'ȯ','Ȱ'=>'ȱ','Ȳ'=>'ȳ','Ⱥ'=>'ⱥ','Ȼ'=>'ȼ','Ƚ'=>'ƚ','Ⱦ'=>'ⱦ','Ɂ'=>'ɂ','Ƀ'=>'ƀ','Ʉ'=>'ʉ','Ʌ'=>'ʌ','Ɇ'=>'ɇ','Ɉ'=>'ɉ','Ɋ'=>'ɋ','Ɍ'=>'ɍ','Ɏ'=>'ɏ','ͅ'=>'ι','Ά'=>'ά','Έ'=>'έ','Ή'=>'ή','Ί'=>'ί','Ό'=>'ό','Ύ'=>'ύ','Ώ'=>'ώ','Α'=>'α','Β'=>'β','Γ'=>'γ','Δ'=>'δ','Ε'=>'ε','Ζ'=>'ζ','Η'=>'η','Θ'=>'θ','Ι'=>'ι','Κ'=>'κ','Λ'=>'λ','Μ'=>'μ','Ν'=>'ν','Ξ'=>'ξ','Ο'=>'ο','Π'=>'π','Ρ'=>'ρ','Σ'=>'σ','Τ'=>'τ','Υ'=>'υ','Φ'=>'φ','Χ'=>'χ','Ψ'=>'ψ','Ω'=>'ω','Ϊ'=>'ϊ','Ϋ'=>'ϋ','ς'=>'σ','ϐ'=>'β','ϑ'=>'θ','ϕ'=>'φ','ϖ'=>'π','Ϙ'=>'ϙ','Ϛ'=>'ϛ','Ϝ'=>'ϝ','Ϟ'=>'ϟ','Ϡ'=>'ϡ','Ϣ'=>'ϣ','Ϥ'=>'ϥ','Ϧ'=>'ϧ','Ϩ'=>'ϩ','Ϫ'=>'ϫ','Ϭ'=>'ϭ','Ϯ'=>'ϯ','ϰ'=>'κ','ϱ'=>'ρ','ϴ'=>'θ','ϵ'=>'ε','Ϸ'=>'ϸ','Ϲ'=>'ϲ','Ϻ'=>'ϻ','Ͻ'=>'ͻ','Ͼ'=>'ͼ','Ͽ'=>'ͽ','Ѐ'=>'ѐ','Ё'=>'ё','Ђ'=>'ђ','Ѓ'=>'ѓ','Є'=>'є','Ѕ'=>'ѕ','І'=>'і','Ї'=>'ї','Ј'=>'ј','Љ'=>'љ','Њ'=>'њ','Ћ'=>'ћ','Ќ'=>'ќ','Ѝ'=>'ѝ','Ў'=>'ў','Џ'=>'џ','А'=>'а','Б'=>'б','В'=>'в','Г'=>'г','Д'=>'д','Е'=>'е','Ж'=>'ж','З'=>'з','И'=>'и','Й'=>'й','К'=>'к','Л'=>'л','М'=>'м','Н'=>'н','О'=>'о','П'=>'п','Р'=>'р','С'=>'с','Т'=>'т','У'=>'у','Ф'=>'ф','Х'=>'х','Ц'=>'ц','Ч'=>'ч','Ш'=>'ш','Щ'=>'щ','Ъ'=>'ъ','Ы'=>'ы','Ь'=>'ь','Э'=>'э','Ю'=>'ю','Я'=>'я','Ѡ'=>'ѡ','Ѣ'=>'ѣ','Ѥ'=>'ѥ','Ѧ'=>'ѧ','Ѩ'=>'ѩ','Ѫ'=>'ѫ','Ѭ'=>'ѭ','Ѯ'=>'ѯ','Ѱ'=>'ѱ','Ѳ'=>'ѳ','Ѵ'=>'ѵ','Ѷ'=>'ѷ','Ѹ'=>'ѹ','Ѻ'=>'ѻ','Ѽ'=>'ѽ','Ѿ'=>'ѿ','Ҁ'=>'ҁ','Ҋ'=>'ҋ','Ҍ'=>'ҍ','Ҏ'=>'ҏ','Ґ'=>'ґ','Ғ'=>'ғ','Ҕ'=>'ҕ','Җ'=>'җ','Ҙ'=>'ҙ','Қ'=>'қ','Ҝ'=>'ҝ','Ҟ'=>'ҟ','Ҡ'=>'ҡ','Ң'=>'ң','Ҥ'=>'ҥ','Ҧ'=>'ҧ','Ҩ'=>'ҩ','Ҫ'=>'ҫ','Ҭ'=>'ҭ','Ү'=>'ү','Ұ'=>'ұ','Ҳ'=>'ҳ','Ҵ'=>'ҵ','Ҷ'=>'ҷ','Ҹ'=>'ҹ','Һ'=>'һ','Ҽ'=>'ҽ','Ҿ'=>'ҿ','Ӏ'=>'ӏ','Ӂ'=>'ӂ','Ӄ'=>'ӄ','Ӆ'=>'ӆ','Ӈ'=>'ӈ','Ӊ'=>'ӊ','Ӌ'=>'ӌ','Ӎ'=>'ӎ','Ӑ'=>'ӑ','Ӓ'=>'ӓ','Ӕ'=>'ӕ','Ӗ'=>'ӗ','Ә'=>'ә','Ӛ'=>'ӛ','Ӝ'=>'ӝ','Ӟ'=>'ӟ','Ӡ'=>'ӡ','Ӣ'=>'ӣ','Ӥ'=>'ӥ','Ӧ'=>'ӧ','Ө'=>'ө','Ӫ'=>'ӫ','Ӭ'=>'ӭ','Ӯ'=>'ӯ','Ӱ'=>'ӱ','Ӳ'=>'ӳ','Ӵ'=>'ӵ','Ӷ'=>'ӷ','Ӹ'=>'ӹ','Ӻ'=>'ӻ','Ӽ'=>'ӽ','Ӿ'=>'ӿ','Ԁ'=>'ԁ','Ԃ'=>'ԃ','Ԅ'=>'ԅ','Ԇ'=>'ԇ','Ԉ'=>'ԉ','Ԋ'=>'ԋ','Ԍ'=>'ԍ','Ԏ'=>'ԏ','Ԑ'=>'ԑ','Ԓ'=>'ԓ','Ա'=>'ա','Բ'=>'բ','Գ'=>'գ','Դ'=>'դ','Ե'=>'ե','Զ'=>'զ','Է'=>'է','Ը'=>'ը','Թ'=>'թ','Ժ'=>'ժ','Ի'=>'ի','Լ'=>'լ','Խ'=>'խ','Ծ'=>'ծ','Կ'=>'կ','Հ'=>'հ','Ձ'=>'ձ','Ղ'=>'ղ','Ճ'=>'ճ','Մ'=>'մ','Յ'=>'յ','Ն'=>'ն','Շ'=>'շ','Ո'=>'ո','Չ'=>'չ','Պ'=>'պ','Ջ'=>'ջ','Ռ'=>'ռ','Ս'=>'ս','Վ'=>'վ','Տ'=>'տ','Ր'=>'ր','Ց'=>'ց','Ւ'=>'ւ','Փ'=>'փ','Ք'=>'ք','Օ'=>'օ','Ֆ'=>'ֆ','Ⴀ'=>'ⴀ','Ⴁ'=>'ⴁ','Ⴂ'=>'ⴂ','Ⴃ'=>'ⴃ','Ⴄ'=>'ⴄ','Ⴅ'=>'ⴅ','Ⴆ'=>'ⴆ','Ⴇ'=>'ⴇ','Ⴈ'=>'ⴈ','Ⴉ'=>'ⴉ','Ⴊ'=>'ⴊ','Ⴋ'=>'ⴋ','Ⴌ'=>'ⴌ','Ⴍ'=>'ⴍ','Ⴎ'=>'ⴎ','Ⴏ'=>'ⴏ','Ⴐ'=>'ⴐ','Ⴑ'=>'ⴑ','Ⴒ'=>'ⴒ','Ⴓ'=>'ⴓ','Ⴔ'=>'ⴔ','Ⴕ'=>'ⴕ','Ⴖ'=>'ⴖ','Ⴗ'=>'ⴗ','Ⴘ'=>'ⴘ','Ⴙ'=>'ⴙ','Ⴚ'=>'ⴚ','Ⴛ'=>'ⴛ','Ⴜ'=>'ⴜ','Ⴝ'=>'ⴝ','Ⴞ'=>'ⴞ','Ⴟ'=>'ⴟ','Ⴠ'=>'ⴠ','Ⴡ'=>'ⴡ','Ⴢ'=>'ⴢ','Ⴣ'=>'ⴣ','Ⴤ'=>'ⴤ','Ⴥ'=>'ⴥ','Ḁ'=>'ḁ','Ḃ'=>'ḃ','Ḅ'=>'ḅ','Ḇ'=>'ḇ','Ḉ'=>'ḉ','Ḋ'=>'ḋ','Ḍ'=>'ḍ','Ḏ'=>'ḏ','Ḑ'=>'ḑ','Ḓ'=>'ḓ','Ḕ'=>'ḕ','Ḗ'=>'ḗ','Ḙ'=>'ḙ','Ḛ'=>'ḛ','Ḝ'=>'ḝ','Ḟ'=>'ḟ','Ḡ'=>'ḡ','Ḣ'=>'ḣ','Ḥ'=>'ḥ','Ḧ'=>'ḧ','Ḩ'=>'ḩ','Ḫ'=>'ḫ','Ḭ'=>'ḭ','Ḯ'=>'ḯ','Ḱ'=>'ḱ','Ḳ'=>'ḳ','Ḵ'=>'ḵ','Ḷ'=>'ḷ','Ḹ'=>'ḹ','Ḻ'=>'ḻ','Ḽ'=>'ḽ','Ḿ'=>'ḿ','Ṁ'=>'ṁ','Ṃ'=>'ṃ','Ṅ'=>'ṅ','Ṇ'=>'ṇ','Ṉ'=>'ṉ','Ṋ'=>'ṋ','Ṍ'=>'ṍ','Ṏ'=>'ṏ','Ṑ'=>'ṑ','Ṓ'=>'ṓ','Ṕ'=>'ṕ','Ṗ'=>'ṗ','Ṙ'=>'ṙ','Ṛ'=>'ṛ','Ṝ'=>'ṝ','Ṟ'=>'ṟ','Ṡ'=>'ṡ','Ṣ'=>'ṣ','Ṥ'=>'ṥ','Ṧ'=>'ṧ','Ṩ'=>'ṩ','Ṫ'=>'ṫ','Ṭ'=>'ṭ','Ṯ'=>'ṯ','Ṱ'=>'ṱ','Ṳ'=>'ṳ','Ṵ'=>'ṵ','Ṷ'=>'ṷ','Ṹ'=>'ṹ','Ṻ'=>'ṻ','Ṽ'=>'ṽ','Ṿ'=>'ṿ','Ẁ'=>'ẁ','Ẃ'=>'ẃ','Ẅ'=>'ẅ','Ẇ'=>'ẇ','Ẉ'=>'ẉ','Ẋ'=>'ẋ','Ẍ'=>'ẍ','Ẏ'=>'ẏ','Ẑ'=>'ẑ','Ẓ'=>'ẓ','Ẕ'=>'ẕ','ẛ'=>'ṡ','Ạ'=>'ạ','Ả'=>'ả','Ấ'=>'ấ','Ầ'=>'ầ','Ẩ'=>'ẩ','Ẫ'=>'ẫ','Ậ'=>'ậ','Ắ'=>'ắ','Ằ'=>'ằ','Ẳ'=>'ẳ','Ẵ'=>'ẵ','Ặ'=>'ặ','Ẹ'=>'ẹ','Ẻ'=>'ẻ','Ẽ'=>'ẽ','Ế'=>'ế','Ề'=>'ề','Ể'=>'ể','Ễ'=>'ễ','Ệ'=>'ệ','Ỉ'=>'ỉ','Ị'=>'ị','Ọ'=>'ọ','Ỏ'=>'ỏ','Ố'=>'ố','Ồ'=>'ồ','Ổ'=>'ổ','Ỗ'=>'ỗ','Ộ'=>'ộ','Ớ'=>'ớ','Ờ'=>'ờ','Ở'=>'ở','Ỡ'=>'ỡ','Ợ'=>'ợ','Ụ'=>'ụ','Ủ'=>'ủ','Ứ'=>'ứ','Ừ'=>'ừ','Ử'=>'ử','Ữ'=>'ữ','Ự'=>'ự','Ỳ'=>'ỳ','Ỵ'=>'ỵ','Ỷ'=>'ỷ','Ỹ'=>'ỹ','Ἀ'=>'ἀ','Ἁ'=>'ἁ','Ἂ'=>'ἂ','Ἃ'=>'ἃ','Ἄ'=>'ἄ','Ἅ'=>'ἅ','Ἆ'=>'ἆ','Ἇ'=>'ἇ','Ἐ'=>'ἐ','Ἑ'=>'ἑ','Ἒ'=>'ἒ','Ἓ'=>'ἓ','Ἔ'=>'ἔ','Ἕ'=>'ἕ','Ἠ'=>'ἠ','Ἡ'=>'ἡ','Ἢ'=>'ἢ','Ἣ'=>'ἣ','Ἤ'=>'ἤ','Ἥ'=>'ἥ','Ἦ'=>'ἦ','Ἧ'=>'ἧ','Ἰ'=>'ἰ','Ἱ'=>'ἱ','Ἲ'=>'ἲ','Ἳ'=>'ἳ','Ἴ'=>'ἴ','Ἵ'=>'ἵ','Ἶ'=>'ἶ','Ἷ'=>'ἷ','Ὀ'=>'ὀ','Ὁ'=>'ὁ','Ὂ'=>'ὂ','Ὃ'=>'ὃ','Ὄ'=>'ὄ','Ὅ'=>'ὅ','Ὑ'=>'ὑ','Ὓ'=>'ὓ','Ὕ'=>'ὕ','Ὗ'=>'ὗ','Ὠ'=>'ὠ','Ὡ'=>'ὡ','Ὢ'=>'ὢ','Ὣ'=>'ὣ','Ὤ'=>'ὤ','Ὥ'=>'ὥ','Ὦ'=>'ὦ','Ὧ'=>'ὧ','Ᾰ'=>'ᾰ','Ᾱ'=>'ᾱ','Ὰ'=>'ὰ','Ά'=>'ά','ι'=>'ι','Ὲ'=>'ὲ','Έ'=>'έ','Ὴ'=>'ὴ','Ή'=>'ή','Ῐ'=>'ῐ','Ῑ'=>'ῑ','Ὶ'=>'ὶ','Ί'=>'ί','Ῠ'=>'ῠ','Ῡ'=>'ῡ','Ὺ'=>'ὺ','Ύ'=>'ύ','Ῥ'=>'ῥ','Ὸ'=>'ὸ','Ό'=>'ό','Ὼ'=>'ὼ','Ώ'=>'ώ','Ω'=>'ω','K'=>'k','Å'=>'å','Ⅎ'=>'ⅎ','Ⅰ'=>'ⅰ','Ⅱ'=>'ⅱ','Ⅲ'=>'ⅲ','Ⅳ'=>'ⅳ','Ⅴ'=>'ⅴ','Ⅵ'=>'ⅵ','Ⅶ'=>'ⅶ','Ⅷ'=>'ⅷ','Ⅸ'=>'ⅸ','Ⅹ'=>'ⅹ','Ⅺ'=>'ⅺ','Ⅻ'=>'ⅻ','Ⅼ'=>'ⅼ','Ⅽ'=>'ⅽ','Ⅾ'=>'ⅾ','Ⅿ'=>'ⅿ','Ↄ'=>'ↄ','Ⓐ'=>'ⓐ','Ⓑ'=>'ⓑ','Ⓒ'=>'ⓒ','Ⓓ'=>'ⓓ','Ⓔ'=>'ⓔ','Ⓕ'=>'ⓕ','Ⓖ'=>'ⓖ','Ⓗ'=>'ⓗ','Ⓘ'=>'ⓘ','Ⓙ'=>'ⓙ','Ⓚ'=>'ⓚ','Ⓛ'=>'ⓛ','Ⓜ'=>'ⓜ','Ⓝ'=>'ⓝ','Ⓞ'=>'ⓞ','Ⓟ'=>'ⓟ','Ⓠ'=>'ⓠ','Ⓡ'=>'ⓡ','Ⓢ'=>'ⓢ','Ⓣ'=>'ⓣ','Ⓤ'=>'ⓤ','Ⓥ'=>'ⓥ','Ⓦ'=>'ⓦ','Ⓧ'=>'ⓧ','Ⓨ'=>'ⓨ','Ⓩ'=>'ⓩ','Ⰰ'=>'ⰰ','Ⰱ'=>'ⰱ','Ⰲ'=>'ⰲ','Ⰳ'=>'ⰳ','Ⰴ'=>'ⰴ','Ⰵ'=>'ⰵ','Ⰶ'=>'ⰶ','Ⰷ'=>'ⰷ','Ⰸ'=>'ⰸ','Ⰹ'=>'ⰹ','Ⰺ'=>'ⰺ','Ⰻ'=>'ⰻ','Ⰼ'=>'ⰼ','Ⰽ'=>'ⰽ','Ⰾ'=>'ⰾ','Ⰿ'=>'ⰿ','Ⱀ'=>'ⱀ','Ⱁ'=>'ⱁ','Ⱂ'=>'ⱂ','Ⱃ'=>'ⱃ','Ⱄ'=>'ⱄ','Ⱅ'=>'ⱅ','Ⱆ'=>'ⱆ','Ⱇ'=>'ⱇ','Ⱈ'=>'ⱈ','Ⱉ'=>'ⱉ','Ⱊ'=>'ⱊ','Ⱋ'=>'ⱋ','Ⱌ'=>'ⱌ','Ⱍ'=>'ⱍ','Ⱎ'=>'ⱎ','Ⱏ'=>'ⱏ','Ⱐ'=>'ⱐ','Ⱑ'=>'ⱑ','Ⱒ'=>'ⱒ','Ⱓ'=>'ⱓ','Ⱔ'=>'ⱔ','Ⱕ'=>'ⱕ','Ⱖ'=>'ⱖ','Ⱗ'=>'ⱗ','Ⱘ'=>'ⱘ','Ⱙ'=>'ⱙ','Ⱚ'=>'ⱚ','Ⱛ'=>'ⱛ','Ⱜ'=>'ⱜ','Ⱝ'=>'ⱝ','Ⱞ'=>'ⱞ','Ⱡ'=>'ⱡ','Ɫ'=>'ɫ','Ᵽ'=>'ᵽ','Ɽ'=>'ɽ','Ⱨ'=>'ⱨ','Ⱪ'=>'ⱪ','Ⱬ'=>'ⱬ','Ⱶ'=>'ⱶ','Ⲁ'=>'ⲁ','Ⲃ'=>'ⲃ','Ⲅ'=>'ⲅ','Ⲇ'=>'ⲇ','Ⲉ'=>'ⲉ','Ⲋ'=>'ⲋ','Ⲍ'=>'ⲍ','Ⲏ'=>'ⲏ','Ⲑ'=>'ⲑ','Ⲓ'=>'ⲓ','Ⲕ'=>'ⲕ','Ⲗ'=>'ⲗ','Ⲙ'=>'ⲙ','Ⲛ'=>'ⲛ','Ⲝ'=>'ⲝ','Ⲟ'=>'ⲟ','Ⲡ'=>'ⲡ','Ⲣ'=>'ⲣ','Ⲥ'=>'ⲥ','Ⲧ'=>'ⲧ','Ⲩ'=>'ⲩ','Ⲫ'=>'ⲫ','Ⲭ'=>'ⲭ','Ⲯ'=>'ⲯ','Ⲱ'=>'ⲱ','Ⲳ'=>'ⲳ','Ⲵ'=>'ⲵ','Ⲷ'=>'ⲷ','Ⲹ'=>'ⲹ','Ⲻ'=>'ⲻ','Ⲽ'=>'ⲽ','Ⲿ'=>'ⲿ','Ⳁ'=>'ⳁ','Ⳃ'=>'ⳃ','Ⳅ'=>'ⳅ','Ⳇ'=>'ⳇ','Ⳉ'=>'ⳉ','Ⳋ'=>'ⳋ','Ⳍ'=>'ⳍ','Ⳏ'=>'ⳏ','Ⳑ'=>'ⳑ','Ⳓ'=>'ⳓ','Ⳕ'=>'ⳕ','Ⳗ'=>'ⳗ','Ⳙ'=>'ⳙ','Ⳛ'=>'ⳛ','Ⳝ'=>'ⳝ','Ⳟ'=>'ⳟ','Ⳡ'=>'ⳡ','Ⳣ'=>'ⳣ','A'=>'a','B'=>'b','C'=>'c','D'=>'d','E'=>'e','F'=>'f','G'=>'g','H'=>'h','I'=>'i','J'=>'j','K'=>'k','L'=>'l','M'=>'m','N'=>'n','O'=>'o','P'=>'p','Q'=>'q','R'=>'r','S'=>'s','T'=>'t','U'=>'u','V'=>'v','W'=>'w','X'=>'x','Y'=>'y','Z'=>'z','𐐀'=>'𐐨','𐐁'=>'𐐩','𐐂'=>'𐐪','𐐃'=>'𐐫','𐐄'=>'𐐬','𐐅'=>'𐐭','𐐆'=>'𐐮','𐐇'=>'𐐯','𐐈'=>'𐐰','𐐉'=>'𐐱','𐐊'=>'𐐲','𐐋'=>'𐐳','𐐌'=>'𐐴','𐐍'=>'𐐵','𐐎'=>'𐐶','𐐏'=>'𐐷','𐐐'=>'𐐸','𐐑'=>'𐐹','𐐒'=>'𐐺','𐐓'=>'𐐻','𐐔'=>'𐐼','𐐕'=>'𐐽','𐐖'=>'𐐾','𐐗'=>'𐐿','𐐘'=>'𐑀','𐐙'=>'𐑁','𐐚'=>'𐑂','𐐛'=>'𐑃','𐐜'=>'𐑄','𐐝'=>'𐑅','𐐞'=>'𐑆','𐐟'=>'𐑇','𐐠'=>'𐑈','𐐡'=>'𐑉','𐐢'=>'𐑊','𐐣'=>'𐑋','𐐤'=>'𐑌','𐐥'=>'𐑍','𐐦'=>'𐑎','𐐧'=>'𐑏');
\ No newline at end of file diff --git a/phpBB/includes/utf/data/case_fold_f.php b/phpBB/includes/utf/data/case_fold_f.php new file mode 100644 index 0000000000..7e2ffb25ec --- /dev/null +++ b/phpBB/includes/utf/data/case_fold_f.php @@ -0,0 +1 @@ +<?php return array('ß'=>'ss','İ'=>'i̇','ʼn'=>'ʼn','ǰ'=>'ǰ','ΐ'=>'ΐ','ΰ'=>'ΰ','և'=>'եւ','ẖ'=>'ẖ','ẗ'=>'ẗ','ẘ'=>'ẘ','ẙ'=>'ẙ','ẚ'=>'aʾ','ὐ'=>'ὐ','ὒ'=>'ὒ','ὔ'=>'ὔ','ὖ'=>'ὖ','ᾀ'=>'ἀι','ᾁ'=>'ἁι','ᾂ'=>'ἂι','ᾃ'=>'ἃι','ᾄ'=>'ἄι','ᾅ'=>'ἅι','ᾆ'=>'ἆι','ᾇ'=>'ἇι','ᾈ'=>'ἀι','ᾉ'=>'ἁι','ᾊ'=>'ἂι','ᾋ'=>'ἃι','ᾌ'=>'ἄι','ᾍ'=>'ἅι','ᾎ'=>'ἆι','ᾏ'=>'ἇι','ᾐ'=>'ἠι','ᾑ'=>'ἡι','ᾒ'=>'ἢι','ᾓ'=>'ἣι','ᾔ'=>'ἤι','ᾕ'=>'ἥι','ᾖ'=>'ἦι','ᾗ'=>'ἧι','ᾘ'=>'ἠι','ᾙ'=>'ἡι','ᾚ'=>'ἢι','ᾛ'=>'ἣι','ᾜ'=>'ἤι','ᾝ'=>'ἥι','ᾞ'=>'ἦι','ᾟ'=>'ἧι','ᾠ'=>'ὠι','ᾡ'=>'ὡι','ᾢ'=>'ὢι','ᾣ'=>'ὣι','ᾤ'=>'ὤι','ᾥ'=>'ὥι','ᾦ'=>'ὦι','ᾧ'=>'ὧι','ᾨ'=>'ὠι','ᾩ'=>'ὡι','ᾪ'=>'ὢι','ᾫ'=>'ὣι','ᾬ'=>'ὤι','ᾭ'=>'ὥι','ᾮ'=>'ὦι','ᾯ'=>'ὧι','ᾲ'=>'ὰι','ᾳ'=>'αι','ᾴ'=>'άι','ᾶ'=>'ᾶ','ᾷ'=>'ᾶι','ᾼ'=>'αι','ῂ'=>'ὴι','ῃ'=>'ηι','ῄ'=>'ήι','ῆ'=>'ῆ','ῇ'=>'ῆι','ῌ'=>'ηι','ῒ'=>'ῒ','ΐ'=>'ΐ','ῖ'=>'ῖ','ῗ'=>'ῗ','ῢ'=>'ῢ','ΰ'=>'ΰ','ῤ'=>'ῤ','ῦ'=>'ῦ','ῧ'=>'ῧ','ῲ'=>'ὼι','ῳ'=>'ωι','ῴ'=>'ώι','ῶ'=>'ῶ','ῷ'=>'ῶι','ῼ'=>'ωι','ff'=>'ff','fi'=>'fi','fl'=>'fl','ffi'=>'ffi','ffl'=>'ffl','ſt'=>'st','st'=>'st','ﬓ'=>'մն','ﬔ'=>'մե','ﬕ'=>'մի','ﬖ'=>'վն','ﬗ'=>'մխ');
\ No newline at end of file diff --git a/phpBB/includes/utf/data/case_fold_s.php b/phpBB/includes/utf/data/case_fold_s.php new file mode 100644 index 0000000000..5f09ffa1dd --- /dev/null +++ b/phpBB/includes/utf/data/case_fold_s.php @@ -0,0 +1 @@ +<?php return array('ᾈ'=>'ᾀ','ᾉ'=>'ᾁ','ᾊ'=>'ᾂ','ᾋ'=>'ᾃ','ᾌ'=>'ᾄ','ᾍ'=>'ᾅ','ᾎ'=>'ᾆ','ᾏ'=>'ᾇ','ᾘ'=>'ᾐ','ᾙ'=>'ᾑ','ᾚ'=>'ᾒ','ᾛ'=>'ᾓ','ᾜ'=>'ᾔ','ᾝ'=>'ᾕ','ᾞ'=>'ᾖ','ᾟ'=>'ᾗ','ᾨ'=>'ᾠ','ᾩ'=>'ᾡ','ᾪ'=>'ᾢ','ᾫ'=>'ᾣ','ᾬ'=>'ᾤ','ᾭ'=>'ᾥ','ᾮ'=>'ᾦ','ᾯ'=>'ᾧ','ᾼ'=>'ᾳ','ῌ'=>'ῃ','ῼ'=>'ῳ');
\ No newline at end of file diff --git a/phpBB/includes/utf/utf_normalizer.php b/phpBB/includes/utf/utf_normalizer.php index 0b567fad6b..0d1d74539a 100644 --- a/phpBB/includes/utf/utf_normalizer.php +++ b/phpBB/includes/utf/utf_normalizer.php @@ -27,148 +27,20 @@ define('UTF8_CJK_LAST', "\xE9\xBE\xBB"); define('UTF8_CJK_B_FIRST', "\xF0\xA0\x80\x80"); define('UTF8_CJK_B_LAST', "\xF0\xAA\x9B\x96"); - -if (function_exists('utf8_normalize')) -{ - -//////////////////////////////////////////////////////////////////////////////// -// Wrapper for the utfnormal extension, ICU wrapper // -//////////////////////////////////////////////////////////////////////////////// - -define('UNORM_NONE', 1); -define('UNORM_NFD', 2); -define('UNORM_NFKD', 3); -define('UNORM_NFC', 4); -define('UNORM_NFKC', 5); -define('UNORM_FCD', 6); -define('UNORM_DEFAULT', UNORM_NFC); - -/** -* utf_normalizer class for the utfnormal extension -* -* @ignore -*/ -class utf_normalizer -{ - function cleanup($str) - { - /** - * The string below is the list of all autorized characters, sorted by - * frequency in latin text - */ - $pos = strspn( - $str, - "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x0D" - ); - - if (!isset($str[$pos])) - { - /** - * ASCII strings with no special chars return immediately - */ - return $str; - } - - /** - * Check if there is potentially a U+FFFE or U+FFFF char (UTF sequence - * 0xEFBFBE or 0xEFBFBF) and replace them - * - * Note: we start searching at position $pos - */ - if (is_int(strpos($str, "\xEF\xBF", $pos))) - { - $str = str_replace( - array("\xEF\xBF\xBE", "\xEF\xBF\xBF"), - array(UTF8_REPLACEMENT, UTF8_REPLACEMENT), - $str - ); - } - - /** - * Replace any byte in the range 0x00..0x1F, except for \r, \n and \t - * - * We replace those characters with a 0xFF byte, which is illegal in - * UTF-8 and will in turn be replaced with a Unicode replacement char - */ - $str = strtr( - $str, - "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F", - "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" - ); - - /** - * As per the original implementation, "the UnicodeString constructor fails - * if the string ends with a head byte". Therefore, if the string ends with - * a leading byte we replace it with 0xFF, which is illegal too and will be - * replaced with a Unicode replacement character - */ - if (substr($str, -1) >= "\xC0") - { - $str[strlen($str) - 1] = "\xFF"; - } - - return utf8_normalize($str, UNORM_NFC); - } - - function nfc($str) - { - return utf8_normalize($str, UNORM_NFC); - } - - function nfkc($str) - { - return utf8_normalize($str, UNORM_NFKC); - } - - function nfd($str) - { - return utf8_normalize($str, UNORM_NFD); - } - - function nfkd($str) - { - return utf8_normalize($str, UNORM_NFKD); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// End of the ICU wrapper // -//////////////////////////////////////////////////////////////////////////////// - - -} -else -{ - - -//////////////////////////////////////////////////////////////////////////////// -// This block will NOT be loaded if the utfnormal extension is // -//////////////////////////////////////////////////////////////////////////////// - -/** -* Unset global variables -*/ +// Unset global variables unset($GLOBALS['utf_jamo_index'], $GLOBALS['utf_jamo_type'], $GLOBALS['utf_nfc_qc'], $GLOBALS['utf_combining_class'], $GLOBALS['utf_canonical_comp'], $GLOBALS['utf_canonical_decomp'], $GLOBALS['utf_nfkc_qc'], $GLOBALS['utf_compatibility_decomp']); -/** -* NFC_QC and NFKC_QC values -*/ +// NFC_QC and NFKC_QC values define('UNICODE_QC_MAYBE', 0); define('UNICODE_QC_NO', 1); -/** -* Contains all the ASCII characters appearing in UTF-8, sorted by frequency -*/ +// Contains all the ASCII characters appearing in UTF-8, sorted by frequency define('UTF8_ASCII_RANGE', "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"); -/** -* Contains all the tail bytes that can appear in the composition of a UTF-8 char -*/ +// Contains all the tail bytes that can appear in the composition of a UTF-8 char define('UTF8_TRAILING_BYTES', "\xA9\xA0\xA8\x80\xAA\x99\xA7\xBB\xAB\x89\x94\x82\xB4\xA2\xAE\x83\xB0\xB9\xB8\x93\xAF\xBC\xB3\x81\xA4\xB2\x9C\xA1\xB5\xBE\xBD\xBA\x98\xAD\xB1\x84\x95\xA6\xB6\x88\x8D\x90\xB7\xBF\x92\x85\xA5\x97\x8C\x86\xA3\x8E\x9F\x8F\x87\x91\x9D\xAC\x9E\x8B\x96\x9B\x8A\x9A"); -/** -* Constants used by the Hangul [de]composition algorithms -*/ +// Constants used by the Hangul [de]composition algorithms define('UNICODE_HANGUL_SBASE', 0xAC00); define('UNICODE_HANGUL_LBASE', 0x1100); define('UNICODE_HANGUL_VBASE', 0x1161); @@ -185,7 +57,7 @@ define('UNICODE_JAMO_T', 2); /** * Unicode normalization routines * -* @package phpBB3 +* @package phpBB3 */ class utf_normalizer { @@ -200,37 +72,25 @@ class utf_normalizer */ function cleanup($str) { - /** - * The string below is the list of all autorized characters, sorted by - * frequency in latin text - */ + // The string below is the list of all autorized characters, sorted by frequency in latin text $pos = strspn($str, "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x0D"); $len = strlen($str); if ($pos == $len) { - /** - * ASCII strings with no special chars return immediately - */ + // ASCII strings with no special chars return immediately return $str; } - /** - * Note: we do not check for $GLOBALS['utf_canonical_decomp']. It is assumed - * they are always loaded together - */ + // Note: we do not check for $GLOBALS['utf_canonical_decomp']. It is assumed they are always loaded together if (!isset($GLOBALS['utf_nfc_qc'])) { global $phpbb_root_path, $phpEx; include($phpbb_root_path . 'includes/utf/data/utf_nfc_qc.' . $phpEx); } - /** - * Replace any byte in the range 0x00..0x1F, except for \r, \n and \t - * - * We replace those characters with a 0xFF byte, which is illegal in - * UTF-8 and will in turn be replaced with a UTF replacement char - */ + // Replace any byte in the range 0x00..0x1F, except for \r, \n and \t + // We replace those characters with a 0xFF byte, which is illegal in UTF-8 and will in turn be replaced with a UTF replacement char return utf_normalizer::recompose( strtr( $str, @@ -254,9 +114,7 @@ class utf_normalizer if ($pos == $len) { - /** - * ASCII strings return immediately - */ + // ASCII strings return immediately return $str; } @@ -282,9 +140,7 @@ class utf_normalizer if ($pos == $len) { - /** - * ASCII strings return immediately - */ + // ASCII strings return immediately return $str; } @@ -293,6 +149,7 @@ class utf_normalizer global $phpbb_root_path, $phpEx; include($phpbb_root_path . 'includes/utf/data/utf_nfkc_qc.' . $phpEx); } + if (!isset($GLOBALS['utf_canonical_comp'])) { global $phpbb_root_path, $phpEx; @@ -315,9 +172,7 @@ class utf_normalizer if ($pos == $len) { - /** - * ASCII strings return immediately - */ + // ASCII strings return immediately return $str; } @@ -343,9 +198,7 @@ class utf_normalizer if ($pos == $len) { - /** - * ASCII strings return immediately - */ + // ASCII strings return immediately return $str; } @@ -359,10 +212,6 @@ class utf_normalizer } - //////////////////////////////////////////////////////////////////////////// - // Internal functions // - //////////////////////////////////////////////////////////////////////////// - /** * Recompose a UTF string * @@ -379,18 +228,14 @@ class utf_normalizer { global $utf_combining_class, $utf_canonical_comp, $utf_jamo_type, $utf_jamo_index; - /** - * Load some commonly-used tables - */ + // Load some commonly-used tables if (!isset($utf_jamo_index, $utf_jamo_type, $utf_combining_class)) { global $phpbb_root_path; include($phpbb_root_path . 'includes/utf/data/utf_normalizer_common.php'); } - /** - * Buffer the last ASCII char before the UTF-8 stuff if applicable - */ + // Buffer the last ASCII char before the UTF-8 stuff if applicable $tmp = ''; $i = $tmp_pos = $last_cc = 0; @@ -403,96 +248,66 @@ class utf_normalizer $buffer = array(); } - /** - * UTF char length array - * - * This array is used to determine the length of a UTF character. Be $c the - * result of ($str[$pos] & "\xF0") --where $str is the string we're operating - * on and $pos the position of the cursor--, if $utf_len_mask[$c] does not - * exist, the byte is an ASCII char. Otherwise, if $utf_len_mask[$c] is greater - * than 0, we have a the leading byte of a multibyte character whose length is - * $utf_len_mask[$c] and if it is equal to 0, the byte is a trailing byte. - */ + // UTF char length array + // This array is used to determine the length of a UTF character. + // Be $c the result of ($str[$pos] & "\xF0") --where $str is the string we're operating on and $pos + // the position of the cursor--, if $utf_len_mask[$c] does not exist, the byte is an ASCII char. + // Otherwise, if $utf_len_mask[$c] is greater than 0, we have a the leading byte of a multibyte character + // whose length is $utf_len_mask[$c] and if it is equal to 0, the byte is a trailing byte. $utf_len_mask = array( - /** - * Leading bytes masks - */ + // Leading bytes masks "\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4, - - /** - * Trailing bytes masks - */ + // Trailing bytes masks "\x80" => 0, "\x90" => 0, "\xA0" => 0, "\xB0" => 0 ); $extra_check = array( - "\xED"=>1, "\xEF"=>1, "\xC0"=>1, "\xC1"=>1, "\xE0"=>1, "\xF0"=>1, - "\xF4"=>1, "\xF5"=>1, "\xF6"=>1, "\xF7"=>1, "\xF8"=>1, "\xF9"=>1, - "\xFA"=>1, "\xFB"=>1, "\xFC"=>1, "\xFD"=>1, "\xFE"=>1, "\xFF"=>1 + "\xED" => 1, "\xEF" => 1, "\xC0" => 1, "\xC1" => 1, "\xE0" => 1, "\xF0" => 1, + "\xF4" => 1, "\xF5" => 1, "\xF6" => 1, "\xF7" => 1, "\xF8" => 1, "\xF9" => 1, + "\xFA" => 1, "\xFB" => 1, "\xFC" => 1, "\xFD" => 1, "\xFE" => 1, "\xFF" => 1 ); $utf_validation_mask = array( - 2 => "\xE0\xC0", - 3 => "\xF0\xC0\xC0", - 4 => "\xF8\xC0\xC0\xC0" + 2 => "\xE0\xC0", + 3 => "\xF0\xC0\xC0", + 4 => "\xF8\xC0\xC0\xC0" ); $utf_validation_check = array( - 2 => "\xC0\x80", - 3 => "\xE0\x80\x80", - 4 => "\xF0\x80\x80\x80" + 2 => "\xC0\x80", + 3 => "\xE0\x80\x80", + 4 => "\xF0\x80\x80\x80" ); - //////////////////////////////////////////////////////////////////////// - // Main loop // - //////////////////////////////////////////////////////////////////////// - + // Main loop do { - //////////////////////////////////////////////////////////////////// - // STEP 0: Capture the current char and buffer it // - //////////////////////////////////////////////////////////////////// - + // STEP 0: Capture the current char and buffer it $c = $str[$pos]; $c_mask = $c & "\xF0"; if (isset($utf_len_mask[$c_mask])) { - /** - * Byte at $pos is either a leading byte or a missplaced trailing byte - */ + // Byte at $pos is either a leading byte or a missplaced trailing byte if ($utf_len = $utf_len_mask[$c_mask]) { - /** - * Capture the char - */ + // Capture the char $buffer[++$i & 7] = $utf_char = substr($str, $pos, $utf_len); - /** - * Let's find out if a thorough check is needed - */ + // Let's find out if a thorough check is needed if (isset($qc[$utf_char])) { - /** - * If the UTF char is in the qc array then it may not be in normal - * form. We do nothing here, the actual processing is below this - * "if" block - */ + // If the UTF char is in the qc array then it may not be in normal form. We do nothing here, the actual processing is below this "if" block } - elseif (isset($utf_combining_class[$utf_char])) + else if (isset($utf_combining_class[$utf_char])) { if ($utf_combining_class[$utf_char] < $last_cc) { - /** - * A combining character that is NOT canonically ordered - */ + // A combining character that is NOT canonically ordered } else { - /** - * A combining character that IS canonically ordered, skip - * to the next char - */ + // A combining character that IS canonically ordered, skip to the next char $last_cc = $utf_combining_class[$utf_char]; $pos += $utf_len; @@ -501,34 +316,26 @@ class utf_normalizer } else { - /** - * At this point, $utf_char holds a UTF char that we know - * is not a NF[K]C_QC and is not a combining character. It can - * be a singleton, a canonical composite, a replacement char or - * an even an ill-formed bunch of bytes. Let's find out - */ + // At this point, $utf_char holds a UTF char that we know is not a NF[K]C_QC and is not a combining character. + // It can be a singleton, a canonical composite, a replacement char or an even an ill-formed bunch of bytes. Let's find out $last_cc = 0; - /** - * Check that we have the correct number of trailing bytes - */ + // Check that we have the correct number of trailing bytes if (($utf_char & $utf_validation_mask[$utf_len]) != $utf_validation_check[$utf_len]) { - /** - * Current char isn't well-formed or legal: either one or - * several trailing bytes are missing, or the Unicode char - * has been encoded in a five- or six- byte sequence - */ + // Current char isn't well-formed or legal: either one or several trailing bytes are missing, or the Unicode char + // has been encoded in a five- or six- byte sequence if ($utf_char[0] >= "\xF8") { if ($utf_char[0] < "\xF8") { $trailing_bytes = 3; } - elseif ($utf_char[0] < "\xFC") + else if ($utf_char[0] < "\xFC") { $trailing_bytes = 4; } + if ($utf_char[0] > "\xFD") { $trailing_bytes = 0; @@ -552,101 +359,80 @@ class utf_normalizer if (isset($extra_check[$c])) { - switch($c) + switch ($c) { - /** - * Note: 0xED is quite common in Korean - */ + // Note: 0xED is quite common in Korean case "\xED": if ($utf_char >= "\xED\xA0\x80") { - /** - * Surrogates (U+D800..U+DFFF) are not allowed in UTF-8 - * (UTF sequence 0xEDA080..0xEDBFBF) - */ + // Surrogates (U+D800..U+DFFF) are not allowed in UTF-8 (UTF sequence 0xEDA080..0xEDBFBF) $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT; $pos += $utf_len; $tmp_pos = $pos; continue 2; } - break; + break; - /** - * Note: 0xEF is quite common in Japanese - */ + // Note: 0xEF is quite common in Japanese case "\xEF": if ($utf_char == "\xEF\xBF\xBE" || $utf_char == "\xEF\xBF\xBF") { - /** - * U+FFFE and U+FFFF are explicitly disallowed - * (UTF sequence 0xEFBFBE..0xEFBFBF) - */ + // U+FFFE and U+FFFF are explicitly disallowed (UTF sequence 0xEFBFBE..0xEFBFBF) $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT; $pos += $utf_len; $tmp_pos = $pos; continue 2; } - break; + break; case "\xC0": case "\xC1": if ($utf_char <= "\xC1\xBF") { - /** - * Overlong sequence: Unicode char U+0000..U+007F encoded as a - * double-byte UTF char - */ + // Overlong sequence: Unicode char U+0000..U+007F encoded as a double-byte UTF char $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT; $pos += $utf_len; $tmp_pos = $pos; continue 2; } - break; + break; case "\xE0": if ($utf_char <= "\xE0\x9F\xBF") { - /** - * Unicode char U+0000..U+07FF encoded in 3 bytes - */ + // Unicode char U+0000..U+07FF encoded in 3 bytes $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT; $pos += $utf_len; $tmp_pos = $pos; continue 2; } - break; + break; case "\xF0": if ($utf_char <= "\xF0\x8F\xBF\xBF") { - /** - * Unicode char U+0000..U+FFFF encoded in 4 bytes - */ + // Unicode char U+0000..U+FFFF encoded in 4 bytes $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . UTF8_REPLACEMENT; $pos += $utf_len; $tmp_pos = $pos; continue 2; } - break; + break; default: - /** - * Five- and six- byte sequences do not need being checked for here anymore - */ + // Five- and six- byte sequences do not need being checked for here anymore if ($utf_char > UTF8_MAX) { - /** - * Out of the Unicode range - */ + // Out of the Unicode range if ($utf_char[0] < "\xF8") { $trailing_bytes = 3; } - elseif ($utf_char[0] < "\xFC") + else if ($utf_char[0] < "\xFC") { $trailing_bytes = 4; } - elseif ($utf_char[0] > "\xFD") + else if ($utf_char[0] > "\xFD") { $trailing_bytes = 0; } @@ -660,23 +446,19 @@ class utf_normalizer $tmp_pos = $pos; continue 2; } + break; } } - /** - * The char is a valid starter, move the cursor and go on - */ + // The char is a valid starter, move the cursor and go on $pos += $utf_len; continue; } } else { - /** - * A trailing byte came out of nowhere, we will advance the cursor - * and treat the this byte and all following trailing bytes as if - * each of them was a Unicode replacement char - */ + // A trailing byte came out of nowhere, we will advance the cursor and treat the this byte and all following trailing bytes as if + // each of them was a Unicode replacement char $spn = strspn($str, UTF8_TRAILING_BYTES, $pos); $tmp .= substr($str, $tmp_pos, $pos - $tmp_pos) . str_repeat(UTF8_REPLACEMENT, $spn); @@ -686,26 +468,20 @@ class utf_normalizer } - //////////////////////////////////////////////////////////////////// - // STEP 1: Decompose current char // - //////////////////////////////////////////////////////////////////// - - /** - * We have found a character that is either: - * - in the NFC_QC/NFKC_QC list - * - a non-starter char that is not canonically ordered - * - * We are going to capture the shortest UTF sequence that satisfies - * these two conditions: - * - * 1 - If the sequence does not start at the begginning of the string, - * it must begin with a starter, and that starter must not have the - * NF[K]C_QC property equal to "MAYBE" - * - * 2 - If the sequence does not end at the end of the string, it must end - * with a non-starter and be immediately followed by a starter that - * is not on the QC list - */ + // STEP 1: Decompose current char + + // We have found a character that is either: + // - in the NFC_QC/NFKC_QC list + // - a non-starter char that is not canonically ordered + // + // We are going to capture the shortest UTF sequence that satisfies these two conditions: + // + // 1 - If the sequence does not start at the begginning of the string, it must begin with a starter, + // and that starter must not have the NF[K]C_QC property equal to "MAYBE" + // + // 2 - If the sequence does not end at the end of the string, it must end with a non-starter and be + // immediately followed by a starter that is not on the QC list + // $utf_seq = array(); $last_cc = 0; $lpos = $pos; @@ -715,6 +491,7 @@ class utf_normalizer { $_pos = 0; $_len = strlen($decomp_map[$utf_char]); + do { $_utf_len =& $utf_len_mask[$decomp_map[$utf_char][$_pos] & "\xF0"]; @@ -730,59 +507,46 @@ class utf_normalizer ++$_pos; } } - while($_pos < $_len); + while ($_pos < $_len); } else { - /** - * The char is not decomposable - */ + // The char is not decomposable $utf_seq = array($utf_char); } - //////////////////////////////////////////////////////////////// - // STEP 2: Capture the starter // - //////////////////////////////////////////////////////////////// + // STEP 2: Capture the starter - /** - * Check out the combining class of the first character of the UTF sequence - */ + // Check out the combining class of the first character of the UTF sequence $k = 0; if (isset($utf_combining_class[$utf_seq[0]]) || $qc[$utf_char] == UNICODE_QC_MAYBE) { - /** - * Not a starter, inspect previous characters - * - * The last 8 characters are kept in a buffer so that we don't have - * to capture them everytime. This is enough for all real-life strings - * but even if it wasn't, we can capture characters in backward mode, - * although it is slower than this method. - * - * In the following loop, $j starts at the previous buffered character - * ($i - 1, because current character is at offset $i) and process them - * in backward mode until we find a starter. - * - * $k is the index on each UTF character inside of our UTF sequence. - * At this time, $utf_seq contains one or more characters numbered 0 to - * n. $k starts at 0 and for each char we prepend we pre-decrement it - * and for numbering - */ + // Not a starter, inspect previous characters + // The last 8 characters are kept in a buffer so that we don't have to capture them everytime. + // This is enough for all real-life strings but even if it wasn't, we can capture characters in backward mode, + // although it is slower than this method. + // + // In the following loop, $j starts at the previous buffered character ($i - 1, because current character is + // at offset $i) and process them in backward mode until we find a starter. + // + // $k is the index on each UTF character inside of our UTF sequence. At this time, $utf_seq contains one or more + // characters numbered 0 to n. $k starts at 0 and for each char we prepend we pre-decrement it and for numbering $starter_found = 0; $j_min = max(1, $i - 7); - for($j = $i - 1; $j >= $j_min && $lpos > $tmp_pos; --$j) + + for ($j = $i - 1; $j >= $j_min && $lpos > $tmp_pos; --$j) { $utf_char = $buffer[$j & 7]; $lpos -= strlen($utf_char); if (isset($decomp_map[$utf_char])) { - /** - * The char is a composite, decompose for storage - */ + // The char is a composite, decompose for storage $decomp_seq = array(); $_pos = 0; $_len = strlen($decomp_map[$utf_char]); + do { $c = $decomp_map[$utf_char][$_pos]; @@ -799,18 +563,15 @@ class utf_normalizer ++$_pos; } } - while($_pos < $_len); + while ($_pos < $_len); - /** - * Prepend the UTF sequence with our decomposed sequence - */ + // Prepend the UTF sequence with our decomposed sequence if (isset($decomp_seq[1])) { - /** - * The char expanded into several chars - */ - $decomp_cnt = count($decomp_seq); - foreach($decomp_seq as $decomp_i => $decomp_char) + // The char expanded into several chars + $decomp_cnt = sizeof($decomp_seq); + + foreach ($decomp_seq as $decomp_i => $decomp_char) { $utf_seq[$k + $decomp_i - $decomp_cnt] = $decomp_char; } @@ -818,9 +579,7 @@ class utf_normalizer } else { - /** - * Decomposed to a single char, easier to prepend - */ + // Decomposed to a single char, easier to prepend $utf_seq[--$k] = $decomp_seq[0]; } } @@ -831,9 +590,7 @@ class utf_normalizer if (!isset($utf_combining_class[$utf_seq[$k]])) { - /** - * We have found our starter - */ + // We have found our starter $starter_found = 1; break; } @@ -841,39 +598,28 @@ class utf_normalizer if (!$starter_found && $lpos > $tmp_pos) { - /** - * The starter was not found in the buffer, let's rewind some more - */ + // The starter was not found in the buffer, let's rewind some more do { - /** - * $utf_len_mask contains the masks of both leading bytes and - * trailing bytes. If $utf_en > 0 then it's a leading byte, - * otherwise it's a trailing byte. - */ + // $utf_len_mask contains the masks of both leading bytes and trailing bytes. If $utf_en > 0 then it's a leading byte, otherwise it's a trailing byte. $c = $str[--$lpos]; $c_mask = $c & "\xF0"; if (isset($utf_len_mask[$c_mask])) { - /** - * UTF byte - */ + // UTF byte if ($utf_len = $utf_len_mask[$c_mask]) { - /** - * UTF *leading* byte - */ + // UTF *leading* byte $utf_char = substr($str, $lpos, $utf_len); if (isset($decomp_map[$utf_char])) { - /** - * Decompose the character - */ + // Decompose the character $decomp_seq = array(); $_pos = 0; $_len = strlen($decomp_map[$utf_char]); + do { $c = $decomp_map[$utf_char][$_pos]; @@ -890,18 +636,14 @@ class utf_normalizer ++$_pos; } } - while($_pos < $_len); + while ($_pos < $_len); - /** - * Prepend the UTF sequence with our decomposed sequence - */ + // Prepend the UTF sequence with our decomposed sequence if (isset($decomp_seq[1])) { - /** - * The char expanded into several chars - */ - $decomp_cnt = count($decomp_seq); - foreach($decomp_seq as $decomp_i => $utf_char) + // The char expanded into several chars + $decomp_cnt = sizeof($decomp_seq); + foreach ($decomp_seq as $decomp_i => $utf_char) { $utf_seq[$k + $decomp_i - $decomp_cnt] = $utf_char; } @@ -909,9 +651,7 @@ class utf_normalizer } else { - /** - * Decomposed to a single char, easier to prepend - */ + // Decomposed to a single char, easier to prepend $utf_seq[--$k] = $decomp_seq[0]; } } @@ -923,22 +663,18 @@ class utf_normalizer } else { - /** - * ASCII char - */ + // ASCII char $utf_seq[--$k] = $c; } } - while($lpos > $tmp_pos); + while ($lpos > $tmp_pos); } } - //////////////////////////////////////////////////////////////// - // STEP 3: Capture following combining modifiers // - //////////////////////////////////////////////////////////////// + // STEP 3: Capture following combining modifiers - while($pos < $len) + while ($pos < $len) { $c_mask = $str[$pos] & "\xF0"; @@ -950,29 +686,21 @@ class utf_normalizer } else { - /** - * A trailing byte came out of nowhere - * - * Trailing bytes are replaced with Unicode replacement chars, - * we will just ignore it for now, break out of the loop - * as if it was a starter (replacement chars ARE starters) - * and let the next loop replace it - */ + // A trailing byte came out of nowhere + // Trailing bytes are replaced with Unicode replacement chars, we will just ignore it for now, break out of the loop + // as if it was a starter (replacement chars ARE starters) and let the next loop replace it break; } if (isset($utf_combining_class[$utf_char]) || isset($qc[$utf_char])) { - /** - * Combining character, add it to the sequence and move the cursor - */ + // Combining character, add it to the sequence and move the cursor if (isset($decomp_map[$utf_char])) { - /** - * Decompose the character - */ + // Decompose the character $_pos = 0; $_len = strlen($decomp_map[$utf_char]); + do { $c = $decomp_map[$utf_char][$_pos]; @@ -989,7 +717,7 @@ class utf_normalizer ++$_pos; } } - while($_pos < $_len); + while ($_pos < $_len); } else { @@ -1000,54 +728,38 @@ class utf_normalizer } else { - /** - * Combining class 0 and no QC, break out of the loop - * - * Note: we do not know if that character is valid. If - * it's not, the next iteration will replace it - */ + // Combining class 0 and no QC, break out of the loop + // Note: we do not know if that character is valid. If it's not, the next iteration will replace it break; } } else { - /** - * ASCII chars are starters - */ + // ASCII chars are starters break; } } - //////////////////////////////////////////////////////////////// - // STEP 4: Sort and combine // - //////////////////////////////////////////////////////////////// + // STEP 4: Sort and combine + + // Here we sort... + $k_max = $k + sizeof($utf_seq); - /** - * Here we sort... - */ - $k_max = $k + count($utf_seq); if (!$k && $k_max == 1) { - /** - * There is only one char in the UTF sequence, add it then - * jump to the next iteration of main loop - * - * Note: the two commented lines below can be enabled under PHP5 - * for a very small performance gain in most cases - */ -// if (substr_compare($str, $utf_seq[0], $lpos, $pos - $lpos)) -// { + // There is only one char in the UTF sequence, add it then jump to the next iteration of main loop + // Note: the two commented lines below can be enabled under PHP5 for a very small performance gain in most cases +// if (substr_compare($str, $utf_seq[0], $lpos, $pos - $lpos)) +// { $tmp .= substr($str, $tmp_pos, $lpos - $tmp_pos) . $utf_seq[0]; $tmp_pos = $pos; -// } +// } continue; } - /** - * ...there we combine - */ + // ...there we combine if (isset($utf_combining_class[$utf_seq[$k]])) { $starter = $nf_seq = ''; @@ -1059,11 +771,8 @@ class utf_normalizer } $utf_sort = array(); - /** - * We add an empty char at the end of the UTF char sequence. - * It will act as a starter and trigger the sort/combine routine - * at the end of the string without altering it - */ + // We add an empty char at the end of the UTF char sequence. It will act as a starter and trigger the sort/combine routine + // at the end of the string without altering it $utf_seq[] = ''; do @@ -1078,45 +787,27 @@ class utf_normalizer { if (empty($utf_sort)) { - /** - * No combining characters... check for a composite - * of the two starters - */ + // No combining characters... check for a composite of the two starters if (isset($utf_canonical_comp[$starter . $utf_char])) { - /** - * Good ol' composite character - */ + // Good ol' composite character $starter = $utf_canonical_comp[$starter . $utf_char]; } - elseif (isset($utf_jamo_type[$utf_char])) + else if (isset($utf_jamo_type[$utf_char])) { - /** - * Current char is a composable jamo - */ - if (isset($utf_jamo_type[$starter]) - && $utf_jamo_type[$starter] == UNICODE_JAMO_L - && $utf_jamo_type[$utf_char] == UNICODE_JAMO_V) + // Current char is a composable jamo + if (isset($utf_jamo_type[$starter]) && $utf_jamo_type[$starter] == UNICODE_JAMO_L && $utf_jamo_type[$utf_char] == UNICODE_JAMO_V) { - /** - * We have a L jamo followed by a V jamo, we are going - * to prefetch the next char to see if it's a T jamo - */ + // We have a L jamo followed by a V jamo, we are going to prefetch the next char to see if it's a T jamo if (isset($utf_jamo_type[$utf_seq[$k]]) && $utf_jamo_type[$utf_seq[$k]] == UNICODE_JAMO_T) { - /** - * L+V+T jamos, combine to a LVT Hangul syllable - * ($k is incremented) - */ + // L+V+T jamos, combine to a LVT Hangul syllable ($k is incremented) $cp = $utf_jamo_index[$starter] + $utf_jamo_index[$utf_char] + $utf_jamo_index[$utf_seq[$k]]; - ++$k; } else { - /** - * L+V jamos, combine to a LV Hangul syllable - */ + // L+V jamos, combine to a LV Hangul syllable $cp = $utf_jamo_index[$starter] + $utf_jamo_index[$utf_char]; } @@ -1124,19 +815,14 @@ class utf_normalizer } else { - /** - * Non-composable jamo, just add it to the sequence - */ + // Non-composable jamo, just add it to the sequence $nf_seq .= $starter; $starter = $utf_char; } } else { - /** - * No composite, just add the first starter to the sequence - * then continue with the other one - */ + // No composite, just add the first starter to the sequence then continue with the other one $nf_seq .= $starter; $starter = $utf_char; } @@ -1145,44 +831,33 @@ class utf_normalizer { ksort($utf_sort); - /** - * For each class of combining characters - */ - foreach($utf_sort as $cc => $utf_chars) + // For each class of combining characters + foreach ($utf_sort as $cc => $utf_chars) { $j = 0; do { - /** - * Look for a composite - */ + // Look for a composite if (isset($utf_canonical_comp[$starter . $utf_chars[$j]])) { - /** - * Found a composite, replace the starter - */ + // Found a composite, replace the starter $starter = $utf_canonical_comp[$starter . $utf_chars[$j]]; unset($utf_sort[$cc][$j]); } else { - /** - * No composite, all following characters in that - * class are blocked - */ + // No composite, all following characters in that class are blocked break; } } - while(isset($utf_sort[$cc][++$j])); + while (isset($utf_sort[$cc][++$j])); } - /** - * Add the starter to the normalized sequence, followed by - * non-starters in canonical order - */ + // Add the starter to the normalized sequence, followed by non-starters in canonical order $nf_seq .= $starter; - foreach($utf_sort as $utf_chars) + + foreach ($utf_sort as $utf_chars) { if (!empty($utf_chars)) { @@ -1190,31 +865,25 @@ class utf_normalizer } } - /** - * Reset the array and go on - */ + // Reset the array and go on $utf_sort = array(); $starter = $utf_char; } } } - while($k <= $k_max); + while ($k <= $k_max); $tmp .= substr($str, $tmp_pos, $lpos - $tmp_pos) . $nf_seq; $tmp_pos = $pos; } else { - /** - * Only a ASCII char can make the program get here - * - * First we skip the current byte with ++$pos, then we quickly - * skip following ASCII chars with strspn(). - * - * The first two "if"'s here can be removed, with the consequences - * of being faster on latin text (lots of ASCII) and slower on - * multi-byte text (where the only ASCII chars are spaces and punctuation) - */ + // Only a ASCII char can make the program get here + // + // First we skip the current byte with ++$pos, then we quickly skip following ASCII chars with strspn(). + // + // The first two "if"'s here can be removed, with the consequences of being faster on latin text (lots of ASCII) and slower on + // multi-byte text (where the only ASCII chars are spaces and punctuation) if (++$pos != $len) { if ($str[$pos] < "\x80") @@ -1229,37 +898,25 @@ class utf_normalizer } } } - while($pos < $len); + while ($pos < $len); - /** - * Now is time to return the string - */ + // Now is time to return the string if ($tmp_pos) { - /** - * If the $tmp_pos cursor is not at the beggining of the string then at least - * one character was not in normal form. Replace $str with the fixed version - */ + // If the $tmp_pos cursor is not at the beggining of the string then at least one character was not in normal form. Replace $str with the fixed version if ($tmp_pos == $len) { - /** - * The $tmp_pos cursor is at the end of $str, therefore $tmp holds the - * whole $str - */ + // The $tmp_pos cursor is at the end of $str, therefore $tmp holds the whole $str return $tmp; } else { - /** - * The rightmost chunk of $str has not been appended to $tmp yet - */ + // The rightmost chunk of $str has not been appended to $tmp yet return $tmp . substr($str, $tmp_pos); } } - /** - * The string was already in normal form - */ + // The string was already in normal form return $str; } @@ -1278,56 +935,42 @@ class utf_normalizer { global $utf_combining_class, $utf_canonical_decomp, $phpbb_root_path; - /** - * Load some commonly-used tables - */ + // Load some commonly-used tables if (!isset($utf_combining_class)) { include($phpbb_root_path . 'includes/utf/data/utf_normalizer_common.php'); } - /** - * UTF char length array - */ + // UTF char length array $utf_len_mask = array( - /** - * Leading bytes masks - */ + // Leading bytes masks "\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4, - - /** - * Trailing bytes masks - */ + // Trailing bytes masks "\x80" => 0, "\x90" => 0, "\xA0" => 0, "\xB0" => 0 ); - /** - * Some extra checks are triggered on the first byte of a UTF sequence - */ + // Some extra checks are triggered on the first byte of a UTF sequence $extra_check = array( - "\xED"=>1, "\xEF"=>1, "\xC0"=>1, "\xC1"=>1, "\xE0"=>1, "\xF0"=>1, - "\xF4"=>1, "\xF5"=>1, "\xF6"=>1, "\xF7"=>1, "\xF8"=>1, "\xF9"=>1, - "\xFA"=>1, "\xFB"=>1, "\xFC"=>1, "\xFD"=>1, "\xFE"=>1, "\xFF"=>1 + "\xED" => 1, "\xEF" => 1, "\xC0" => 1, "\xC1" => 1, "\xE0" => 1, "\xF0" => 1, + "\xF4" => 1, "\xF5" => 1, "\xF6" => 1, "\xF7" => 1, "\xF8" => 1, "\xF9" => 1, + "\xFA" => 1, "\xFB" => 1, "\xFC" => 1, "\xFD" => 1, "\xFE" => 1, "\xFF" => 1 ); - /** - * These masks are used to check if a UTF sequence is well formed. - * Here are the only 3 lengths we acknowledge: - * - 2-byte: 110? ???? 10?? ???? - * - 3-byte: 1110 ???? 10?? ???? 10?? ???? - * - 4-byte: 1111 0??? 10?? ???? 10?? ???? 10?? ???? - * - * Note that 5- and 6- byte sequences are automatically discarded - */ + // These masks are used to check if a UTF sequence is well formed. Here are the only 3 lengths we acknowledge: + // - 2-byte: 110? ???? 10?? ???? + // - 3-byte: 1110 ???? 10?? ???? 10?? ???? + // - 4-byte: 1111 0??? 10?? ???? 10?? ???? 10?? ???? + // Note that 5- and 6- byte sequences are automatically discarded $utf_validation_mask = array( - 2 => "\xE0\xC0", - 3 => "\xF0\xC0\xC0", - 4 => "\xF8\xC0\xC0\xC0" + 2 => "\xE0\xC0", + 3 => "\xF0\xC0\xC0", + 4 => "\xF8\xC0\xC0\xC0" ); + $utf_validation_check = array( - 2 => "\xC0\x80", - 3 => "\xE0\x80\x80", - 4 => "\xF0\x80\x80\x80" + 2 => "\xC0\x80", + 3 => "\xE0\x80\x80", + 4 => "\xF0\x80\x80\x80" ); $tmp = ''; @@ -1336,43 +979,31 @@ class utf_normalizer $utf_sort = array(); - //////////////////////////////////////////////////////////////////////// - // Main loop // - //////////////////////////////////////////////////////////////////////// - + // Main loop do { - //////////////////////////////////////////////////////////////////// - // STEP 0: Capture the current char // - //////////////////////////////////////////////////////////////////// + // STEP 0: Capture the current char $cur_mask = $str[$pos] & "\xF0"; if (isset($utf_len_mask[$cur_mask])) { if ($utf_len = $utf_len_mask[$cur_mask]) { - /** - * Multibyte char - */ + // Multibyte char $utf_char = substr($str, $pos, $utf_len); $pos += $utf_len; } else { - /** - * A trailing byte came out of nowhere, we will treat it and all - * following trailing bytes as if each of them was a Unicode - * replacement char and we will advance the cursor - */ + // A trailing byte came out of nowhere, we will treat it and all following trailing bytes as if each of them was a Unicode + // replacement char and we will advance the cursor $spn = strspn($str, UTF8_TRAILING_BYTES, $pos); if ($dump) { $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); - /** - * Dump combiners - */ + // Dump combiners if (!empty($utf_sort)) { if ($sort) @@ -1404,21 +1035,15 @@ class utf_normalizer } - //////////////////////////////////////////////////////////////////// - // STEP 1: Decide what to do with current char // - //////////////////////////////////////////////////////////////////// + // STEP 1: Decide what to do with current char - /** - * Now, in that order: - * - check if that character is decomposable - * - check if that character is a non-starter - * - check if that character requires extra checks to be performed - */ + // Now, in that order: + // - check if that character is decomposable + // - check if that character is a non-starter + // - check if that character requires extra checks to be performed if (isset($decomp_map[$utf_char])) { - /** - * Decompose the char - */ + // Decompose the char $_pos = 0; $_len = strlen($decomp_map[$utf_char]); @@ -1434,16 +1059,12 @@ class utf_normalizer if (isset($utf_combining_class[$_utf_char])) { - /** - * The character decomposed to a non-starter, buffer it for sorting - */ + // The character decomposed to a non-starter, buffer it for sorting $utf_sort[$utf_combining_class[$_utf_char]][] = $_utf_char; if ($utf_combining_class[$_utf_char] < $last_cc) { - /** - * Not canonically ordered, will require sorting - */ + // Not canonically ordered, will require sorting $sort = $dump = 1; } else @@ -1454,17 +1075,12 @@ class utf_normalizer } else { - /** - * This character decomposition contains a starter, - * dump the buffer and continue - */ + // This character decomposition contains a starter, dump the buffer and continue if ($dump) { $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); - /** - * Dump combiners - */ + // Dump combiners if (!empty($utf_sort)) { if ($sort) @@ -1472,7 +1088,7 @@ class utf_normalizer ksort($utf_sort); } - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } @@ -1493,18 +1109,14 @@ class utf_normalizer } else { - /** - * This character decomposition contains an ASCII char, - * which is a starter. Dump the buffer and continue - */ + // This character decomposition contains an ASCII char, which is a starter. Dump the buffer and continue ++$_pos; + if ($dump) { $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); - /** - * Dump combiners - */ + // Dump combiners if (!empty($utf_sort)) { if ($sort) @@ -1512,7 +1124,7 @@ class utf_normalizer ksort($utf_sort); } - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } @@ -1531,18 +1143,14 @@ class utf_normalizer $last_cc = 0; } } - while($_pos < $_len); + while ($_pos < $_len); } - elseif (isset($utf_combining_class[$utf_char])) + else if (isset($utf_combining_class[$utf_char])) { - /** - * Combining character - */ + // Combining character if ($utf_combining_class[$utf_char] < $last_cc) { - /** - * Not in canonical order - */ + // Not in canonical order $sort = $dump = 1; } else @@ -1554,24 +1162,15 @@ class utf_normalizer } else { - /** - * Non-decomposable starter, check out if it's a Hangul syllable - */ + // Non-decomposable starter, check out if it's a Hangul syllable if ($utf_char < UTF8_HANGUL_FIRST || $utf_char > UTF8_HANGUL_LAST) { - /** - * Nope, regular UTF char, check that we have the correct number of trailing bytes - */ + // Nope, regular UTF char, check that we have the correct number of trailing bytes if (($utf_char & $utf_validation_mask[$utf_len]) != $utf_validation_check[$utf_len]) { - /** - * Current char isn't well-formed or legal: either one or - * several trailing bytes are missing, or the Unicode char - * has been encoded in a five- or six- byte sequence. - * - * Move the cursor back to its original position then advance - * it to the position it should really be at - */ + // Current char isn't well-formed or legal: either one or several trailing bytes are missing, or the Unicode char + // has been encoded in a five- or six- byte sequence. + // Move the cursor back to its original position then advance it to the position it should really be at $pos -= $utf_len; $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); @@ -1579,20 +1178,16 @@ class utf_normalizer { ksort($utf_sort); - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } $utf_sort = array(); } - /** - * Add a replacement char then another replacement char for - * every trailing byte. - * - * @todo I'm not entirely sure that's how we're supposed to - * mark invalidated byte sequences, check this - */ + // Add a replacement char then another replacement char for every trailing byte. + // + // @todo I'm not entirely sure that's how we're supposed to mark invalidated byte sequences, check this $spn = strspn($str, UTF8_TRAILING_BYTES, ++$pos); $tmp .= str_repeat(UTF8_REPLACEMENT, $spn + 1); @@ -1605,25 +1200,20 @@ class utf_normalizer if (isset($extra_check[$utf_char[0]])) { - switch($utf_char[0]) + switch ($utf_char[0]) { - /** - * Note: 0xED is quite common in Korean - */ + // Note: 0xED is quite common in Korean case "\xED": if ($utf_char >= "\xED\xA0\x80") { - /** - * Surrogates (U+D800..U+DFFF) are not allowed in UTF-8 - * (UTF sequence 0xEDA080..0xEDBFBF) - */ + // Surrogates (U+D800..U+DFFF) are not allowed in UTF-8 (UTF sequence 0xEDA080..0xEDBFBF) $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); if (!empty($utf_sort)) { ksort($utf_sort); - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } @@ -1636,25 +1226,20 @@ class utf_normalizer $tmp_pos = $starter_pos = $pos; continue 2; } - break; + break; - /** - * Note: 0xEF is quite common in Japanese - */ + // Note: 0xEF is quite common in Japanese case "\xEF": if ($utf_char == "\xEF\xBF\xBE" || $utf_char == "\xEF\xBF\xBF") { - /** - * U+FFFE and U+FFFF are explicitly disallowed - * (UTF sequence 0xEFBFBE..0xEFBFBF) - */ + // U+FFFE and U+FFFF are explicitly disallowed (UTF sequence 0xEFBFBE..0xEFBFBF) $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); if (!empty($utf_sort)) { ksort($utf_sort); - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } @@ -1667,23 +1252,20 @@ class utf_normalizer $tmp_pos = $starter_pos = $pos; continue 2; } - break; + break; case "\xC0": case "\xC1": if ($utf_char <= "\xC1\xBF") { - /** - * Overlong sequence: Unicode char U+0000..U+007F encoded as a - * double-byte UTF char - */ + // Overlong sequence: Unicode char U+0000..U+007F encoded as a double-byte UTF char $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); if (!empty($utf_sort)) { ksort($utf_sort); - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } @@ -1696,21 +1278,19 @@ class utf_normalizer $tmp_pos = $starter_pos = $pos; continue 2; } - break; + break; case "\xE0": if ($utf_char <= "\xE0\x9F\xBF") { - /** - * Unicode char U+0000..U+07FF encoded in 3 bytes - */ + // Unicode char U+0000..U+07FF encoded in 3 bytes $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); if (!empty($utf_sort)) { ksort($utf_sort); - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } @@ -1723,21 +1303,19 @@ class utf_normalizer $tmp_pos = $starter_pos = $pos; continue 2; } - break; + break; case "\xF0": if ($utf_char <= "\xF0\x8F\xBF\xBF") { - /** - * Unicode char U+0000..U+FFFF encoded in 4 bytes - */ + // Unicode char U+0000..U+FFFF encoded in 4 bytes $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); if (!empty($utf_sort)) { ksort($utf_sort); - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } @@ -1750,21 +1328,19 @@ class utf_normalizer $tmp_pos = $starter_pos = $pos; continue 2; } - break; + break; default: if ($utf_char > UTF8_MAX) { - /** - * Out of the Unicode range - */ + // Out of the Unicode range $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); if (!empty($utf_sort)) { ksort($utf_sort); - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } @@ -1777,25 +1353,18 @@ class utf_normalizer $tmp_pos = $starter_pos = $pos; continue 2; } + break; } } } else { - /** - * Hangul syllable - */ + // Hangul syllable $idx = (((ord($utf_char[0]) & 0x0F) << 12) | ((ord($utf_char[1]) & 0x3F) << 6) | (ord($utf_char[2]) & 0x3F)) - UNICODE_HANGUL_SBASE; - /** - * LIndex can only range from 0 to 18, therefore it cannot influence - * the first two bytes of the L Jamo, which allows us to hardcode - * them (based on LBase). - * - * The same goes for VIndex, but for TIndex there's a catch: the value - * of the third byte could exceed 0xBF and we would have to increment - * the second byte - */ + // LIndex can only range from 0 to 18, therefore it cannot influence the first two bytes of the L Jamo, which allows us to hardcode them (based on LBase). + // + // The same goes for VIndex, but for TIndex there's a catch: the value of the third byte could exceed 0xBF and we would have to increment the second byte if ($tIndex = $idx % UNICODE_HANGUL_TCOUNT) { if ($tIndex < 25) @@ -1817,24 +1386,16 @@ class utf_normalizer $utf_char[2] = chr(0x80 + (int) ($idx / UNICODE_HANGUL_NCOUNT)); $utf_char[5] = chr(0xA1 + (int) (($idx % UNICODE_HANGUL_NCOUNT) / UNICODE_HANGUL_TCOUNT)); - - /** - * Just like other decompositions, the resulting Jamos must - * be dumped to the tmp string - */ + // Just like other decompositions, the resulting Jamos must be dumped to the tmp string $dump = 1; } - /** - * Do we need to dump stuff to the tmp string? - */ + // Do we need to dump stuff to the tmp string? if ($dump) { $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); - /** - * Dump combiners - */ + // Dump combiners if (!empty($utf_sort)) { if ($sort) @@ -1842,7 +1403,7 @@ class utf_normalizer ksort($utf_sort); } - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } @@ -1860,16 +1421,12 @@ class utf_normalizer } else { - /** - * ASCII char, which happens to be a starter (as any other ASCII char) - */ + // ASCII char, which happens to be a starter (as any other ASCII char) if ($dump) { $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); - /** - * Dump combiners - */ + // Dump combiners if (!empty($utf_sort)) { if ($sort) @@ -1877,7 +1434,7 @@ class utf_normalizer ksort($utf_sort); } - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } @@ -1899,18 +1456,14 @@ class utf_normalizer $starter_pos = $pos; } } - while($pos < $len); + while ($pos < $len); - /** - * Now is time to return the string - */ + // Now is time to return the string if ($dump) { $tmp .= substr($str, $tmp_pos, $starter_pos - $tmp_pos); - /** - * Dump combiners - */ + // Dump combiners if (!empty($utf_sort)) { if ($sort) @@ -1918,7 +1471,7 @@ class utf_normalizer ksort($utf_sort); } - foreach($utf_sort as $utf_chars) + foreach ($utf_sort as $utf_chars) { $tmp .= implode('', $utf_chars); } @@ -1927,34 +1480,24 @@ class utf_normalizer return $tmp; } - elseif ($tmp_pos) + else if ($tmp_pos) { - /** - * If the $tmp_pos cursor was moved then at least one character was not in - * normal form. Replace $str with the fixed version - */ + // If the $tmp_pos cursor was moved then at least one character was not in normal form. Replace $str with the fixed version if ($tmp_pos == $len) { - /** - * The $tmp_pos cursor is at the end of $str, therefore $tmp holds - * the whole $str - */ + // The $tmp_pos cursor is at the end of $str, therefore $tmp holds the whole $str return $tmp; } else { - /** - * The rightmost chunk of $str has not been appended to $tmp yet - */ + // The rightmost chunk of $str has not been appended to $tmp yet return $tmp . substr($str, $tmp_pos); } } - /** - * The string was already in normal form - */ + // The string was already in normal form return $str; } } -}
\ No newline at end of file +?>
\ No newline at end of file diff --git a/phpBB/includes/utf/utf_tools.php b/phpBB/includes/utf/utf_tools.php index b3c3c5ed5e..b91fd51c20 100644 --- a/phpBB/includes/utf/utf_tools.php +++ b/phpBB/includes/utf/utf_tools.php @@ -3,42 +3,700 @@ * * @package phpBB3 * @version $Id$ -* @copyright (c) 2005 phpBB Group +* @copyright (c) 2006 phpBB Group * @license http://opensource.org/licenses/gpl-license.php GNU Public License * +* @todo make sure the replacements are called correctly +* already done: strtolower, strtoupper, ucfirst, str_split, strrpos, strlen (hopefully!), strpos, substr +* remaining: clean_username, htmlentities (no longer needed for internal data?), htmlspecialchars (using charset) +* strspn, chr, ord */ /** +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +/** * UTF-8 tools * * Whenever possible, these functions will try to use PHP's built-in functions or * extensions, otherwise they will default to custom routines. * -* If we go with UTF-8 in 3.2, we will also need a Unicode-aware replacement -* to strtolower() -* * @package phpBB3 */ +if (!extension_loaded('xml')) +{ + /** + * Implementation of PHP's native utf8_encode for people without XML support + * This function exploits some nice things that ISO-8859-1 and UTF-8 have in common + * + * @param string $str ISO-8859-1 encoded data + * @return string UTF-8 encoded data + */ + function utf8_encode($str) + { + $out = ''; + for ($i = 0, $len = strlen($str); $i < $len; $i++) + { + $letter = $str[$i]; + $num = ord($letter); + if ($num < 0x80) + { + $out .= $letter; + } + else if ($num < 0xC0) + { + $out .= "\xC2" . $letter; + } + else + { + $out .= "\xC3" . chr($num - 64); + } + } + return $out; + } + + /** + * Implementation of PHP's native utf8_decode for people without XML support + * + * @param string $string UTF-8 encoded data + * @return string ISO-8859-1 encoded data + */ + function utf8_decode($str) + { + $pos = 0; + $len = strlen($str); + $ret = ''; + + while ($pos < $len) + { + $ord = ord($str[$pos]) & 0xF0; + if ($ord === 0xC0 || $ord === 0xD0) + { + $charval = ((ord($str[$pos]) & 0x1F) << 6) | (ord($str[$pos + 1]) & 0x3F); + $pos += 2; + $ret .= (($charval < 256) ? chr($charval) : '?'); + } + else if ($ord === 0xE0) + { + $ret .= '?'; + $pos += 3; + } + else if ($ord === 0xF0) + { + $ret .= '?'; + $pos += 4; + } + else + { + $ret .= $str[$pos]; + ++$pos; + } + } + return $ret; + } +} + +// mbstring is old and has it's functions around for older versions of PHP. +// if mbstring is not loaded, we go into native mode. +if (extension_loaded('mbstring')) +{ + /** + * UTF-8 aware alternative to strrpos + * Find position of last occurrence of a char in a string + * + * Notes: + * - offset for mb_strrpos was added in 5.2.0, we emulate if it is lower + */ + if (version_compare(phpversion(), '5.2.0', '>=')) + { + /** + * UTF-8 aware alternative to strrpos + * @ignore + */ + function utf8_strrpos($str, $needle, $offset = null) + { + // Emulate behaviour of strrpos rather than raising warning + if (empty($str)) + { + return false; + } + + return mb_strrpos($str, $search); + } + } + else + { + /** + * UTF-8 aware alternative to strrpos + * @ignore + */ + function utf8_strrpos($str, $needle, $offset = null) + { + // offset for mb_strrpos was added in 5.2.0 + if ($offset === false) + { + // Emulate behaviour of strrpos rather than raising warning + if (empty($str)) + { + return false; + } + + return mb_strrpos($str, $search); + } + else + { + if (!is_int($offset)) + { + trigger_error('utf8_strrpos expects parameter 3 to be long', E_USER_WARNING); + return false; + } + + $str = mb_substr($str, $offset); + + if (false !== ($pos = mb_strrpos($str, $search))) + { + return $pos + $offset; + } + + return false; + } + } + } + + /** + * UTF-8 aware alternative to strpos + * @ignore + */ + function utf8_strpos($str, $needle, $offset = null) + { + if ($offset === false) + { + return mb_strpos($str, $needle); + } + else + { + return mb_strpos($str, $needle, $offset); + } + } + + /** + * UTF-8 aware alternative to strtolower + * @ignore + */ + function utf8_strtolower($str) + { + return mb_strtolower($str); + } + + /** + * UTF-8 aware alternative to strtoupper + * @ignore + */ + function utf8_strtoupper($str) + { + return mb_strtoupper($str); + } + + /** + * UTF-8 aware alternative to substr + * @ignore + */ + function utf8_substr($str, $offset, $length = null) + { + if ($length === false) + { + return mb_substr($str, $offset); + } + else + { + return mb_substr($str, $offset, $length); + } + } + + /** + * Return the length (in characters) of a UTF-8 string + * @ignore + */ + function utf8_strlen($text) + { + return mb_strlen($text, 'utf-8'); + } +} +else +{ + /** + * UTF-8 aware alternative to strrpos + * Find position of last occurrence of a char in a string + * + * @author Harry Fuecks + * @param string haystack + * @param string needle + * @param integer (optional) offset (from left) + * @return mixed integer position or FALSE on failure + */ + function utf8_strrpos($str, $needle, $offset = null) + { + if (is_null($offset)) + { + $ar = explode($needle, $str); + + if (sizeof($ar) > 1) + { + // Pop off the end of the string where the last match was made + array_pop($ar); + $str = join($needle, $ar); + + return utf8_strlen($str); + } + return false; + } + else + { + if (!is_int($offset)) + { + trigger_error('utf8_strrpos expects parameter 3 to be long', E_USER_WARNING); + return false; + } + + $str = utf8_substr($str, $offset); + + if (false !== ($pos = utf8_strrpos($str, $needle))) + { + return $pos + $offset; + } + + return false; + } + } + + /** + * UTF-8 aware alternative to strpos + * Find position of first occurrence of a string + * + * @author Harry Fuecks + * @param string haystack + * @param string needle + * @param integer offset in characters (from left) + * @return mixed integer position or FALSE on failure + */ + function utf8_strpos($str, $needle, $offset = null) + { + if (is_null($offset)) + { + $ar = explode($needle, $str); + if (sizeof($ar) > 1) + { + return utf8_strlen($ar[0]); + } + return false; + } + else + { + if (!is_int($offset)) + { + trigger_error('utf8_strpos: Offset must be an integer', E_USER_ERROR); + return false; + } + + $str = utf8_substr($str, $offset); + + if (false !== ($pos = utf8_strpos($str, $needle))) + { + return $pos + $offset; + } + + return false; + } + } + + $UTF8_UPPER_TO_LOWER = array( + "\x41" => "\x61", "\x42" => "\x62", "\x43" => "\x63", "\x44" => "\x64", + "\x45" => "\x65", "\x46" => "\x66", "\x47" => "\x67", "\x48" => "\x68", + "\x49" => "\x69", "\x4A" => "\x6A", "\x4B" => "\x6B", "\x4C" => "\x6C", + "\x4D" => "\x6D", "\x4E" => "\x6E", "\x4F" => "\x6F", "\x50" => "\x70", + "\x51" => "\x71", "\x52" => "\x72", "\x53" => "\x73", "\x54" => "\x74", + "\x55" => "\x75", "\x56" => "\x76", "\x57" => "\x77", "\x58" => "\x78", + "\x59" => "\x79", "\x5A" => "\x7A", "\xC3\x80" => "\xC3\xA0", "\xC3\x81" => "\xC3\xA1", + "\xC3\x82" => "\xC3\xA2", "\xC3\x83" => "\xC3\xA3", "\xC3\x84" => "\xC3\xA4", "\xC3\x85" => "\xC3\xA5", + "\xC3\x86" => "\xC3\xA6", "\xC3\x87" => "\xC3\xA7", "\xC3\x88" => "\xC3\xA8", "\xC3\x89" => "\xC3\xA9", + "\xC3\x8A" => "\xC3\xAA", "\xC3\x8B" => "\xC3\xAB", "\xC3\x8C" => "\xC3\xAC", "\xC3\x8D" => "\xC3\xAD", + "\xC3\x8E" => "\xC3\xAE", "\xC3\x8F" => "\xC3\xAF", "\xC3\x90" => "\xC3\xB0", "\xC3\x91" => "\xC3\xB1", + "\xC3\x92" => "\xC3\xB2", "\xC3\x93" => "\xC3\xB3", "\xC3\x94" => "\xC3\xB4", "\xC3\x95" => "\xC3\xB5", + "\xC3\x96" => "\xC3\xB6", "\xC3\x98" => "\xC3\xB8", "\xC3\x99" => "\xC3\xB9", "\xC3\x9A" => "\xC3\xBA", + "\xC3\x9B" => "\xC3\xBB", "\xC3\x9C" => "\xC3\xBC", "\xC3\x9D" => "\xC3\xBD", "\xC3\x9E" => "\xC3\xBE", + "\xC4\x80" => "\xC4\x81", "\xC4\x82" => "\xC4\x83", "\xC4\x84" => "\xC4\x85", "\xC4\x86" => "\xC4\x87", + "\xC4\x88" => "\xC4\x89", "\xC4\x8A" => "\xC4\x8B", "\xC4\x8C" => "\xC4\x8D", "\xC4\x8E" => "\xC4\x8F", + "\xC4\x90" => "\xC4\x91", "\xC4\x92" => "\xC4\x93", "\xC4\x96" => "\xC4\x97", "\xC4\x98" => "\xC4\x99", + "\xC4\x9A" => "\xC4\x9B", "\xC4\x9C" => "\xC4\x9D", "\xC4\x9E" => "\xC4\x9F", "\xC4\xA0" => "\xC4\xA1", + "\xC4\xA2" => "\xC4\xA3", "\xC4\xA4" => "\xC4\xA5", "\xC4\xA6" => "\xC4\xA7", "\xC4\xA8" => "\xC4\xA9", + "\xC4\xAA" => "\xC4\xAB", "\xC4\xAE" => "\xC4\xAF", "\xC4\xB4" => "\xC4\xB5", "\xC4\xB6" => "\xC4\xB7", + "\xC4\xB9" => "\xC4\xBA", "\xC4\xBB" => "\xC4\xBC", "\xC4\xBD" => "\xC4\xBE", "\xC5\x81" => "\xC5\x82", + "\xC5\x83" => "\xC5\x84", "\xC5\x85" => "\xC5\x86", "\xC5\x87" => "\xC5\x88", "\xC5\x8A" => "\xC5\x8B", + "\xC5\x8C" => "\xC5\x8D", "\xC5\x90" => "\xC5\x91", "\xC5\x94" => "\xC5\x95", "\xC5\x96" => "\xC5\x97", + "\xC5\x98" => "\xC5\x99", "\xC5\x9A" => "\xC5\x9B", "\xC5\x9C" => "\xC5\x9D", "\xC5\x9E" => "\xC5\x9F", + "\xC5\xA0" => "\xC5\xA1", "\xC5\xA2" => "\xC5\xA3", "\xC5\xA4" => "\xC5\xA5", "\xC5\xA6" => "\xC5\xA7", + "\xC5\xA8" => "\xC5\xA9", "\xC5\xAA" => "\xC5\xAB", "\xC5\xAC" => "\xC5\xAD", "\xC5\xAE" => "\xC5\xAF", + "\xC5\xB0" => "\xC5\xB1", "\xC5\xB2" => "\xC5\xB3", "\xC5\xB4" => "\xC5\xB5", "\xC5\xB6" => "\xC5\xB7", + "\xC5\xB8" => "\xC3\xBF", "\xC5\xB9" => "\xC5\xBA", "\xC5\xBB" => "\xC5\xBC", "\xC5\xBD" => "\xC5\xBE", + "\xC6\xA0" => "\xC6\xA1", "\xC6\xAF" => "\xC6\xB0", "\xC8\x98" => "\xC8\x99", "\xC8\x9A" => "\xC8\x9B", + "\xCE\x86" => "\xCE\xAC", "\xCE\x88" => "\xCE\xAD", "\xCE\x89" => "\xCE\xAE", "\xCE\x8A" => "\xCE\xAF", + "\xCE\x8C" => "\xCF\x8C", "\xCE\x8E" => "\xCF\x8D", "\xCE\x8F" => "\xCF\x8E", "\xCE\x91" => "\xCE\xB1", + "\xCE\x92" => "\xCE\xB2", "\xCE\x93" => "\xCE\xB3", "\xCE\x94" => "\xCE\xB4", "\xCE\x95" => "\xCE\xB5", + "\xCE\x96" => "\xCE\xB6", "\xCE\x97" => "\xCE\xB7", "\xCE\x98" => "\xCE\xB8", "\xCE\x99" => "\xCE\xB9", + "\xCE\x9A" => "\xCE\xBA", "\xCE\x9B" => "\xCE\xBB", "\xCE\x9C" => "\xCE\xBC", "\xCE\x9D" => "\xCE\xBD", + "\xCE\x9E" => "\xCE\xBE", "\xCE\x9F" => "\xCE\xBF", "\xCE\xA0" => "\xCF\x80", "\xCE\xA1" => "\xCF\x81", + "\xCE\xA3" => "\xCF\x83", "\xCE\xA4" => "\xCF\x84", "\xCE\xA5" => "\xCF\x85", "\xCE\xA6" => "\xCF\x86", + "\xCE\xA7" => "\xCF\x87", "\xCE\xA8" => "\xCF\x88", "\xCE\xA9" => "\xCF\x89", "\xCE\xAA" => "\xCF\x8A", + "\xCE\xAB" => "\xCF\x8B", "\xD0\x81" => "\xD1\x91", "\xD0\x82" => "\xD1\x92", "\xD0\x83" => "\xD1\x93", + "\xD0\x84" => "\xD1\x94", "\xD0\x85" => "\xD1\x95", "\xD0\x86" => "\xD1\x96", "\xD0\x87" => "\xD1\x97", + "\xD0\x88" => "\xD1\x98", "\xD0\x89" => "\xD1\x99", "\xD0\x8A" => "\xD1\x9A", "\xD0\x8B" => "\xD1\x9B", + "\xD0\x8C" => "\xD1\x9C", "\xD0\x8E" => "\xD1\x9E", "\xD0\x8F" => "\xD1\x9F", "\xD0\x90" => "\xD0\xB0", + "\xD0\x91" => "\xD0\xB1", "\xD0\x92" => "\xD0\xB2", "\xD0\x93" => "\xD0\xB3", "\xD0\x94" => "\xD0\xB4", + "\xD0\x95" => "\xD0\xB5", "\xD0\x96" => "\xD0\xB6", "\xD0\x97" => "\xD0\xB7", "\xD0\x98" => "\xD0\xB8", + "\xD0\x99" => "\xD0\xB9", "\xD0\x9A" => "\xD0\xBA", "\xD0\x9B" => "\xD0\xBB", "\xD0\x9C" => "\xD0\xBC", + "\xD0\x9D" => "\xD0\xBD", "\xD0\x9E" => "\xD0\xBE", "\xD0\x9F" => "\xD0\xBF", "\xD0\xA0" => "\xD1\x80", + "\xD0\xA1" => "\xD1\x81", "\xD0\xA2" => "\xD1\x82", "\xD0\xA3" => "\xD1\x83", "\xD0\xA4" => "\xD1\x84", + "\xD0\xA5" => "\xD1\x85", "\xD0\xA6" => "\xD1\x86", "\xD0\xA7" => "\xD1\x87", "\xD0\xA8" => "\xD1\x88", + "\xD0\xA9" => "\xD1\x89", "\xD0\xAA" => "\xD1\x8A", "\xD0\xAB" => "\xD1\x8B", "\xD0\xAC" => "\xD1\x8C", + "\xD0\xAD" => "\xD1\x8D", "\xD0\xAE" => "\xD1\x8E", "\xD0\xAF" => "\xD1\x8F", "\xD2\x90" => "\xD2\x91", + "\xE1\xB8\x82" => "\xE1\xB8\x83", "\xE1\xB8\x8A" => "\xE1\xB8\x8B", "\xE1\xB8\x9E" => "\xE1\xB8\x9F", "\xE1\xB9\x80" => "\xE1\xB9\x81", + "\xE1\xB9\x96" => "\xE1\xB9\x97", "\xE1\xB9\xA0" => "\xE1\xB9\xA1", "\xE1\xB9\xAA" => "\xE1\xB9\xAB", "\xE1\xBA\x80" => "\xE1\xBA\x81", + "\xE1\xBA\x82" => "\xE1\xBA\x83", "\xE1\xBA\x84" => "\xE1\xBA\x85", "\xE1\xBB\xB2" => "\xE1\xBB\xB3" + ); + + $UTF8_LOWER_TO_UPPER = array( + "\x61" => "\x41", "\x62" => "\x42", "\x63" => "\x43", "\x64" => "\x44", + "\x65" => "\x45", "\x66" => "\x46", "\x67" => "\x47", "\x68" => "\x48", + "\x69" => "\x49", "\x6A" => "\x4A", "\x6B" => "\x4B", "\x6C" => "\x4C", + "\x6D" => "\x4D", "\x6E" => "\x4E", "\x6F" => "\x4F", "\x70" => "\x50", + "\x71" => "\x51", "\x72" => "\x52", "\x73" => "\x53", "\x74" => "\x54", + "\x75" => "\x55", "\x76" => "\x56", "\x77" => "\x57", "\x78" => "\x58", + "\x79" => "\x59", "\x7A" => "\x5A", "\xC3\xA0" => "\xC3\x80", "\xC3\xA1" => "\xC3\x81", + "\xC3\xA2" => "\xC3\x82", "\xC3\xA3" => "\xC3\x83", "\xC3\xA4" => "\xC3\x84", "\xC3\xA5" => "\xC3\x85", + "\xC3\xA6" => "\xC3\x86", "\xC3\xA7" => "\xC3\x87", "\xC3\xA8" => "\xC3\x88", "\xC3\xA9" => "\xC3\x89", + "\xC3\xAA" => "\xC3\x8A", "\xC3\xAB" => "\xC3\x8B", "\xC3\xAC" => "\xC3\x8C", "\xC3\xAD" => "\xC3\x8D", + "\xC3\xAE" => "\xC3\x8E", "\xC3\xAF" => "\xC3\x8F", "\xC3\xB0" => "\xC3\x90", "\xC3\xB1" => "\xC3\x91", + "\xC3\xB2" => "\xC3\x92", "\xC3\xB3" => "\xC3\x93", "\xC3\xB4" => "\xC3\x94", "\xC3\xB5" => "\xC3\x95", + "\xC3\xB6" => "\xC3\x96", "\xC3\xB8" => "\xC3\x98", "\xC3\xB9" => "\xC3\x99", "\xC3\xBA" => "\xC3\x9A", + "\xC3\xBB" => "\xC3\x9B", "\xC3\xBC" => "\xC3\x9C", "\xC3\xBD" => "\xC3\x9D", "\xC3\xBE" => "\xC3\x9E", + "\xC3\xBF" => "\xC5\xB8", "\xC4\x81" => "\xC4\x80", "\xC4\x83" => "\xC4\x82", "\xC4\x85" => "\xC4\x84", + "\xC4\x87" => "\xC4\x86", "\xC4\x89" => "\xC4\x88", "\xC4\x8B" => "\xC4\x8A", "\xC4\x8D" => "\xC4\x8C", + "\xC4\x8F" => "\xC4\x8E", "\xC4\x91" => "\xC4\x90", "\xC4\x93" => "\xC4\x92", "\xC4\x97" => "\xC4\x96", + "\xC4\x99" => "\xC4\x98", "\xC4\x9B" => "\xC4\x9A", "\xC4\x9D" => "\xC4\x9C", "\xC4\x9F" => "\xC4\x9E", + "\xC4\xA1" => "\xC4\xA0", "\xC4\xA3" => "\xC4\xA2", "\xC4\xA5" => "\xC4\xA4", "\xC4\xA7" => "\xC4\xA6", + "\xC4\xA9" => "\xC4\xA8", "\xC4\xAB" => "\xC4\xAA", "\xC4\xAF" => "\xC4\xAE", "\xC4\xB5" => "\xC4\xB4", + "\xC4\xB7" => "\xC4\xB6", "\xC4\xBA" => "\xC4\xB9", "\xC4\xBC" => "\xC4\xBB", "\xC4\xBE" => "\xC4\xBD", + "\xC5\x82" => "\xC5\x81", "\xC5\x84" => "\xC5\x83", "\xC5\x86" => "\xC5\x85", "\xC5\x88" => "\xC5\x87", + "\xC5\x8B" => "\xC5\x8A", "\xC5\x8D" => "\xC5\x8C", "\xC5\x91" => "\xC5\x90", "\xC5\x95" => "\xC5\x94", + "\xC5\x97" => "\xC5\x96", "\xC5\x99" => "\xC5\x98", "\xC5\x9B" => "\xC5\x9A", "\xC5\x9D" => "\xC5\x9C", + "\xC5\x9F" => "\xC5\x9E", "\xC5\xA1" => "\xC5\xA0", "\xC5\xA3" => "\xC5\xA2", "\xC5\xA5" => "\xC5\xA4", + "\xC5\xA7" => "\xC5\xA6", "\xC5\xA9" => "\xC5\xA8", "\xC5\xAB" => "\xC5\xAA", "\xC5\xAD" => "\xC5\xAC", + "\xC5\xAF" => "\xC5\xAE", "\xC5\xB1" => "\xC5\xB0", "\xC5\xB3" => "\xC5\xB2", "\xC5\xB5" => "\xC5\xB4", + "\xC5\xB7" => "\xC5\xB6", "\xC5\xBA" => "\xC5\xB9", "\xC5\xBC" => "\xC5\xBB", "\xC5\xBE" => "\xC5\xBD", + "\xC6\xA1" => "\xC6\xA0", "\xC6\xB0" => "\xC6\xAF", "\xC8\x99" => "\xC8\x98", "\xC8\x9B" => "\xC8\x9A", + "\xCE\xAC" => "\xCE\x86", "\xCE\xAD" => "\xCE\x88", "\xCE\xAE" => "\xCE\x89", "\xCE\xAF" => "\xCE\x8A", + "\xCE\xB1" => "\xCE\x91", "\xCE\xB2" => "\xCE\x92", "\xCE\xB3" => "\xCE\x93", "\xCE\xB4" => "\xCE\x94", + "\xCE\xB5" => "\xCE\x95", "\xCE\xB6" => "\xCE\x96", "\xCE\xB7" => "\xCE\x97", "\xCE\xB8" => "\xCE\x98", + "\xCE\xB9" => "\xCE\x99", "\xCE\xBA" => "\xCE\x9A", "\xCE\xBB" => "\xCE\x9B", "\xCE\xBC" => "\xCE\x9C", + "\xCE\xBD" => "\xCE\x9D", "\xCE\xBE" => "\xCE\x9E", "\xCE\xBF" => "\xCE\x9F", "\xCF\x80" => "\xCE\xA0", + "\xCF\x81" => "\xCE\xA1", "\xCF\x83" => "\xCE\xA3", "\xCF\x84" => "\xCE\xA4", "\xCF\x85" => "\xCE\xA5", + "\xCF\x86" => "\xCE\xA6", "\xCF\x87" => "\xCE\xA7", "\xCF\x88" => "\xCE\xA8", "\xCF\x89" => "\xCE\xA9", + "\xCF\x8A" => "\xCE\xAA", "\xCF\x8B" => "\xCE\xAB", "\xCF\x8C" => "\xCE\x8C", "\xCF\x8D" => "\xCE\x8E", + "\xCF\x8E" => "\xCE\x8F", "\xD0\xB0" => "\xD0\x90", "\xD0\xB1" => "\xD0\x91", "\xD0\xB2" => "\xD0\x92", + "\xD0\xB3" => "\xD0\x93", "\xD0\xB4" => "\xD0\x94", "\xD0\xB5" => "\xD0\x95", "\xD0\xB6" => "\xD0\x96", + "\xD0\xB7" => "\xD0\x97", "\xD0\xB8" => "\xD0\x98", "\xD0\xB9" => "\xD0\x99", "\xD0\xBA" => "\xD0\x9A", + "\xD0\xBB" => "\xD0\x9B", "\xD0\xBC" => "\xD0\x9C", "\xD0\xBD" => "\xD0\x9D", "\xD0\xBE" => "\xD0\x9E", + "\xD0\xBF" => "\xD0\x9F", "\xD1\x80" => "\xD0\xA0", "\xD1\x81" => "\xD0\xA1", "\xD1\x82" => "\xD0\xA2", + "\xD1\x83" => "\xD0\xA3", "\xD1\x84" => "\xD0\xA4", "\xD1\x85" => "\xD0\xA5", "\xD1\x86" => "\xD0\xA6", + "\xD1\x87" => "\xD0\xA7", "\xD1\x88" => "\xD0\xA8", "\xD1\x89" => "\xD0\xA9", "\xD1\x8A" => "\xD0\xAA", + "\xD1\x8B" => "\xD0\xAB", "\xD1\x8C" => "\xD0\xAC", "\xD1\x8D" => "\xD0\xAD", "\xD1\x8E" => "\xD0\xAE", + "\xD1\x8F" => "\xD0\xAF", "\xD1\x91" => "\xD0\x81", "\xD1\x92" => "\xD0\x82", "\xD1\x93" => "\xD0\x83", + "\xD1\x94" => "\xD0\x84", "\xD1\x95" => "\xD0\x85", "\xD1\x96" => "\xD0\x86", "\xD1\x97" => "\xD0\x87", + "\xD1\x98" => "\xD0\x88", "\xD1\x99" => "\xD0\x89", "\xD1\x9A" => "\xD0\x8A", "\xD1\x9B" => "\xD0\x8B", + "\xD1\x9C" => "\xD0\x8C", "\xD1\x9E" => "\xD0\x8E", "\xD1\x9F" => "\xD0\x8F", "\xD2\x91" => "\xD2\x90", + "\xE1\xB8\x83" => "\xE1\xB8\x82", "\xE1\xB8\x8B" => "\xE1\xB8\x8A", "\xE1\xB8\x9F" => "\xE1\xB8\x9E", "\xE1\xB9\x81" => "\xE1\xB9\x80", + "\xE1\xB9\x97" => "\xE1\xB9\x96", "\xE1\xB9\xA1" => "\xE1\xB9\xA0", "\xE1\xB9\xAB" => "\xE1\xB9\xAA", "\xE1\xBA\x81" => "\xE1\xBA\x80", + "\xE1\xBA\x83" => "\xE1\xBA\x82", "\xE1\xBA\x85" => "\xE1\xBA\x84", "\xE1\xBB\xB3" => "\xE1\xBB\xB2" + ); + + /** + * UTF-8 aware alternative to strtolower + * Make a string lowercase + * Note: The concept of a characters "case" only exists is some alphabets + * such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does + * not exist in the Chinese alphabet, for example. See Unicode Standard + * Annex #21: Case Mappings + * + * @param string + * @return string string in lowercase + */ + function utf8_strtolower($string) + { + global $UTF8_UPPER_TO_LOWER; + + return strtr($string, $UTF8_UPPER_TO_LOWER); + } + + /** + * UTF-8 aware alternative to strtoupper + * Make a string uppercase + * Note: The concept of a characters "case" only exists is some alphabets + * such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does + * not exist in the Chinese alphabet, for example. See Unicode Standard + * Annex #21: Case Mappings + * + * @param string + * @return string string in uppercase + */ + function utf8_strtoupper($string) + { + global $UTF8_LOWER_TO_UPPER; + + return strtr($string, $UTF8_LOWER_TO_UPPER); + } + + /** + * UTF-8 aware alternative to substr + * Return part of a string given character offset (and optionally length) + * + * Note arguments: comparied to substr - if offset or length are + * not integers, this version will not complain but rather massages them + * into an integer. + * + * Note on returned values: substr documentation states false can be + * returned in some cases (e.g. offset > string length) + * mb_substr never returns false, it will return an empty string instead. + * This adopts the mb_substr approach + * + * Note on implementation: PCRE only supports repetitions of less than + * 65536, in order to accept up to MAXINT values for offset and length, + * we'll repeat a group of 65535 characters when needed. + * + * Note on implementation: calculating the number of characters in the + * string is a relatively expensive operation, so we only carry it out when + * necessary. It isn't necessary for +ve offsets and no specified length + * + * @author Chris Smith<chris@jalakai.co.uk> + * @param string + * @param integer number of UTF-8 characters offset (from left) + * @param integer (optional) length in UTF-8 characters from offset + * @return mixed string or FALSE if failure + */ + function utf8_substr($str, $offset, $length = NULL) + { + // generates E_NOTICE + // for PHP4 objects, but not PHP5 objects + $str = (string) $str; + $offset = (int) $offset; + if (!is_null($length)) + { + $length = (int) $length; + } + + // handle trivial cases + if ($length === 0 || ($offset < 0 && $length < 0 && $length < $offset)) + { + return ''; + } + + // normalise negative offsets (we could use a tail + // anchored pattern, but they are horribly slow!) + if ($offset < 0) + { + // see notes + $strlen = utf8_strlen($str); + $offset = $strlen + $offset; + if ($offset < 0) + { + $offset = 0; + } + } + + $op = ''; + $lp = ''; + + // establish a pattern for offset, a + // non-captured group equal in length to offset + if ($offset > 0) + { + $ox = (int) ($offset / 65535); + $oy = $offset % 65535; + + if ($ox) + { + $op = '(?:.{65535}){' . $ox . '}'; + } + + $op = '^(?:' . $op . '.{' . $oy . '})'; + } + else + { + // offset == 0; just anchor the pattern + $op = '^'; + } + + // establish a pattern for length + if (is_null($length)) + { + // the rest of the string + $lp = '(.*)$'; + } + else + { + if (!isset($strlen)) + { + // see notes + $strlen = utf8_strlen($str); + } + + // another trivial case + if ($offset > $strlen) + { + return ''; + } + + if ($length > 0) + { + // reduce any length that would + // go passed the end of the string + $length = min($strlen - $offset, $length); + + $lx = (int) ($length / 65535); + $ly = $length % 65535; + + // negative length requires a captured group + // of length characters + if ($lx) + { + $lp = '(?:.{65535}){' . $lx . '}'; + } + $lp = '(' . $lp . '.{'. $ly . '})'; + } + else if ($length < 0) + { + if ($length < ($offset - $strlen)) + { + return ''; + } + + $lx = (int)((-$length) / 65535); + $ly = (-$length) % 65535; + + // negative length requires ... capture everything + // except a group of -length characters + // anchored at the tail-end of the string + if ($lx) + { + $lp = '(?:.{65535}){' . $lx . '}'; + } + $lp = '(.*)(?:' . $lp . '.{' . $ly . '})$'; + } + } + + if (!preg_match('#' . $op . $lp . '#us', $str, $match)) + { + return ''; + } + + return $match[1]; + } + + /** + * Return the length (in characters) of a UTF-8 string + * + * @param string $text UTF-8 string + * @return integer Length (in chars) of given string + */ + function utf8_strlen($text) + { + // Since utf8_decode is replacing multibyte characters to ? strlen works fine + return strlen(utf8_decode($text)); + } +} + /** -* Return the length (in characters) of a UTF-8 string -* -* @param string $text UTF-8 string -* @return integer Length (in chars) of given string +* UTF-8 aware alternative to str_split +* Convert a string to an array +* +* @author Harry Fuecks +* @param string UTF-8 encoded +* @param int number to characters to split string by +* @return string characters in string reverses */ -function utf8_strlen($text) +function utf8_str_split($str, $split_len = 1) { - if (function_exists('iconv_strlen')) + if (!preg_match('/^[0-9]+$/', $split_len) || $split_len < 1) { - return iconv_strlen($text, 'utf-8'); + return false; } - if (function_exists('mb_strlen')) + $len = utf8_strlen($str); + if ($len <= $split_len) { - return mb_strlen($text, 'utf-8'); + return array($str); + } + + preg_match_all('/.{' . $split_len . '}|[^\x00]{1,' . $split_len . '}$/us', $str, $ar); + return $ar[0]; +} + +/** +* UTF-8 aware alternative to strcspn +* Find length of initial segment not matching mask +* +* @author Harry Fuecks +* @param string +* @return int +*/ +function utf8_strspn($str, $mask, $start = null, $length = null) +{ + $mask = preg_replace('!([\\\\\\-\\]\\[/^])!', '\\\${1}', $mask); + + if ($start !== null || $length !== null) + { + $str = utf8_substr($str, $start, $length); } - return strlen(utf8_decode($text)); + preg_match('/^[' . $mask . ']+/u', $str, $matches); + + if (isset($matches[0])) + { + return utf8_strlen($matches[0]); + } + + return 0; +} + +/** +* UTF-8 aware alternative to ucfirst +* Make a string's first character uppercase +* +* @author Harry Fuecks +* @param string +* @return string with first character as upper case (if applicable) +*/ +function utf8_ucfirst($str) +{ + switch (utf8_strlen($str)) + { + case 0: + return ''; + break; + + case 1: + return utf8_strtoupper($str); + break; + + default: + preg_match('/^(.{1})(.*)$/us', $str, $matches); + return utf8_strtoupper($matches[1]) . $matches[2]; + break; + } } /** @@ -47,7 +705,7 @@ function utf8_strlen($text) * If the encoding is not supported, the string is returned as-is * * @param string $string Original string -* @param string $encoding Original encoding +* @param string $encoding Original encoding (lowered) * @return string The string, encoded in UTF-8 */ function utf8_recode($string, $encoding) @@ -59,17 +717,13 @@ function utf8_recode($string, $encoding) return $string; } - /** - * PHP has a built-in function for encoding from iso-8859-1, let's use that - */ + // start with something simple if ($encoding == 'iso-8859-1') { return utf8_encode($string); } - /** - * First, try iconv() - */ + // First, try iconv() if (function_exists('iconv')) { $ret = @iconv($encoding, 'utf-8', $string); @@ -80,9 +734,7 @@ function utf8_recode($string, $encoding) } } - /** - * Try the mb_string extension - */ + // Try the mb_string extension if (function_exists('mb_convert_encoding')) { $ret = @mb_convert_encoding($string, 'utf-8', $encoding); @@ -93,9 +745,7 @@ function utf8_recode($string, $encoding) } } - /** - * Try the recode extension - */ + // Try the recode extension if (function_exists('recode_string')) { $ret = @recode_string($encoding . '..utf-8', $string); @@ -106,25 +756,21 @@ function utf8_recode($string, $encoding) } } - /** - * If nothing works, check if we have a custom transcoder available - */ + // If nothing works, check if we have a custom transcoder available if (!preg_match('#^[a-z0-9\\-]+$#', $encoding)) { - /** - * Make sure the encoding name is alphanumeric, we don't want it - * to be abused into loading arbitrary files - */ - trigger_error('Unknown encoding: ' . $encoding); + // Make sure the encoding name is alphanumeric, we don't want it to be abused into loading arbitrary files + trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR); } global $phpbb_root_path; + if (!file_exists($phpbb_root_path . 'includes/utf/data/')) { return $string; } - die('Finish me!! '.basename(__FILE__).' at line '.__LINE__); + die('Finish me!! ' . basename(__FILE__) . ' at line ' . __LINE__); } /** @@ -135,7 +781,7 @@ function utf8_recode($string, $encoding) */ function utf8_encode_ncr($text) { - return preg_replace_callback('#[\\xC2-\\xF4][\\x80-\\xBF]+#', 'utf8_encode_ncr_callback', $text); + return preg_replace_callback('#[\\xC2-\\xF4][\\x80-\\xBF]{1,3}#', 'utf8_encode_ncr_callback', $text); } /** @@ -148,23 +794,64 @@ function utf8_encode_ncr($text) */ function utf8_encode_ncr_callback($m) { - switch (strlen($m[0])) + return '&#' . utf8_ord($m[0]) . ';'; +} + +/** +* Enter description here... +* +* @param string $chr UTF-8 char +* @return integer UNICODE code point +*/ +function utf8_ord($chr) +{ + switch (strlen($chr)) { case 1: - return '&#' . ord($m[0]) . ';'; + return ord($chr); + break; case 2: - return '&#' . (((ord($m[0][0]) & 0x1F) << 6) | (ord($m[0][1]) & 0x3F)) . ';'; + return ((ord($chr[0]) & 0x1F) << 6) | (ord($chr[1]) & 0x3F); + break; case 3: - return '&#' . (((ord($m[0][0]) & 0x0F) << 12) | ((ord($m[0][1]) & 0x3F) << 6) | (ord($m[0][2]) & 0x3F)) . ';'; + return ((ord($chr[0]) & 0x0F) << 12) | ((ord($chr[1]) & 0x3F) << 6) | (ord($chr[2]) & 0x3F); + break; case 4: - return '&#' . (((ord($m[0][0]) & 0x07) << 18) | ((ord($m[0][1]) & 0x3F) << 12) | ((ord($m[0][2]) & 0x3F) << 6) | (ord($m[0][3]) & 0x3F)) . ';'; + return ((ord($chr[0]) & 0x07) << 18) | ((ord($chr[1]) & 0x3F) << 12) | ((ord($chr[2]) & 0x3F) << 6) | (ord($chr[3]) & 0x3F); + break; default: - return $m[0]; - } + return $chr; + } +} + +/** +* Converts an NCR to a UTF-8 char +* +* @param integer $cp UNICODE code point +* @return string UTF-8 char +*/ +function utf8_chr($cp) +{ + if ($cp > 0xFFFF) + { + return chr(0xF0 | ($cp >> 18)) . chr(0x80 | (($cp >> 12) & 0x3F)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F)); + } + else if ($cp > 0x7FF) + { + return chr(0xE0 | ($cp >> 12)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F)); + } + else if ($cp > 0x7F) + { + return chr(0xC0 | ($cp >> 6)) . chr(0x80 | ($cp & 0x3F)); + } + else + { + return chr($cp); + } } /** @@ -196,22 +883,130 @@ function utf8_decode_ncr_callback($m) { $cp = (strncasecmp($m[1], 'x', 1)) ? $m[1] : hexdec(substr($m[1], 1)); - if ($cp > 0xFFFF) + return utf8_chr($cp); +} + +/** +* Takes an array of ints representing the Unicode characters and returns +* a UTF-8 string. +* +* @param string $text text to be case folded +* @param string $option determines how we will fold the cases +* @return string case folded text +*/ +function utf8_case_fold($text, $option = 'full') +{ + static $uniarray = array(); + global $phpbb_root_path, $phpEx; + + // common is always set + if (!isset($uniarray['c'])) { - return chr(0xF0 | ($cp >> 18)) . chr(0x80 | (($cp >> 12) & 0x3F)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F)); + $uniarray['c'] = include($phpbb_root_path . 'includes/utf/data/case_fold_c.' . $phpEx); } - elseif ($cp > 0x7FF) + + // only set full if we need to + if ($option === 'full' && !isset($uniarray['f'])) { - return chr(0xE0 | ($cp >> 12)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F)); + $uniarray['f'] = include($phpbb_root_path . 'includes/utf/data/case_fold_f.' . $phpEx); } - elseif ($cp > 0x7F) + + // only set simple if we need to + if ($option !== 'full' && !isset($uniarray['s'])) { - return chr(0xC0 | ($cp >> 6)) . chr(0x80 | ($cp & 0x3F)); + $uniarray['s'] = include($phpbb_root_path . 'includes/utf/data/case_fold_s.' . $phpEx); + } + + $text = strtr($text, $uniarray['c']); + if ($option === 'full') + { + $text = strtr($text, $uniarray['f']); } else { - return chr($cp); + $text = strtr($text, $uniarray['s']); } + return $text; +} + +/** +* A wrapper function for the normalizer which takes care of including the class if required and modifies the passed strings +* to be in NFC (Normalization Form Composition). +* +* @param mixed $strings Either an array of references to strings, a reference to an array of strings or a reference to a single string +*/ +function utf8_normalize_nfc($strings) +{ + if (!is_array($strings) || (sizeof($strings) > 0)) + { + if (!class_exists('utf_normalizer')) + { + global $phpbb_root_path, $phpEx; + include($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx); + } + + if (is_array($strings)) + { + foreach ($strings as $key => $string) + { + $strings[$key] = utf_normalizer::nfc($strings[$key]); + } + } + else + { + $strings = utf_normalizer::nfc($strings); + } + } +} + +/** +* This function is used to generate a "clean" version of a string. +* Clean means that it is a case insensitive form (case folding) and that it is normalized (NFC). +* Additionally a homographs of one character are transformed into one specific character (preferably ASCII +* if it is an ASCII character). +* +* Please be aware that if you change something within this function or within +* functions used here you need to rebuild/update the username_clean column in the users table. And all other +* columns that store a clean string otherwise you will break this functionality. +* +* @param $text An unclean string, mabye user input (has to be valid UTF-8!) +* @return Cleaned up version of the input string +*/ +function utf8_clean_string($text) +{ + $text = utf8_case_fold($text); + + if (!class_exists('utf_normalizer')) + { + global $phpbb_root_path, $phpEx; + include($phpbb_root_path . 'includes/utf/utf_normalizer.' . $phpEx); + } + + $text = utf_normalizer::nfc($text); + + static $homographs = array( + // cyrllic + "\xD0\xB0" => "\x61", + "\xD0\xB5" => "\x65", + "\xD0\xBE" => "\x6F", + "\xD1\x80" => "\x70", + "\xD1\x81" => "\x63", + "\xD1\x83" => "\x79", + "\xD1\x85" => "\x78", + "\xD1\x95" => "\x73", + "\xD1\x96" => "\x69", + "\xD1\x98" => "\x6A", + "\xD2\xBB" => "\x68", + // greek + "\xCE\xB1" => "\x61", + "\xCE\xBF" => "\x6F", + // other + "\xC2\xA1" => "\x69", + ); + + $text = strtr($text, $homographs); + + return $text; } ?>
\ No newline at end of file |
