First commit of smf_2-0-7_upgrade.tar.bz2

This commit is contained in:
Travis Burtrum 2014-02-03 21:58:48 -05:00
commit be85b7ae06
1014 changed files with 184956 additions and 0 deletions

12
.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
# backup files
**~
**.bak
# settings files
Settings.php
Settings_bak.php
# things that change
attachments/
avatars/
cache/

5
Packages/.htaccess Normal file
View File

@ -0,0 +1,5 @@
<Files *>
Order Deny,Allow
Deny from all
Allow from localhost
</Files>

View File

@ -0,0 +1,5 @@
<Files *>
Order Deny,Allow
Deny from all
Allow from localhost
</Files>

View File

@ -0,0 +1,9 @@
<?php
// Try to handle it with the upper level index.php. (it should know what to do.)
if (file_exists(dirname(dirname(__FILE__)) . '/index.php'))
include (dirname(dirname(__FILE__)) . '/index.php');
else
exit;
?>

16
Packages/index.php Normal file
View File

@ -0,0 +1,16 @@
<?php
// This file is here solely to protect your Packages directory.
// Look for Settings.php....
if (file_exists(dirname(dirname(__FILE__)) . '/Settings.php'))
{
// Found it!
require(dirname(dirname(__FILE__)) . '/Settings.php');
header('Location: ' . $boardurl);
}
// Can't find it... just forget it.
else
exit;
?>

0
Packages/installed.list Normal file
View File

1999
SSI.php Normal file

File diff suppressed because it is too large Load Diff

62
Settings.orig.php Normal file
View File

@ -0,0 +1,62 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
########## Maintenance ##########
# Note: If $maintenance is set to 2, the forum will be unusable! Change it to 0 to fix it.
$maintenance = 0; # Set to 1 to enable Maintenance Mode, 2 to make the forum untouchable. (you'll have to make it 0 again manually!)
$mtitle = 'Maintenance Mode'; # Title for the Maintenance Mode message.
$mmessage = 'Okay faithful users...we\'re attempting to restore an older backup of the database...news will be posted once we\'re back!'; # Description of why the forum is in maintenance mode.
########## Forum Info ##########
$mbname = 'My Community'; # The name of your forum.
$language = 'english'; # The default language file set for the forum.
$boardurl = 'http://127.0.0.1/smf'; # URL to your forum's folder. (without the trailing /!)
$webmaster_email = 'noreply@myserver.com'; # Email address to send emails from. (like noreply@yourdomain.com.)
$cookiename = 'SMFCookie11'; # Name of the cookie to set for authentication.
########## Database Info ##########
$db_type = 'mysql';
$db_server = 'localhost';
$db_name = 'smf';
$db_user = 'root';
$db_passwd = '';
$ssi_db_user = '';
$ssi_db_passwd = '';
$db_prefix = 'smf_';
$db_persist = 0;
$db_error_send = 1;
########## Directories/Files ##########
# Note: These directories do not have to be changed unless you move things.
$boarddir = dirname(__FILE__); # The absolute path to the forum's folder. (not just '.'!)
$sourcedir = dirname(__FILE__) . '/Sources'; # Path to the Sources directory.
$cachedir = dirname(__FILE__) . '/cache'; # Path to the cache directory.
########## Error-Catching ##########
# Note: You shouldn't touch these settings.
$db_last_error = 0;
if (file_exists(dirname(__FILE__) . '/install.php'))
{
header('Location: http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on' ? 's' : '') . '://' . (empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST']) . (strtr(dirname($_SERVER['PHP_SELF']), '\\', '/') == '/' ? '' : strtr(dirname($_SERVER['PHP_SELF']), '\\', '/')) . '/install.php'); exit;
}
# Make sure the paths are correct... at least try to fix them.
if (!file_exists($boarddir) && file_exists(dirname(__FILE__) . '/agreement.txt'))
$boarddir = dirname(__FILE__);
if (!file_exists($sourcedir) && file_exists($boarddir . '/Sources'))
$sourcedir = $boarddir . '/Sources';
if (!file_exists($cachedir) && file_exists($boarddir . '/cache'))
$cachedir = $boarddir . '/cache';
?>

BIN
Smileys/aaron/afro.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

BIN
Smileys/aaron/angel.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

BIN
Smileys/aaron/angry.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

BIN
Smileys/aaron/azn.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

BIN
Smileys/aaron/blank.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

BIN
Smileys/aaron/cheesy.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

BIN
Smileys/aaron/cool.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

BIN
Smileys/aaron/cry.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

BIN
Smileys/aaron/evil.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

BIN
Smileys/aaron/grin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

BIN
Smileys/aaron/huh.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

9
Smileys/aaron/index.php Normal file
View File

@ -0,0 +1,9 @@
<?php
// Try to handle it with the upper level index.php. (it should know what to do.)
if (file_exists(dirname(dirname(__FILE__)) . '/index.php'))
include (dirname(dirname(__FILE__)) . '/index.php');
else
exit;
?>

BIN
Smileys/aaron/kiss.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

BIN
Smileys/aaron/laugh.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

BIN
Smileys/aaron/police.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

BIN
Smileys/aaron/rolleyes.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

BIN
Smileys/aaron/sad.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

BIN
Smileys/aaron/shocked.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

BIN
Smileys/aaron/smiley.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

BIN
Smileys/aaron/tongue.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 B

BIN
Smileys/aaron/undecided.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

BIN
Smileys/aaron/wink.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

BIN
Smileys/akyhne/afro.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/angel.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/angry.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/azn.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/blank.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

BIN
Smileys/akyhne/cheesy.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/cool.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/cry.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/evil.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/grin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/huh.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

9
Smileys/akyhne/index.php Normal file
View File

@ -0,0 +1,9 @@
<?php
// Try to handle it with the upper level index.php. (it should know what to do.)
if (file_exists(dirname(dirname(__FILE__)) . '/index.php'))
include (dirname(dirname(__FILE__)) . '/index.php');
else
exit;
?>

BIN
Smileys/akyhne/kiss.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/laugh.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/police.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/rolleyes.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/sad.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/shocked.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/smiley.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/tongue.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/akyhne/wink.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/default/afro.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Smileys/default/angel.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 B

BIN
Smileys/default/angry.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 B

BIN
Smileys/default/azn.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

BIN
Smileys/default/blank.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

BIN
Smileys/default/cheesy.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 B

BIN
Smileys/default/cool.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 B

BIN
Smileys/default/cry.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1017 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 B

BIN
Smileys/default/evil.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

BIN
Smileys/default/grin.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1001 B

BIN
Smileys/default/huh.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

View File

@ -0,0 +1,9 @@
<?php
// Try to handle it with the upper level index.php. (it should know what to do.)
if (file_exists(dirname(dirname(__FILE__)) . '/index.php'))
include (dirname(dirname(__FILE__)) . '/index.php');
else
exit;
?>

BIN
Smileys/default/kiss.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 B

BIN
Smileys/default/laugh.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 B

BIN
Smileys/default/police.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

BIN
Smileys/default/sad.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1009 B

BIN
Smileys/default/shocked.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 B

BIN
Smileys/default/smiley.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1009 B

BIN
Smileys/default/tongue.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

BIN
Smileys/default/wink.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1004 B

16
Smileys/index.php Normal file
View File

@ -0,0 +1,16 @@
<?php
// This file is here solely to protect your Smileys directory.
// Look for Settings.php....
if (file_exists(dirname(dirname(__FILE__)) . '/Settings.php'))
{
// Found it!
require(dirname(dirname(__FILE__)) . '/Settings.php');
header('Location: ' . $boardurl);
}
// Can't find it... just forget it.
else
exit;
?>

999
Sources/Admin.php Normal file
View File

@ -0,0 +1,999 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines
*
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file, unpredictable as this might be, handles basic administration.
void AdminMain()
- initialises all the basic context required for the admin center.
- passes execution onto the relevant admin section.
- if the passed section is not found it shows the admin home page.
void AdminHome()
- prepares all the data necessary for the administration front page.
- uses the Admin template along with the admin sub template.
- requires the moderate_forum, manage_membergroups, manage_bans,
admin_forum, manage_permissions, manage_attachments, manage_smileys,
manage_boards, edit_news, or send_mail permission.
- uses the index administrative area.
- can be found by going to ?action=admin.
void AdminSearch()
- allocates out all the search stuff.
void AdminSearchInternal()
- a complicated but relatively quick internal search.
void AdminSearchMember()
- pass through to manage members.
void DisplayAdminFile()
- get one of the admin information files from Simple Machines.
*/
// The main admin handling function.
function AdminMain()
{
global $txt, $context, $scripturl, $sc, $modSettings, $user_info, $settings, $sourcedir, $options, $smcFunc, $boarddir;
// Load the language and templates....
loadLanguage('Admin');
loadTemplate('Admin', 'admin');
// No indexing evil stuff.
$context['robot_no_index'] = true;
require_once($sourcedir . '/Subs-Menu.php');
// Some preferences.
$context['admin_preferences'] = !empty($options['admin_preferences']) ? unserialize($options['admin_preferences']) : array();
// Define all the menu structure - see Subs-Menu.php for details!
$admin_areas = array(
'forum' => array(
'title' => $txt['admin_main'],
'permission' => array('admin_forum', 'manage_permissions', 'moderate_forum', 'manage_membergroups', 'manage_bans', 'send_mail', 'edit_news', 'manage_boards', 'manage_smileys', 'manage_attachments'),
'areas' => array(
'index' => array(
'label' => $txt['admin_center'],
'function' => 'AdminHome',
'icon' => 'administration.gif',
),
'credits' => array(
'label' => $txt['support_credits_title'],
'function' => 'AdminHome',
'icon' => 'support.gif',
),
'news' => array(
'label' => $txt['news_title'],
'file' => 'ManageNews.php',
'function' => 'ManageNews',
'icon' => 'news.gif',
'permission' => array('edit_news', 'send_mail', 'admin_forum'),
'subsections' => array(
'editnews' => array($txt['admin_edit_news'], 'edit_news'),
'mailingmembers' => array($txt['admin_newsletters'], 'send_mail'),
'settings' => array($txt['settings'], 'admin_forum'),
),
),
'packages' => array(
'label' => $txt['package'],
'file' => 'Packages.php',
'function' => 'Packages',
'permission' => array('admin_forum'),
'icon' => 'packages.gif',
'subsections' => array(
'browse' => array($txt['browse_packages']),
'packageget' => array($txt['download_packages'], 'url' => $scripturl . '?action=admin;area=packages;sa=packageget;get'),
'installed' => array($txt['installed_packages']),
'perms' => array($txt['package_file_perms']),
'options' => array($txt['package_settings']),
),
),
'search' => array(
'function' => 'AdminSearch',
'permission' => array('admin_forum'),
'select' => 'index'
),
),
),
'config' => array(
'title' => $txt['admin_config'],
'permission' => array('admin_forum'),
'areas' => array(
'corefeatures' => array(
'label' => $txt['core_settings_title'],
'file' => 'ManageSettings.php',
'function' => 'ModifyCoreFeatures',
'icon' => 'corefeatures.gif',
),
'featuresettings' => array(
'label' => $txt['modSettings_title'],
'file' => 'ManageSettings.php',
'function' => 'ModifyFeatureSettings',
'icon' => 'features.gif',
'subsections' => array(
'basic' => array($txt['mods_cat_features']),
'layout' => array($txt['mods_cat_layout']),
'karma' => array($txt['karma'], 'enabled' => in_array('k', $context['admin_features'])),
'sig' => array($txt['signature_settings_short']),
'profile' => array($txt['custom_profile_shorttitle'], 'enabled' => in_array('cp', $context['admin_features'])),
),
),
'securitysettings' => array(
'label' => $txt['admin_security_moderation'],
'file' => 'ManageSettings.php',
'function' => 'ModifySecuritySettings',
'icon' => 'security.gif',
'subsections' => array(
'general' => array($txt['mods_cat_security_general']),
'spam' => array($txt['antispam_title']),
'moderation' => array($txt['moderation_settings_short'], 'enabled' => substr($modSettings['warning_settings'], 0, 1) == 1),
),
),
'languages' => array(
'label' => $txt['language_configuration'],
'file' => 'ManageServer.php',
'function' => 'ManageLanguages',
'icon' => 'languages.gif',
'subsections' => array(
'edit' => array($txt['language_edit']),
'add' => array($txt['language_add']),
'settings' => array($txt['language_settings']),
),
),
'serversettings' => array(
'label' => $txt['admin_server_settings'],
'file' => 'ManageServer.php',
'function' => 'ModifySettings',
'icon' => 'server.gif',
'subsections' => array(
'general' => array($txt['general_settings']),
'database' => array($txt['database_paths_settings']),
'cookie' => array($txt['cookies_sessions_settings']),
'cache' => array($txt['caching_settings']),
'loads' => array($txt['load_balancing_settings']),
),
),
'current_theme' => array(
'label' => $txt['theme_current_settings'],
'file' => 'Themes.php',
'function' => 'ThemesMain',
'custom_url' => $scripturl . '?action=admin;area=theme;sa=settings;th=' . $settings['theme_id'],
'icon' => 'current_theme.gif',
),
'theme' => array(
'label' => $txt['theme_admin'],
'file' => 'Themes.php',
'function' => 'ThemesMain',
'custom_url' => $scripturl . '?action=admin;area=theme;sa=admin',
'icon' => 'themes.gif',
'subsections' => array(
'admin' => array($txt['themeadmin_admin_title']),
'list' => array($txt['themeadmin_list_title']),
'reset' => array($txt['themeadmin_reset_title']),
'edit' => array($txt['themeadmin_edit_title']),
),
),
'modsettings' => array(
'label' => $txt['admin_modifications'],
'file' => 'ManageSettings.php',
'function' => 'ModifyModSettings',
'icon' => 'modifications.gif',
'subsections' => array(
'general' => array($txt['mods_cat_modifications_misc']),
// Mod Authors for a "ADD AFTER" on this line. Ensure you end your change with a comma. For example:
// 'shout' => array($txt['shout']),
// Note the comma!! The setting with automatically appear with the first mod to be added.
),
),
),
),
'layout' => array(
'title' => $txt['layout_controls'],
'permission' => array('manage_boards', 'admin_forum', 'manage_smileys', 'manage_attachments', 'moderate_forum'),
'areas' => array(
'manageboards' => array(
'label' => $txt['admin_boards'],
'file' => 'ManageBoards.php',
'function' => 'ManageBoards',
'icon' => 'boards.gif',
'permission' => array('manage_boards'),
'subsections' => array(
'main' => array($txt['boardsEdit']),
'newcat' => array($txt['mboards_new_cat']),
'settings' => array($txt['settings'], 'admin_forum'),
),
),
'postsettings' => array(
'label' => $txt['manageposts'],
'file' => 'ManagePosts.php',
'function' => 'ManagePostSettings',
'permission' => array('admin_forum'),
'icon' => 'posts.gif',
'subsections' => array(
'posts' => array($txt['manageposts_settings']),
'bbc' => array($txt['manageposts_bbc_settings']),
'censor' => array($txt['admin_censored_words']),
'topics' => array($txt['manageposts_topic_settings']),
),
),
'managecalendar' => array(
'label' => $txt['manage_calendar'],
'file' => 'ManageCalendar.php',
'function' => 'ManageCalendar',
'icon' => 'calendar.gif',
'permission' => array('admin_forum'),
'enabled' => in_array('cd', $context['admin_features']),
'subsections' => array(
'holidays' => array($txt['manage_holidays'], 'admin_forum', 'enabled' => !empty($modSettings['cal_enabled'])),
'settings' => array($txt['calendar_settings'], 'admin_forum'),
),
),
'managesearch' => array(
'label' => $txt['manage_search'],
'file' => 'ManageSearch.php',
'function' => 'ManageSearch',
'icon' => 'search.gif',
'permission' => array('admin_forum'),
'subsections' => array(
'weights' => array($txt['search_weights']),
'method' => array($txt['search_method']),
'settings' => array($txt['settings']),
),
),
'smileys' => array(
'label' => $txt['smileys_manage'],
'file' => 'ManageSmileys.php',
'function' => 'ManageSmileys',
'icon' => 'smiley.gif',
'permission' => array('manage_smileys'),
'subsections' => array(
'editsets' => array($txt['smiley_sets']),
'addsmiley' => array($txt['smileys_add'], 'enabled' => !empty($modSettings['smiley_enable'])),
'editsmileys' => array($txt['smileys_edit'], 'enabled' => !empty($modSettings['smiley_enable'])),
'setorder' => array($txt['smileys_set_order'], 'enabled' => !empty($modSettings['smiley_enable'])),
'editicons' => array($txt['icons_edit_message_icons'], 'enabled' => !empty($modSettings['messageIcons_enable'])),
'settings' => array($txt['settings']),
),
),
'manageattachments' => array(
'label' => $txt['attachments_avatars'],
'file' => 'ManageAttachments.php',
'function' => 'ManageAttachments',
'icon' => 'attachment.gif',
'permission' => array('manage_attachments'),
'subsections' => array(
'browse' => array($txt['attachment_manager_browse']),
'attachments' => array($txt['attachment_manager_settings']),
'avatars' => array($txt['attachment_manager_avatar_settings']),
'maintenance' => array($txt['attachment_manager_maintenance']),
),
),
),
),
'members' => array(
'title' => $txt['admin_manage_members'],
'permission' => array('moderate_forum', 'manage_membergroups', 'manage_bans', 'manage_permissions', 'admin_forum'),
'areas' => array(
'viewmembers' => array(
'label' => $txt['admin_users'],
'file' => 'ManageMembers.php',
'function' => 'ViewMembers',
'icon' => 'members.gif',
'permission' => array('moderate_forum'),
'subsections' => array(
'all' => array($txt['view_all_members']),
'search' => array($txt['mlist_search']),
),
),
'membergroups' => array(
'label' => $txt['admin_groups'],
'file' => 'ManageMembergroups.php',
'function' => 'ModifyMembergroups',
'icon' => 'membergroups.gif',
'permission' => array('manage_membergroups'),
'subsections' => array(
'index' => array($txt['membergroups_edit_groups'], 'manage_membergroups'),
'add' => array($txt['membergroups_new_group'], 'manage_membergroups'),
'settings' => array($txt['settings'], 'admin_forum'),
),
),
'permissions' => array(
'label' => $txt['edit_permissions'],
'file' => 'ManagePermissions.php',
'function' => 'ModifyPermissions',
'icon' => 'permissions.gif',
'permission' => array('manage_permissions'),
'subsections' => array(
'index' => array($txt['permissions_groups'], 'manage_permissions'),
'board' => array($txt['permissions_boards'], 'manage_permissions'),
'profiles' => array($txt['permissions_profiles'], 'manage_permissions'),
'postmod' => array($txt['permissions_post_moderation'], 'manage_permissions', 'enabled' => $modSettings['postmod_active']),
'settings' => array($txt['settings'], 'admin_forum'),
),
),
'regcenter' => array(
'label' => $txt['registration_center'],
'file' => 'ManageRegistration.php',
'function' => 'RegCenter',
'icon' => 'regcenter.gif',
'permission' => array('admin_forum', 'moderate_forum'),
'subsections' => array(
'register' => array($txt['admin_browse_register_new'], 'moderate_forum'),
'agreement' => array($txt['registration_agreement'], 'admin_forum'),
'reservednames' => array($txt['admin_reserved_set'], 'admin_forum'),
'settings' => array($txt['settings'], 'admin_forum'),
),
),
'ban' => array(
'label' => $txt['ban_title'],
'file' => 'ManageBans.php',
'function' => 'Ban',
'icon' => 'ban.gif',
'permission' => 'manage_bans',
'subsections' => array(
'list' => array($txt['ban_edit_list']),
'add' => array($txt['ban_add_new']),
'browse' => array($txt['ban_trigger_browse']),
'log' => array($txt['ban_log']),
),
),
'paidsubscribe' => array(
'label' => $txt['paid_subscriptions'],
'enabled' => in_array('ps', $context['admin_features']),
'file' => 'ManagePaid.php',
'icon' => 'paid.gif',
'function' => 'ManagePaidSubscriptions',
'permission' => 'admin_forum',
'subsections' => array(
'view' => array($txt['paid_subs_view']),
'settings' => array($txt['settings']),
),
),
'sengines' => array(
'label' => $txt['search_engines'],
'enabled' => in_array('sp', $context['admin_features']),
'file' => 'ManageSearchEngines.php',
'icon' => 'engines.gif',
'function' => 'SearchEngines',
'permission' => 'admin_forum',
'subsections' => array(
'stats' => array($txt['spider_stats']),
'logs' => array($txt['spider_logs']),
'spiders' => array($txt['spiders']),
'settings' => array($txt['settings']),
),
),
),
),
'maintenance' => array(
'title' => $txt['admin_maintenance'],
'permission' => array('admin_forum'),
'areas' => array(
'maintain' => array(
'label' => $txt['maintain_title'],
'file' => 'ManageMaintenance.php',
'icon' => 'maintain.gif',
'function' => 'ManageMaintenance',
'subsections' => array(
'routine' => array($txt['maintain_sub_routine'], 'admin_forum'),
'database' => array($txt['maintain_sub_database'], 'admin_forum'),
'members' => array($txt['maintain_sub_members'], 'admin_forum'),
'topics' => array($txt['maintain_sub_topics'], 'admin_forum'),
),
),
'scheduledtasks' => array(
'label' => $txt['maintain_tasks'],
'file' => 'ManageScheduledTasks.php',
'icon' => 'scheduled.gif',
'function' => 'ManageScheduledTasks',
'subsections' => array(
'tasks' => array($txt['maintain_tasks'], 'admin_forum'),
'tasklog' => array($txt['scheduled_log'], 'admin_forum'),
),
),
'mailqueue' => array(
'label' => $txt['mailqueue_title'],
'file' => 'ManageMail.php',
'function' => 'ManageMail',
'icon' => 'mail.gif',
'subsections' => array(
'browse' => array($txt['mailqueue_browse'], 'admin_forum'),
'settings' => array($txt['mailqueue_settings'], 'admin_forum'),
),
),
'reports' => array(
'enabled' => in_array('rg', $context['admin_features']),
'label' => $txt['generate_reports'],
'file' => 'Reports.php',
'function' => 'ReportsMain',
'icon' => 'reports.gif',
),
'logs' => array(
'label' => $txt['logs'],
'function' => 'AdminLogs',
'icon' => 'logs.gif',
'subsections' => array(
'errorlog' => array($txt['errlog'], 'admin_forum', 'enabled' => !empty($modSettings['enableErrorLogging']), 'url' => $scripturl . '?action=admin;area=logs;sa=errorlog;desc'),
'adminlog' => array($txt['admin_log'], 'admin_forum', 'enabled' => in_array('ml', $context['admin_features'])),
'modlog' => array($txt['moderation_log'], 'admin_forum', 'enabled' => in_array('ml', $context['admin_features'])),
'banlog' => array($txt['ban_log'], 'manage_bans'),
'spiderlog' => array($txt['spider_logs'], 'admin_forum', 'enabled' => in_array('sp', $context['admin_features'])),
'tasklog' => array($txt['scheduled_log'], 'admin_forum'),
'pruning' => array($txt['pruning_title'], 'admin_forum'),
),
),
'repairboards' => array(
'label' => $txt['admin_repair'],
'file' => 'RepairBoards.php',
'function' => 'RepairBoards',
'select' => 'maintain',
'hidden' => true,
),
),
),
);
// Any files to include for administration?
if (!empty($modSettings['integrate_admin_include']))
{
$admin_includes = explode(',', $modSettings['integrate_admin_include']);
foreach ($admin_includes as $include)
{
$include = strtr(trim($include), array('$boarddir' => $boarddir, '$sourcedir' => $sourcedir, '$themedir' => $settings['theme_dir']));
if (file_exists($include))
require_once($include);
}
}
// Let them modify admin areas easily.
call_integration_hook('integrate_admin_areas', array(&$admin_areas));
// Make sure the administrator has a valid session...
validateSession();
// Actually create the menu!
$admin_include_data = createMenu($admin_areas);
unset($admin_areas);
// Nothing valid?
if ($admin_include_data == false)
fatal_lang_error('no_access', false);
// Build the link tree.
$context['linktree'][] = array(
'url' => $scripturl . '?action=admin',
'name' => $txt['admin_center'],
);
if (isset($admin_include_data['current_area']) && $admin_include_data['current_area'] != 'index')
$context['linktree'][] = array(
'url' => $scripturl . '?action=admin;area=' . $admin_include_data['current_area'] . ';' . $context['session_var'] . '=' . $context['session_id'],
'name' => $admin_include_data['label'],
);
if (!empty($admin_include_data['current_subsection']) && $admin_include_data['subsections'][$admin_include_data['current_subsection']][0] != $admin_include_data['label'])
$context['linktree'][] = array(
'url' => $scripturl . '?action=admin;area=' . $admin_include_data['current_area'] . ';sa=' . $admin_include_data['current_subsection'] . ';' . $context['session_var'] . '=' . $context['session_id'],
'name' => $admin_include_data['subsections'][$admin_include_data['current_subsection']][0],
);
// Make a note of the Unique ID for this menu.
$context['admin_menu_id'] = $context['max_menu_id'];
$context['admin_menu_name'] = 'menu_data_' . $context['admin_menu_id'];
// Why on the admin are we?
$context['admin_area'] = $admin_include_data['current_area'];
// Now - finally - call the right place!
if (isset($admin_include_data['file']))
require_once($sourcedir . '/' . $admin_include_data['file']);
$admin_include_data['function']();
}
// The main administration section.
function AdminHome()
{
global $sourcedir, $forum_version, $txt, $scripturl, $context, $user_info, $boardurl, $modSettings, $smcFunc;
// You have to be able to do at least one of the below to see this page.
isAllowedTo(array('admin_forum', 'manage_permissions', 'moderate_forum', 'manage_membergroups', 'manage_bans', 'send_mail', 'edit_news', 'manage_boards', 'manage_smileys', 'manage_attachments'));
// Find all of this forum's administrators...
require_once($sourcedir . '/Subs-Membergroups.php');
if (listMembergroupMembers_Href($context['administrators'], 1, 32) && allowedTo('manage_membergroups'))
{
// Add a 'more'-link if there are more than 32.
$context['more_admins_link'] = '<a href="' . $scripturl . '?action=moderate;area=viewgroups;sa=members;group=1">' . $txt['more'] . '</a>';
}
// Load the credits stuff.
require_once($sourcedir . '/Who.php');
Credits(true);
// This makes it easier to get the latest news with your time format.
$context['time_format'] = urlencode($user_info['time_format']);
$context['current_versions'] = array(
'php' => array('title' => $txt['support_versions_php'], 'version' => PHP_VERSION),
'db' => array('title' => sprintf($txt['support_versions_db'], $smcFunc['db_title']), 'version' => ''),
'server' => array('title' => $txt['support_versions_server'], 'version' => $_SERVER['SERVER_SOFTWARE']),
);
$context['forum_version'] = $forum_version;
// Get a list of current server versions.
require_once($sourcedir . '/Subs-Admin.php');
$checkFor = array(
'gd',
'db_server',
'mmcache',
'eaccelerator',
'phpa',
'apc',
'memcache',
'xcache',
'php',
'server',
);
$context['current_versions'] = getServerVersions($checkFor);
$context['can_admin'] = allowedTo('admin_forum');
$context['sub_template'] = $context['admin_area'] == 'credits' ? 'credits' : 'admin';
$context['page_title'] = $context['admin_area'] == 'credits' ? $txt['support_credits_title'] : $txt['admin_center'];
// The format of this array is: permission, action, title, description, icon.
$quick_admin_tasks = array(
array('', 'credits', 'support_credits_title', 'support_credits_info', 'support_and_credits.png'),
array('admin_forum', 'featuresettings', 'modSettings_title', 'modSettings_info', 'features_and_options.png'),
array('admin_forum', 'maintain', 'maintain_title', 'maintain_info', 'forum_maintenance.png'),
array('manage_permissions', 'permissions', 'edit_permissions', 'edit_permissions_info', 'permissions.png'),
array('admin_forum', 'theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id'], 'theme_admin', 'theme_admin_info', 'themes_and_layout.png'),
array('admin_forum', 'packages', 'package', 'package_info', 'packages.png'),
array('manage_smileys', 'smileys', 'smileys_manage', 'smileys_manage_info', 'smilies_and_messageicons.png'),
array('moderate_forum', 'viewmembers', 'admin_users', 'member_center_info', 'members.png'),
);
$context['quick_admin_tasks'] = array();
foreach ($quick_admin_tasks as $task)
{
if (!empty($task[0]) && !allowedTo($task[0]))
continue;
$context['quick_admin_tasks'][] = array(
'href' => $scripturl . '?action=admin;area=' . $task[1],
'link' => '<a href="' . $scripturl . '?action=admin;area=' . $task[1] . '">' . $txt[$task[2]] . '</a>',
'title' => $txt[$task[2]],
'description' => $txt[$task[3]],
'icon' => $task[4],
'is_last' => false
);
}
if (count($context['quick_admin_tasks']) % 2 == 1)
{
$context['quick_admin_tasks'][] = array(
'href' => '',
'link' => '',
'title' => '',
'description' => '',
'is_last' => true
);
$context['quick_admin_tasks'][count($context['quick_admin_tasks']) - 2]['is_last'] = true;
}
elseif (count($context['quick_admin_tasks']) != 0)
{
$context['quick_admin_tasks'][count($context['quick_admin_tasks']) - 1]['is_last'] = true;
$context['quick_admin_tasks'][count($context['quick_admin_tasks']) - 2]['is_last'] = true;
}
// Lastly, fill in the blanks in the support resources paragraphs.
$txt['support_resources_p1'] = sprintf($txt['support_resources_p1'],
'http://wiki.simplemachines.org/',
'http://wiki.simplemachines.org/smf/features2',
'http://wiki.simplemachines.org/smf/options2',
'http://wiki.simplemachines.org/smf/themes2',
'http://wiki.simplemachines.org/smf/packages2'
);
$txt['support_resources_p2'] = sprintf($txt['support_resources_p2'],
'http://www.simplemachines.org/community/',
'http://www.simplemachines.org/redirect/english_support',
'http://www.simplemachines.org/redirect/international_support_boards',
'http://www.simplemachines.org/redirect/smf_support',
'http://www.simplemachines.org/redirect/customize_support'
);
}
// Get one of the admin information files from Simple Machines.
function DisplayAdminFile()
{
global $context, $modSettings, $smcFunc;
@ini_set('memory_limit', '32M');
if (empty($_REQUEST['filename']) || !is_string($_REQUEST['filename']))
fatal_lang_error('no_access', false);
$request = $smcFunc['db_query']('', '
SELECT data, filetype
FROM {db_prefix}admin_info_files
WHERE filename = {string:current_filename}
LIMIT 1',
array(
'current_filename' => $_REQUEST['filename'],
)
);
if ($smcFunc['db_num_rows']($request) == 0)
fatal_lang_error('admin_file_not_found', true, array($_REQUEST['filename']));
list ($file_data, $filetype) = $smcFunc['db_fetch_row']($request);
$smcFunc['db_free_result']($request);
// !!! Temp.
// Figure out if sesc is still being used.
if (strpos($file_data, ';sesc=') !== false)
$file_data = '
if (!(\'smfForum_sessionvar\' in window))
window.smfForum_sessionvar = \'sesc\';
' . strtr($file_data, array(';sesc=' => ';\' + window.smfForum_sessionvar + \'='));
$context['template_layers'] = array();
// Lets make sure we aren't going to output anything nasty.
@ob_end_clean();
if (!empty($modSettings['enableCompressedOutput']))
@ob_start('ob_gzhandler');
else
@ob_start();
// Make sure they know what type of file we are.
header('Content-Type: ' . $filetype);
echo $file_data;
obExit(false);
}
// This allocates out all the search stuff.
function AdminSearch()
{
global $txt, $context, $smcFunc, $sourcedir;
isAllowedTo('admin_forum');
// What can we search for?
$subactions = array(
'internal' => 'AdminSearchInternal',
'online' => 'AdminSearchOM',
'member' => 'AdminSearchMember',
);
$context['search_type'] = !isset($_REQUEST['search_type']) || !isset($subactions[$_REQUEST['search_type']]) ? 'internal' : $_REQUEST['search_type'];
$context['search_term'] = isset($_REQUEST['search_term']) ? $smcFunc['htmlspecialchars']($_REQUEST['search_term'], ENT_QUOTES) : '';
$context['sub_template'] = 'admin_search_results';
$context['page_title'] = $txt['admin_search_results'];
// Keep track of what the admin wants.
if (empty($context['admin_preferences']['sb']) || $context['admin_preferences']['sb'] != $context['search_type'])
{
$context['admin_preferences']['sb'] = $context['search_type'];
// Update the preferences.
require_once($sourcedir . '/Subs-Admin.php');
updateAdminPreferences();
}
if (trim($context['search_term']) == '')
$context['search_results'] = array();
else
$subactions[$context['search_type']]();
}
// A complicated but relatively quick internal search.
function AdminSearchInternal()
{
global $context, $txt, $helptxt, $scripturl, $sourcedir;
// Try to get some more memory.
@ini_set('memory_limit', '128M');
// Load a lot of language files.
$language_files = array(
'Help', 'ManageMail', 'ManageSettings', 'ManageCalendar', 'ManageBoards', 'ManagePaid', 'ManagePermissions', 'Search',
'Login', 'ManageSmileys',
);
loadLanguage(implode('+', $language_files));
// All the files we need to include.
$include_files = array(
'ManageSettings', 'ManageBoards', 'ManageNews', 'ManageAttachments', 'ManageCalendar', 'ManageMail', 'ManagePaid', 'ManagePermissions',
'ManagePosts', 'ManageRegistration', 'ManageSearch', 'ManageSearchEngines', 'ManageServer', 'ManageSmileys',
);
foreach ($include_files as $file)
require_once($sourcedir . '/' . $file . '.php');
/* This is the huge array that defines everything... it's a huge array of items formatted as follows:
0 = Language index (Can be array of indexes) to search through for this setting.
1 = URL for this indexes page.
2 = Help index for help associated with this item (If different from 0)
*/
$search_data = array(
// All the major sections of the forum.
'sections' => array(
),
'settings' => array(
array('COPPA', 'area=regcenter;sa=settings'),
array('CAPTCHA', 'area=securitysettings;sa=spam'),
),
);
// Go through the admin menu structure trying to find suitably named areas!
foreach ($context[$context['admin_menu_name']]['sections'] as $section)
{
foreach ($section['areas'] as $menu_key => $menu_item)
{
$search_data['sections'][] = array($menu_item['label'], 'area=' . $menu_key);
if (!empty($menu_item['subsections']))
foreach ($menu_item['subsections'] as $key => $sublabel)
{
if (isset($sublabel['label']))
$search_data['sections'][] = array($sublabel['label'], 'area=' . $menu_key . ';sa=' . $key);
}
}
}
// This is a special array of functions that contain setting data - we query all these to simply pull all setting bits!
$settings_search = array(
array('ModifyCoreFeatures', 'area=corefeatures'),
array('ModifyBasicSettings', 'area=featuresettings;sa=basic'),
array('ModifyLayoutSettings', 'area=featuresettings;sa=layout'),
array('ModifyKarmaSettings', 'area=featuresettings;sa=karma'),
array('ModifySignatureSettings', 'area=featuresettings;sa=sig'),
array('ModifyGeneralSecuritySettings', 'area=securitysettings;sa=general'),
array('ModifySpamSettings', 'area=securitysettings;sa=spam'),
array('ModifyModerationSettings', 'area=securitysettings;sa=moderation'),
array('ModifyGeneralModSettings', 'area=modsettings;sa=general'),
// Mod authors if you want to be "real freaking good" then add any setting pages for your mod BELOW this line!
array('ManageAttachmentSettings', 'area=manageattachments;sa=attachments'),
array('ManageAvatarSettings', 'area=manageattachments;sa=avatars'),
array('ModifyCalendarSettings', 'area=managecalendar;sa=settings'),
array('EditBoardSettings', 'area=manageboards;sa=settings'),
array('ModifyMailSettings', 'area=mailqueue;sa=settings'),
array('ModifyNewsSettings', 'area=news;sa=settings'),
array('GeneralPermissionSettings', 'area=permissions;sa=settings'),
array('ModifyPostSettings', 'area=postsettings;sa=posts'),
array('ModifyBBCSettings', 'area=postsettings;sa=bbc'),
array('ModifyTopicSettings', 'area=postsettings;sa=topics'),
array('EditSearchSettings', 'area=managesearch;sa=settings'),
array('EditSmileySettings', 'area=smileys;sa=settings'),
array('ModifyGeneralSettings', 'area=serversettings;sa=general'),
array('ModifyDatabaseSettings', 'area=serversettings;sa=database'),
array('ModifyCookieSettings', 'area=serversettings;sa=cookie'),
array('ModifyCacheSettings', 'area=serversettings;sa=cache'),
array('ModifyLanguageSettings', 'area=languages;sa=settings'),
array('ModifyRegistrationSettings', 'area=regcenter;sa=settings'),
array('ManageSearchEngineSettings', 'area=sengines;sa=settings'),
array('ModifySubscriptionSettings', 'area=paidsubscribe;sa=settings'),
array('ModifyPruningSettings', 'area=logs;sa=pruning'),
);
foreach ($settings_search as $setting_area)
{
// Get a list of their variables.
$config_vars = $setting_area[0](true);
foreach ($config_vars as $var)
if (!empty($var[1]) && !in_array($var[0], array('permissions', 'switch')))
$search_data['settings'][] = array($var[(isset($var[2]) && in_array($var[2], array('file', 'db'))) ? 0 : 1], $setting_area[1]);
}
$context['page_title'] = $txt['admin_search_results'];
$context['search_results'] = array();
$search_term = strtolower($context['search_term']);
// Go through all the search data trying to find this text!
foreach ($search_data as $section => $data)
{
foreach ($data as $item)
{
$found = false;
if (!is_array($item[0]))
$item[0] = array($item[0]);
foreach ($item[0] as $term)
{
$lc_term = strtolower($term);
if (strpos($lc_term, $search_term) !== false || (isset($txt[$term]) && strpos(strtolower($txt[$term]), $search_term) !== false) || (isset($txt['setting_' . $term]) && strpos(strtolower($txt['setting_' . $term]), $search_term) !== false))
{
$found = $term;
break;
}
}
if ($found)
{
// Format the name - and remove any descriptions the entry may have.
$name = isset($txt[$found]) ? $txt[$found] : (isset($txt['setting_' . $found]) ? $txt['setting_' . $found] : $found);
$name = preg_replace('~<(?:div|span)\sclass="smalltext">.+?</(?:div|span)>~', '', $name);
$context['search_results'][] = array(
'url' => (substr($item[1], 0, 4) == 'area' ? $scripturl . '?action=admin;' . $item[1] : $item[1]) . ';' . $context['session_var'] . '=' . $context['session_id'] . ((substr($item[1], 0, 4) == 'area' && $section == 'settings' ? '#' . $item[0][0] : '')),
'name' => $name,
'type' => $section,
'help' => shorten_subject(isset($item[2]) ? strip_tags($helptxt[$item2]) : (isset($helptxt[$found]) ? strip_tags($helptxt[$found]) : ''), 255),
);
}
}
}
}
// All this does is pass through to manage members.
function AdminSearchMember()
{
global $context, $sourcedir;
require_once($sourcedir . '/ManageMembers.php');
$_REQUEST['sa'] = 'query';
$_POST['membername'] = $context['search_term'];
ViewMembers();
}
// This file allows the user to search the SM online manual for a little of help.
function AdminSearchOM()
{
global $context, $sourcedir;
$docsURL = 'docs.simplemachines.org';
$context['doc_scripturl'] = 'http://docs.simplemachines.org/index.php';
// Set all the parameters search might expect.
$postVars = array(
'search' => $context['search_term'],
);
// Encode the search data.
foreach ($postVars as $k => $v)
$postVars[$k] = urlencode($k) . '=' . urlencode($v);
// This is what we will send.
$postVars = implode('&', $postVars);
// Get the results from the doc site.
require_once($sourcedir . '/Subs-Package.php');
$search_results = fetch_web_data($context['doc_scripturl'] . '?action=search2&xml', $postVars);
// If we didn't get any xml back we are in trouble - perhaps the doc site is overloaded?
if (!$search_results || preg_match('~<' . '\?xml\sversion="\d+\.\d+"\sencoding=".+?"\?' . '>\s*(<smf>.+?</smf>)~is', $search_results, $matches) != true)
fatal_lang_error('cannot_connect_doc_site');
$search_results = $matches[1];
// Otherwise we simply walk through the XML and stick it in context for display.
$context['search_results'] = array();
loadClassFile('Class-Package.php');
// Get the results loaded into an array for processing!
$results = new xmlArray($search_results, false);
// Move through the smf layer.
if (!$results->exists('smf'))
fatal_lang_error('cannot_connect_doc_site');
$results = $results->path('smf[0]');
// Are there actually some results?
if (!$results->exists('noresults') && !$results->exists('results'))
fatal_lang_error('cannot_connect_doc_site');
elseif ($results->exists('results'))
{
foreach ($results->set('results/result') as $result)
{
if (!$result->exists('messages'))
continue;
$context['search_results'][$result->fetch('id')] = array(
'topic_id' => $result->fetch('id'),
'relevance' => $result->fetch('relevance'),
'board' => array(
'id' => $result->fetch('board/id'),
'name' => $result->fetch('board/name'),
'href' => $result->fetch('board/href'),
),
'category' => array(
'id' => $result->fetch('category/id'),
'name' => $result->fetch('category/name'),
'href' => $result->fetch('category/href'),
),
'messages' => array(),
);
// Add the messages.
foreach ($result->set('messages/message') as $message)
$context['search_results'][$result->fetch('id')]['messages'][] = array(
'id' => $message->fetch('id'),
'subject' => $message->fetch('subject'),
'body' => $message->fetch('body'),
'time' => $message->fetch('time'),
'timestamp' => $message->fetch('timestamp'),
'start' => $message->fetch('start'),
'author' => array(
'id' => $message->fetch('author/id'),
'name' => $message->fetch('author/name'),
'href' => $message->fetch('author/href'),
),
);
}
}
}
// This function decides which log to load.
function AdminLogs()
{
global $sourcedir, $context, $txt, $scripturl;
// These are the logs they can load.
$log_functions = array(
'errorlog' => array('ManageErrors.php', 'ViewErrorLog'),
'adminlog' => array('Modlog.php', 'ViewModlog'),
'modlog' => array('Modlog.php', 'ViewModlog'),
'banlog' => array('ManageBans.php', 'BanLog'),
'spiderlog' => array('ManageSearchEngines.php', 'SpiderLogs'),
'tasklog' => array('ManageScheduledTasks.php', 'TaskLog'),
'pruning' => array('ManageSettings.php', 'ModifyPruningSettings'),
);
$sub_action = isset($_REQUEST['sa']) && isset($log_functions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'errorlog';
// If it's not got a sa set it must have come here for first time, pretend error log should be reversed.
if (!isset($_REQUEST['sa']))
$_REQUEST['desc'] = true;
// Setup some tab stuff.
$context[$context['admin_menu_name']]['tab_data'] = array(
'title' => $txt['logs'],
'help' => '',
'description' => $txt['maintain_info'],
'tabs' => array(
'errorlog' => array(
'url' => $scripturl . '?action=admin;area=logs;sa=errorlog;desc',
'description' => sprintf($txt['errlog_desc'], $txt['remove']),
),
'adminlog' => array(
'description' => $txt['admin_log_desc'],
),
'modlog' => array(
'description' => $txt['moderation_log_desc'],
),
'banlog' => array(
'description' => $txt['ban_log_description'],
),
'spiderlog' => array(
'description' => $txt['spider_log_desc'],
),
'tasklog' => array(
'description' => $txt['scheduled_log_desc'],
),
'pruning' => array(
'description' => $txt['pruning_log_desc'],
),
),
);
require_once($sourcedir . '/' . $log_functions[$sub_action][0]);
$log_functions[$sub_action][1]();
}
?>

143
Sources/BoardIndex.php Normal file
View File

@ -0,0 +1,143 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* The single function this file contains is used to display the main
board index. It uses just the following functions:
void BoardIndex()
- shows the board index.
- uses the BoardIndex template, and main sub template.
- may use the boardindex subtemplate for wireless support.
- updates the most online statistics.
- is accessed by ?action=boardindex.
void CollapseCategory()
- collapse or expand a category
*/
// Show the board index!
function BoardIndex()
{
global $txt, $user_info, $sourcedir, $modSettings, $context, $settings, $scripturl;
// For wireless, we use the Wireless template...
if (WIRELESS)
$context['sub_template'] = WIRELESS_PROTOCOL . '_boardindex';
else
loadTemplate('BoardIndex');
// Set a canonical URL for this page.
$context['canonical_url'] = $scripturl;
// Do not let search engines index anything if there is a random thing in $_GET.
if (!empty($_GET))
$context['robot_no_index'] = true;
// Retrieve the categories and boards.
require_once($sourcedir . '/Subs-BoardIndex.php');
$boardIndexOptions = array(
'include_categories' => true,
'base_level' => 0,
'parent_id' => 0,
'set_latest_post' => true,
'countChildPosts' => !empty($modSettings['countChildPosts']),
);
$context['categories'] = getBoardIndex($boardIndexOptions);
// Get the user online list.
require_once($sourcedir . '/Subs-MembersOnline.php');
$membersOnlineOptions = array(
'show_hidden' => allowedTo('moderate_forum'),
'sort' => 'log_time',
'reverse_sort' => true,
);
$context += getMembersOnlineStats($membersOnlineOptions);
$context['show_buddies'] = !empty($user_info['buddies']);
// Are we showing all membergroups on the board index?
if (!empty($settings['show_group_key']))
$context['membergroups'] = cache_quick_get('membergroup_list', 'Subs-Membergroups.php', 'cache_getMembergroupList', array());
// Track most online statistics? (Subs-MembersOnline.php)
if (!empty($modSettings['trackStats']))
trackStatsUsersOnline($context['num_guests'] + $context['num_spiders'] + $context['num_users_online']);
// Retrieve the latest posts if the theme settings require it.
if (isset($settings['number_recent_posts']) && $settings['number_recent_posts'] > 1)
{
$latestPostOptions = array(
'number_posts' => $settings['number_recent_posts'],
);
$context['latest_posts'] = cache_quick_get('boardindex-latest_posts:' . md5($user_info['query_wanna_see_board'] . $user_info['language']), 'Subs-Recent.php', 'cache_getLastPosts', array($latestPostOptions));
}
$settings['display_recent_bar'] = !empty($settings['number_recent_posts']) ? $settings['number_recent_posts'] : 0;
$settings['show_member_bar'] &= allowedTo('view_mlist');
$context['show_stats'] = allowedTo('view_stats') && !empty($modSettings['trackStats']);
$context['show_member_list'] = allowedTo('view_mlist');
$context['show_who'] = allowedTo('who_view') && !empty($modSettings['who_enabled']);
// Load the calendar?
if (!empty($modSettings['cal_enabled']) && allowedTo('calendar_view'))
{
// Retrieve the calendar data (events, birthdays, holidays).
$eventOptions = array(
'include_holidays' => $modSettings['cal_showholidays'] > 1,
'include_birthdays' => $modSettings['cal_showbdays'] > 1,
'include_events' => $modSettings['cal_showevents'] > 1,
'num_days_shown' => empty($modSettings['cal_days_for_index']) || $modSettings['cal_days_for_index'] < 1 ? 1 : $modSettings['cal_days_for_index'],
);
$context += cache_quick_get('calendar_index_offset_' . ($user_info['time_offset'] + $modSettings['time_offset']), 'Subs-Calendar.php', 'cache_getRecentEvents', array($eventOptions));
// Whether one or multiple days are shown on the board index.
$context['calendar_only_today'] = $modSettings['cal_days_for_index'] == 1;
// This is used to show the "how-do-I-edit" help.
$context['calendar_can_edit'] = allowedTo('calendar_edit_any');
}
else
$context['show_calendar'] = false;
$context['page_title'] = sprintf($txt['forum_index'], $context['forum_name']);
}
// Collapse or expand a category
function CollapseCategory()
{
global $user_info, $sourcedir, $context;
// Just in case, no need, no need.
$context['robot_no_index'] = true;
checkSession('request');
if (!isset($_GET['sa']))
fatal_lang_error('no_access', false);
// Check if the input values are correct.
if (in_array($_REQUEST['sa'], array('expand', 'collapse', 'toggle')) && isset($_REQUEST['c']))
{
// And collapse/expand/toggle the category.
require_once($sourcedir . '/Subs-Categories.php');
collapseCategories(array((int) $_REQUEST['c']), $_REQUEST['sa'], array($user_info['id']));
}
// And go back to the board index.
BoardIndex();
}
?>

487
Sources/Calendar.php Normal file
View File

@ -0,0 +1,487 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
// Original module by Aaron O'Neil - aaron@mud-master.com
if (!defined('SMF'))
die('Hacking attempt...');
/* This file has only one real task... showing the calendar. Posting is done
in Post.php - this just has the following functions:
void CalendarMain()
- loads the specified month's events, holidays, and birthdays.
- requires the calendar_view permission.
- depends on the cal_enabled setting, and many of the other cal_
settings.
- uses the calendar_start_day theme option. (Monday/Sunday)
- uses the main sub template in the Calendar template.
- goes to the month and year passed in 'month' and 'year' by
get or post.
- accessed through ?action=calendar.
void CalendarPost()
- processes posting/editing/deleting a calendar event.
- calls Post() function if event is linked to a post.
- calls insertEvent() to insert the event if not linked to post.
- requires the calendar_post permission to use.
- uses the event_post sub template in the Calendar template.
- is accessed with ?action=calendar;sa=post.
void iCalDownload()
- offers up a download of an event in iCal 2.0 format.
*/
// Show the calendar.
function CalendarMain()
{
global $txt, $context, $modSettings, $scripturl, $options, $sourcedir;
// Permissions, permissions, permissions.
isAllowedTo('calendar_view');
// Doing something other than calendar viewing?
$subActions = array(
'ical' => 'iCalDownload',
'post' => 'CalendarPost',
);
if (isset($_GET['sa']) && isset($subActions[$_GET['sa']]) && !WIRELESS)
return $subActions[$_GET['sa']]();
// This is gonna be needed...
loadTemplate('Calendar');
// You can't do anything if the calendar is off.
if (empty($modSettings['cal_enabled']))
fatal_lang_error('calendar_off', false);
// Set the page title to mention the calendar ;).
$context['page_title'] = $txt['calendar'];
// Is this a week view?
$context['view_week'] = isset($_GET['viewweek']);
// Don't let search engines index weekly calendar pages.
if ($context['view_week'])
$context['robot_no_index'] = true;
// Get the current day of month...
require_once($sourcedir . '/Subs-Calendar.php');
$today = getTodayInfo();
// If the month and year are not passed in, use today's date as a starting point.
$curPage = array(
'day' => isset($_REQUEST['day']) ? (int) $_REQUEST['day'] : $today['day'],
'month' => isset($_REQUEST['month']) ? (int) $_REQUEST['month'] : $today['month'],
'year' => isset($_REQUEST['year']) ? (int) $_REQUEST['year'] : $today['year']
);
// Make sure the year and month are in valid ranges.
if ($curPage['month'] < 1 || $curPage['month'] > 12)
fatal_lang_error('invalid_month', false);
if ($curPage['year'] < $modSettings['cal_minyear'] || $curPage['year'] > $modSettings['cal_maxyear'])
fatal_lang_error('invalid_year', false);
// If we have a day clean that too.
if ($context['view_week'])
{
// Note $isValid is -1 < PHP 5.1
$isValid = mktime(0, 0, 0, $curPage['month'], $curPage['day'], $curPage['year']);
if ($curPage['day'] > 31 || !$isValid || $isValid == -1)
fatal_lang_error('invalid_day', false);
}
// Load all the context information needed to show the calendar grid.
$calendarOptions = array(
'start_day' => !empty($options['calendar_start_day']) ? $options['calendar_start_day'] : 0,
'show_birthdays' => in_array($modSettings['cal_showbdays'], array(1, 2)),
'show_events' => in_array($modSettings['cal_showevents'], array(1, 2)),
'show_holidays' => in_array($modSettings['cal_showholidays'], array(1, 2)),
'show_week_num' => true,
'short_day_titles' => false,
'show_next_prev' => true,
'show_week_links' => true,
'size' => 'large',
);
// Load up the main view.
if ($context['view_week'])
$context['calendar_grid_main'] = getCalendarWeek($curPage['month'], $curPage['year'], $curPage['day'], $calendarOptions);
else
$context['calendar_grid_main'] = getCalendarGrid($curPage['month'], $curPage['year'], $calendarOptions);
// Load up the previous and next months.
$calendarOptions['show_birthdays'] = $calendarOptions['show_events'] = $calendarOptions['show_holidays'] = false;
$calendarOptions['short_day_titles'] = true;
$calendarOptions['show_next_prev'] = false;
$calendarOptions['show_week_links'] = false;
$calendarOptions['size'] = 'small';
$context['calendar_grid_current'] = getCalendarGrid($curPage['month'], $curPage['year'], $calendarOptions);
// Only show previous month if it isn't pre-January of the min-year
if ($context['calendar_grid_current']['previous_calendar']['year'] > $modSettings['cal_minyear'] || $curPage['month'] != 1)
$context['calendar_grid_prev'] = getCalendarGrid($context['calendar_grid_current']['previous_calendar']['month'], $context['calendar_grid_current']['previous_calendar']['year'], $calendarOptions);
// Only show next month if it isn't post-December of the max-year
if ($context['calendar_grid_current']['next_calendar']['year'] < $modSettings['cal_maxyear'] || $curPage['month'] != 12)
$context['calendar_grid_next'] = getCalendarGrid($context['calendar_grid_current']['next_calendar']['month'], $context['calendar_grid_current']['next_calendar']['year'], $calendarOptions);
// Basic template stuff.
$context['can_post'] = allowedTo('calendar_post');
$context['current_day'] = $curPage['day'];
$context['current_month'] = $curPage['month'];
$context['current_year'] = $curPage['year'];
$context['show_all_birthdays'] = isset($_GET['showbd']);
// Set the page title to mention the month or week, too
$context['page_title'] .= ' - ' . ($context['view_week'] ? sprintf($txt['calendar_week_title'], $context['calendar_grid_main']['week_number'], ($context['calendar_grid_main']['week_number'] == 53 ? $context['current_year'] - 1 : $context['current_year'])) : $txt['months'][$context['current_month']] . ' ' . $context['current_year']);
// Load up the linktree!
$context['linktree'][] = array(
'url' => $scripturl . '?action=calendar',
'name' => $txt['calendar']
);
// Add the current month to the linktree.
$context['linktree'][] = array(
'url' => $scripturl . '?action=calendar;year=' . $context['current_year'] . ';month=' . $context['current_month'],
'name' => $txt['months'][$context['current_month']] . ' ' . $context['current_year']
);
// If applicable, add the current week to the linktree.
if ($context['view_week'])
$context['linktree'][] = array(
'url' => $scripturl . '?action=calendar;viewweek;year=' . $context['current_year'] . ';month=' . $context['current_month'] . ';day=' . $context['current_day'],
'name' => $txt['calendar_week'] . ' ' . $context['calendar_grid_main']['week_number']
);
}
function CalendarPost()
{
global $context, $txt, $user_info, $sourcedir, $scripturl;
global $modSettings, $topic, $smcFunc;
// Well - can they?
isAllowedTo('calendar_post');
// We need this for all kinds of useful functions.
require_once($sourcedir . '/Subs-Calendar.php');
// Cast this for safety...
if (isset($_REQUEST['eventid']))
$_REQUEST['eventid'] = (int) $_REQUEST['eventid'];
// Submitting?
if (isset($_POST[$context['session_var']], $_REQUEST['eventid']))
{
checkSession();
// Validate the post...
if (!isset($_POST['link_to_board']))
validateEventPost();
// If you're not allowed to edit any events, you have to be the poster.
if ($_REQUEST['eventid'] > 0 && !allowedTo('calendar_edit_any'))
isAllowedTo('calendar_edit_' . (!empty($user_info['id']) && getEventPoster($_REQUEST['eventid']) == $user_info['id'] ? 'own' : 'any'));
// New - and directing?
if ($_REQUEST['eventid'] == -1 && isset($_POST['link_to_board']))
{
$_REQUEST['calendar'] = 1;
require_once($sourcedir . '/Post.php');
return Post();
}
// New...
elseif ($_REQUEST['eventid'] == -1)
{
$eventOptions = array(
'board' => 0,
'topic' => 0,
'title' => substr($_REQUEST['evtitle'], 0, 60),
'member' => $user_info['id'],
'start_date' => sprintf('%04d-%02d-%02d', $_POST['year'], $_POST['month'], $_POST['day']),
'span' => isset($_POST['span']) && $_POST['span'] > 0 ? min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1) : 0,
);
insertEvent($eventOptions);
}
// Deleting...
elseif (isset($_REQUEST['deleteevent']))
removeEvent($_REQUEST['eventid']);
// ... or just update it?
else
{
$eventOptions = array(
'title' => substr($_REQUEST['evtitle'], 0, 60),
'span' => empty($modSettings['cal_allowspan']) || empty($_POST['span']) || $_POST['span'] == 1 || empty($modSettings['cal_maxspan']) || $_POST['span'] > $modSettings['cal_maxspan'] ? 0 : min((int) $modSettings['cal_maxspan'], (int) $_POST['span'] - 1),
'start_date' => strftime('%Y-%m-%d', mktime(0, 0, 0, (int) $_REQUEST['month'], (int) $_REQUEST['day'], (int) $_REQUEST['year'])),
);
modifyEvent($_REQUEST['eventid'], $eventOptions);
}
updateSettings(array(
'calendar_updated' => time(),
));
// No point hanging around here now...
redirectexit($scripturl . '?action=calendar;month=' . $_POST['month'] . ';year=' . $_POST['year']);
}
// If we are not enabled... we are not enabled.
if (empty($modSettings['cal_allow_unlinked']) && empty($_REQUEST['eventid']))
{
$_REQUEST['calendar'] = 1;
require_once($sourcedir . '/Post.php');
return Post();
}
// New?
if (!isset($_REQUEST['eventid']))
{
$today = getdate();
$context['event'] = array(
'boards' => array(),
'board' => 0,
'new' => 1,
'eventid' => -1,
'year' => isset($_REQUEST['year']) ? $_REQUEST['year'] : $today['year'],
'month' => isset($_REQUEST['month']) ? $_REQUEST['month'] : $today['mon'],
'day' => isset($_REQUEST['day']) ? $_REQUEST['day'] : $today['mday'],
'title' => '',
'span' => 1,
);
$context['event']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['event']['month'] == 12 ? 1 : $context['event']['month'] + 1, 0, $context['event']['month'] == 12 ? $context['event']['year'] + 1 : $context['event']['year']));
// Get list of boards that can be posted in.
$boards = boardsAllowedTo('post_new');
if (empty($boards))
fatal_lang_error('cannot_post_new', 'permission');
// Load the list of boards and categories in the context.
require_once($sourcedir . '/Subs-MessageIndex.php');
$boardListOptions = array(
'included_boards' => in_array(0, $boards) ? null : $boards,
'not_redirection' => true,
'use_permissions' => true,
'selected_board' => $modSettings['cal_defaultboard'],
);
$context['event']['categories'] = getBoardList($boardListOptions);
}
else
{
$context['event'] = getEventProperties($_REQUEST['eventid']);
if ($context['event'] === false)
fatal_lang_error('no_access', false);
// If it has a board, then they should be editing it within the topic.
if (!empty($context['event']['topic']['id']) && !empty($context['event']['topic']['first_msg']))
{
// We load the board up, for a check on the board access rights...
$topic = $context['event']['topic']['id'];
loadBoard();
}
// Make sure the user is allowed to edit this event.
if ($context['event']['member'] != $user_info['id'])
isAllowedTo('calendar_edit_any');
elseif (!allowedTo('calendar_edit_any'))
isAllowedTo('calendar_edit_own');
}
// Template, sub template, etc.
loadTemplate('Calendar');
$context['sub_template'] = 'event_post';
$context['page_title'] = isset($_REQUEST['eventid']) ? $txt['calendar_edit'] : $txt['calendar_post_event'];
$context['linktree'][] = array(
'name' => $context['page_title'],
);
}
function iCalDownload()
{
global $smcFunc, $sourcedir, $forum_version, $context, $modSettings;
// Goes without saying that this is required.
if (!isset($_REQUEST['eventid']))
fatal_lang_error('no_access', false);
// This is kinda wanted.
require_once($sourcedir . '/Subs-Calendar.php');
// Load up the event in question and check it exists.
$event = getEventProperties($_REQUEST['eventid']);
if ($event === false)
fatal_lang_error('no_access', false);
// Check the title isn't too long - iCal requires some formatting if so.
$title = str_split($event['title'], 30);
foreach ($title as $id => $line)
{
if ($id != 0)
$title[$id] = ' ' . $title[$id];
$title[$id] .= "\n";
}
// Format the date.
$date = $event['year'] . '-' . ($event['month'] < 10 ? '0' . $event['month'] : $event['month']) . '-' . ($event['day'] < 10 ? '0' . $event['day'] : $event['day']) . 'T';
$date .= '1200:00:00Z';
// This is what we will be sending later.
$filecontents = '';
$filecontents .= 'BEGIN:VCALENDAR' . "\n";
$filecontents .= 'VERSION:2.0' . "\n";
$filecontents .= 'PRODID:-//SimpleMachines//SMF ' . (empty($forum_version) ? 1.0 : strtr($forum_version, array('SMF ' => ''))) . '//EN' . "\n";
$filecontents .= 'BEGIN:VEVENT' . "\n";
$filecontents .= 'DTSTART:' . $date . "\n";
$filecontents .= 'DTEND:' . $date . "\n";
$filecontents .= 'SUMMARY:' . implode('', $title);
$filecontents .= 'END:VEVENT' . "\n";
$filecontents .= 'END:VCALENDAR';
// Send some standard headers.
ob_end_clean();
if (!empty($modSettings['enableCompressedOutput']))
@ob_start('ob_gzhandler');
else
ob_start();
// Send the file headers
header('Pragma: ');
header('Cache-Control: no-cache');
if (!$context['browser']['is_gecko'])
header('Content-Transfer-Encoding: binary');
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 525600 * 60) . ' GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . 'GMT');
header('Accept-Ranges: bytes');
header('Connection: close');
header('Content-Disposition: attachment; filename=' . $event['title'] . '.ics');
// How big is it?
if (empty($modSettings['enableCompressedOutput']))
header('Content-Length: ' . $smcFunc['strlen']($filecontents));
// This is a calendar item!
header('Content-Type: text/calendar');
// Chuck out the card.
echo $filecontents;
// Off we pop - lovely!
obExit(false);
}
// This is not the code you are looking for.
function clock()
{
global $settings, $context;
$context['onimg'] = $settings['images_url'] . '/bbc/bbc_bg.gif';
$context['offimg'] = $settings['images_url'] . '/bbc/bbc_hoverbg.gif';
$context['page_title'] = 'Anyone know what time it is?';
$context['robot_no_index'] = true;
$omfg = isset($_REQUEST['omfg']);
$bcd = !isset($_REQUEST['rb']) && !isset($_REQUEST['omfg']) && !isset($_REQUEST['time']);
loadTemplate('Calendar');
if ($bcd && !$omfg)
{
$context['sub_template'] = 'bcd';
$context['clockicons'] = unserialize(base64_decode('YTo2OntzOjI6ImgxIjthOjI6e2k6MDtpOjI7aToxO2k6MTt9czoyOiJoMiI7YTo0OntpOjA7aTo4O2k6MTtpOjQ7aToyO2k6MjtpOjM7aToxO31zOjI6Im0xIjthOjM6e2k6MDtpOjQ7aToxO2k6MjtpOjI7aToxO31zOjI6Im0yIjthOjQ6e2k6MDtpOjg7aToxO2k6NDtpOjI7aToyO2k6MztpOjE7fXM6MjoiczEiO2E6Mzp7aTowO2k6NDtpOjE7aToyO2k6MjtpOjE7fXM6MjoiczIiO2E6NDp7aTowO2k6ODtpOjE7aTo0O2k6MjtpOjI7aTozO2k6MTt9fQ=='));
}
elseif (!$omfg && !isset($_REQUEST['time']))
{
$context['sub_template'] = 'hms';
$context['clockicons'] = unserialize(base64_decode('YTozOntzOjE6ImgiO2E6NTp7aTowO2k6MTY7aToxO2k6ODtpOjI7aTo0O2k6MztpOjI7aTo0O2k6MTt9czoxOiJtIjthOjY6e2k6MDtpOjMyO2k6MTtpOjE2O2k6MjtpOjg7aTozO2k6NDtpOjQ7aToyO2k6NTtpOjE7fXM6MToicyI7YTo2OntpOjA7aTozMjtpOjE7aToxNjtpOjI7aTo4O2k6MztpOjQ7aTo0O2k6MjtpOjU7aToxO319'));
}
elseif ($omfg)
{
$context['sub_template'] = 'omfg';
$context['clockicons'] = unserialize(base64_decode('YTo2OntzOjQ6InllYXIiO2E6Nzp7aTowO2k6NjQ7aToxO2k6MzI7aToyO2k6MTY7aTozO2k6ODtpOjQ7aTo0O2k6NTtpOjI7aTo2O2k6MTt9czo1OiJtb250aCI7YTo0OntpOjA7aTo4O2k6MTtpOjQ7aToyO2k6MjtpOjM7aToxO31zOjM6ImRheSI7YTo1OntpOjA7aToxNjtpOjE7aTo4O2k6MjtpOjQ7aTozO2k6MjtpOjQ7aToxO31zOjQ6ImhvdXIiO2E6NTp7aTowO2k6MTY7aToxO2k6ODtpOjI7aTo0O2k6MztpOjI7aTo0O2k6MTt9czozOiJtaW4iO2E6Njp7aTowO2k6MzI7aToxO2k6MTY7aToyO2k6ODtpOjM7aTo0O2k6NDtpOjI7aTo1O2k6MTt9czozOiJzZWMiO2E6Njp7aTowO2k6MzI7aToxO2k6MTY7aToyO2k6ODtpOjM7aTo0O2k6NDtpOjI7aTo1O2k6MTt9fQ=='));
}
elseif (isset($_REQUEST['time']))
{
$context['sub_template'] = 'thetime';
$time = getdate($_REQUEST['time'] == 'now' ? time() : (int) $_REQUEST['time']);
$context['clockicons'] = array(
'year' => array(
64 => false,
32 => false,
16 => false,
8 => false,
4 => false,
2 => false,
1 => false
),
'month' => array(
8 => false,
4 => false,
2 => false,
1 => false
),
'day' => array(
16 => false,
4 => false,
8 => false,
2 => false,
1 => false
),
'hour' => array(
32 => false,
16 => false,
8 => false,
4 => false,
2 => false,
1 => false
),
'min' => array(
32 => false,
16 => false,
8 => false,
4 => false,
2 => false,
1 => false
),
'sec' => array(
32 => false,
16 => false,
8 => false,
4 => false,
2 => false,
1 => false
),
);
$year = $time['year'] % 100;
$month = $time['mon'];
$day = $time['mday'];
$hour = $time['hours'];
$min = $time['minutes'];
$sec = $time['seconds'];
foreach ($context['clockicons'] as $t => $vs)
foreach ($vs as $v => $dumb)
{
if ($$t >= $v)
{
$$t -= $v;
$context['clockicons'][$t][$v] = true;
}
}
}
}
?>

715
Sources/Class-Graphics.php Normal file
View File

@ -0,0 +1,715 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
/* Gif Util copyright 2003 by Yamasoft (S/C). All rights reserved.
Do not remove this portion of the header, or use these functions except
from the original author. To get it, please navigate to:
http://www.yamasoft.com/php-gif.zip
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* Classes used for reading gif files (in case PHP's GD doesn't provide the
proper gif-functions).
*/
class gif_lzw_compression
{
public $MAX_LZW_BITS;
public $Fresh, $CodeSize, $SetCodeSize, $MaxCode, $MaxCodeSize, $FirstCode, $OldCode;
public $ClearCode, $EndCode, $Next, $Vals, $Stack, $sp, $Buf, $CurBit, $LastBit, $Done, $LastByte;
public function __construct()
{
$this->MAX_LZW_BITS = 12;
unset($this->Next, $this->Vals, $this->Stack, $this->Buf);
$this->Next = range(0, (1 << $this->MAX_LZW_BITS) - 1);
$this->Vals = range(0, (1 << $this->MAX_LZW_BITS) - 1);
$this->Stack = range(0, (1 << ($this->MAX_LZW_BITS + 1)) - 1);
$this->Buf = range(0, 279);
}
public function decompress($data, &$datLen)
{
$stLen = strlen($data);
$datLen = 0;
$ret = '';
$this->LZWCommand($data, true);
while (($iIndex = $this->LZWCommand($data, false)) >= 0)
$ret .= chr($iIndex);
$datLen = $stLen - strlen($data);
if ($iIndex != -2)
return false;
return $ret;
}
public function LZWCommand(&$data, $bInit)
{
if ($bInit)
{
$this->SetCodeSize = ord($data[0]);
$data = substr($data, 1);
$this->CodeSize = $this->SetCodeSize + 1;
$this->ClearCode = 1 << $this->SetCodeSize;
$this->EndCode = $this->ClearCode + 1;
$this->MaxCode = $this->ClearCode + 2;
$this->MaxCodeSize = $this->ClearCode << 1;
$this->GetCode($data, $bInit);
$this->Fresh = 1;
for ($i = 0; $i < $this->ClearCode; $i++)
{
$this->Next[$i] = 0;
$this->Vals[$i] = $i;
}
for (; $i < (1 << $this->MAX_LZW_BITS); $i++)
{
$this->Next[$i] = 0;
$this->Vals[$i] = 0;
}
$this->sp = 0;
return 1;
}
if ($this->Fresh)
{
$this->Fresh = 0;
do
{
$this->FirstCode = $this->GetCode($data, $bInit);
$this->OldCode = $this->FirstCode;
}
while ($this->FirstCode == $this->ClearCode);
return $this->FirstCode;
}
if ($this->sp > 0)
{
$this->sp--;
return $this->Stack[$this->sp];
}
while (($Code = $this->GetCode($data, $bInit)) >= 0)
{
if ($Code == $this->ClearCode)
{
for ($i = 0; $i < $this->ClearCode; $i++)
{
$this->Next[$i] = 0;
$this->Vals[$i] = $i;
}
for (; $i < (1 << $this->MAX_LZW_BITS); $i++)
{
$this->Next[$i] = 0;
$this->Vals[$i] = 0;
}
$this->CodeSize = $this->SetCodeSize + 1;
$this->MaxCodeSize = $this->ClearCode << 1;
$this->MaxCode = $this->ClearCode + 2;
$this->sp = 0;
$this->FirstCode = $this->GetCode($data, $bInit);
$this->OldCode = $this->FirstCode;
return $this->FirstCode;
}
if ($Code == $this->EndCode)
return -2;
$InCode = $Code;
if ($Code >= $this->MaxCode)
{
$this->Stack[$this->sp] = $this->FirstCode;
$this->sp++;
$Code = $this->OldCode;
}
while ($Code >= $this->ClearCode)
{
$this->Stack[$this->sp] = $this->Vals[$Code];
$this->sp++;
if ($Code == $this->Next[$Code]) // Circular table entry, big GIF Error!
return -1;
$Code = $this->Next[$Code];
}
$this->FirstCode = $this->Vals[$Code];
$this->Stack[$this->sp] = $this->FirstCode;
$this->sp++;
if (($Code = $this->MaxCode) < (1 << $this->MAX_LZW_BITS))
{
$this->Next[$Code] = $this->OldCode;
$this->Vals[$Code] = $this->FirstCode;
$this->MaxCode++;
if (($this->MaxCode >= $this->MaxCodeSize) && ($this->MaxCodeSize < (1 << $this->MAX_LZW_BITS)))
{
$this->MaxCodeSize *= 2;
$this->CodeSize++;
}
}
$this->OldCode = $InCode;
if ($this->sp > 0)
{
$this->sp--;
return $this->Stack[$this->sp];
}
}
return $Code;
}
public function GetCode(&$data, $bInit)
{
if ($bInit)
{
$this->CurBit = 0;
$this->LastBit = 0;
$this->Done = 0;
$this->LastByte = 2;
return 1;
}
if (($this->CurBit + $this->CodeSize) >= $this->LastBit)
{
if ($this->Done)
{
// Ran off the end of my bits...
if ($this->CurBit >= $this->LastBit)
return 0;
return -1;
}
$this->Buf[0] = $this->Buf[$this->LastByte - 2];
$this->Buf[1] = $this->Buf[$this->LastByte - 1];
$count = ord($data[0]);
$data = substr($data, 1);
if ($count)
{
for ($i = 0; $i < $count; $i++)
$this->Buf[2 + $i] = ord($data{$i});
$data = substr($data, $count);
}
else
$this->Done = 1;
$this->LastByte = 2 + $count;
$this->CurBit = ($this->CurBit - $this->LastBit) + 16;
$this->LastBit = (2 + $count) << 3;
}
$iRet = 0;
for ($i = $this->CurBit, $j = 0; $j < $this->CodeSize; $i++, $j++)
$iRet |= (($this->Buf[intval($i / 8)] & (1 << ($i % 8))) != 0) << $j;
$this->CurBit += $this->CodeSize;
return $iRet;
}
}
class gif_color_table
{
public $m_nColors;
public $m_arColors;
public function __construct()
{
unset($this->m_nColors, $this->m_arColors);
}
public function load($lpData, $num)
{
$this->m_nColors = 0;
$this->m_arColors = array();
for ($i = 0; $i < $num; $i++)
{
$rgb = substr($lpData, $i * 3, 3);
if (strlen($rgb) < 3)
return false;
$this->m_arColors[] = (ord($rgb[2]) << 16) + (ord($rgb[1]) << 8) + ord($rgb[0]);
$this->m_nColors++;
}
return true;
}
public function toString()
{
$ret = '';
for ($i = 0; $i < $this->m_nColors; $i++)
{
$ret .=
chr(($this->m_arColors[$i] & 0x000000FF)) . // R
chr(($this->m_arColors[$i] & 0x0000FF00) >> 8) . // G
chr(($this->m_arColors[$i] & 0x00FF0000) >> 16); // B
}
return $ret;
}
public function colorIndex($rgb)
{
$rgb = intval($rgb) & 0xFFFFFF;
$r1 = ($rgb & 0x0000FF);
$g1 = ($rgb & 0x00FF00) >> 8;
$b1 = ($rgb & 0xFF0000) >> 16;
$idx = -1;
for ($i = 0; $i < $this->m_nColors; $i++)
{
$r2 = ($this->m_arColors[$i] & 0x000000FF);
$g2 = ($this->m_arColors[$i] & 0x0000FF00) >> 8;
$b2 = ($this->m_arColors[$i] & 0x00FF0000) >> 16;
$d = abs($r2 - $r1) + abs($g2 - $g1) + abs($b2 - $b1);
if (($idx == -1) || ($d < $dif))
{
$idx = $i;
$dif = $d;
}
}
return $idx;
}
}
class gif_file_header
{
public $m_lpVer, $m_nWidth, $m_nHeight, $m_bGlobalClr, $m_nColorRes;
public $m_bSorted, $m_nTableSize, $m_nBgColor, $m_nPixelRatio;
public $m_colorTable;
public function __construct()
{
unset($this->m_lpVer, $this->m_nWidth, $this->m_nHeight, $this->m_bGlobalClr, $this->m_nColorRes);
unset($this->m_bSorted, $this->m_nTableSize, $this->m_nBgColor, $this->m_nPixelRatio, $this->m_colorTable);
}
public function load($lpData, &$hdrLen)
{
$hdrLen = 0;
$this->m_lpVer = substr($lpData, 0, 6);
if (($this->m_lpVer != 'GIF87a') && ($this->m_lpVer != 'GIF89a'))
return false;
list ($this->m_nWidth, $this->m_nHeight) = array_values(unpack('v2', substr($lpData, 6, 4)));
if (!$this->m_nWidth || !$this->m_nHeight)
return false;
$b = ord(substr($lpData, 10, 1));
$this->m_bGlobalClr = ($b & 0x80) ? true : false;
$this->m_nColorRes = ($b & 0x70) >> 4;
$this->m_bSorted = ($b & 0x08) ? true : false;
$this->m_nTableSize = 2 << ($b & 0x07);
$this->m_nBgColor = ord(substr($lpData, 11, 1));
$this->m_nPixelRatio = ord(substr($lpData, 12, 1));
$hdrLen = 13;
if ($this->m_bGlobalClr)
{
$this->m_colorTable = new gif_color_table();
if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize))
return false;
$hdrLen += 3 * $this->m_nTableSize;
}
return true;
}
}
class gif_image_header
{
public $m_nLeft, $m_nTop, $m_nWidth, $m_nHeight, $m_bLocalClr;
public $m_bInterlace, $m_bSorted, $m_nTableSize, $m_colorTable;
public function __construct()
{
unset($this->m_nLeft, $this->m_nTop, $this->m_nWidth, $this->m_nHeight, $this->m_bLocalClr);
unset($this->m_bInterlace, $this->m_bSorted, $this->m_nTableSize, $this->m_colorTable);
}
public function load($lpData, &$hdrLen)
{
$hdrLen = 0;
// Get the width/height/etc. from the header.
list ($this->m_nLeft, $this->m_nTop, $this->m_nWidth, $this->m_nHeight) = array_values(unpack('v4', substr($lpData, 0, 8)));
if (!$this->m_nWidth || !$this->m_nHeight)
return false;
$b = ord($lpData[8]);
$this->m_bLocalClr = ($b & 0x80) ? true : false;
$this->m_bInterlace = ($b & 0x40) ? true : false;
$this->m_bSorted = ($b & 0x20) ? true : false;
$this->m_nTableSize = 2 << ($b & 0x07);
$hdrLen = 9;
if ($this->m_bLocalClr)
{
$this->m_colorTable = new gif_color_table();
if (!$this->m_colorTable->load(substr($lpData, $hdrLen), $this->m_nTableSize))
return false;
$hdrLen += 3 * $this->m_nTableSize;
}
return true;
}
}
class gif_image
{
public $m_disp, $m_bUser, $m_bTrans, $m_nDelay, $m_nTrans, $m_lpComm;
public $m_gih, $m_data, $m_lzw;
public function __construct()
{
unset($this->m_disp, $this->m_bUser, $this->m_nDelay, $this->m_nTrans, $this->m_lpComm, $this->m_data);
$this->m_gih = new gif_image_header();
$this->m_lzw = new gif_lzw_compression();
}
public function load($data, &$datLen)
{
$datLen = 0;
while (true)
{
$b = ord($data[0]);
$data = substr($data, 1);
$datLen++;
switch ($b)
{
// Extension...
case 0x21:
$len = 0;
if (!$this->skipExt($data, $len))
return false;
$datLen += $len;
break;
// Image...
case 0x2C:
// Load the header and color table.
$len = 0;
if (!$this->m_gih->load($data, $len))
return false;
$data = substr($data, $len);
$datLen += $len;
// Decompress the data, and ride on home ;).
$len = 0;
if (!($this->m_data = $this->m_lzw->decompress($data, $len)))
return false;
$data = substr($data, $len);
$datLen += $len;
if ($this->m_gih->m_bInterlace)
$this->deInterlace();
return true;
case 0x3B: // EOF
default:
return false;
}
}
return false;
}
public function skipExt(&$data, &$extLen)
{
$extLen = 0;
$b = ord($data[0]);
$data = substr($data, 1);
$extLen++;
switch ($b)
{
// Graphic Control...
case 0xF9:
$b = ord($data[1]);
$this->m_disp = ($b & 0x1C) >> 2;
$this->m_bUser = ($b & 0x02) ? true : false;
$this->m_bTrans = ($b & 0x01) ? true : false;
list ($this->m_nDelay) = array_values(unpack('v', substr($data, 2, 2)));
$this->m_nTrans = ord($data[4]);
break;
// Comment...
case 0xFE:
$this->m_lpComm = substr($data, 1, ord($data[0]));
break;
// Plain text...
case 0x01:
break;
// Application...
case 0xFF:
break;
}
// Skip default as defs may change.
$b = ord($data[0]);
$data = substr($data, 1);
$extLen++;
while ($b > 0)
{
$data = substr($data, $b);
$extLen += $b;
$b = ord($data[0]);
$data = substr($data, 1);
$extLen++;
}
return true;
}
public function deInterlace()
{
$data = $this->m_data;
for ($i = 0; $i < 4; $i++)
{
switch ($i)
{
case 0:
$s = 8;
$y = 0;
break;
case 1:
$s = 8;
$y = 4;
break;
case 2:
$s = 4;
$y = 2;
break;
case 3:
$s = 2;
$y = 1;
break;
}
for (; $y < $this->m_gih->m_nHeight; $y += $s)
{
$lne = substr($this->m_data, 0, $this->m_gih->m_nWidth);
$this->m_data = substr($this->m_data, $this->m_gih->m_nWidth);
$data =
substr($data, 0, $y * $this->m_gih->m_nWidth) .
$lne .
substr($data, ($y + 1) * $this->m_gih->m_nWidth);
}
}
$this->m_data = $data;
}
}
class gif_file
{
public $header, $image, $data, $loaded;
public function __construct()
{
$this->data = '';
$this->loaded = false;
$this->header = new gif_file_header();
$this->image = new gif_image();
}
public function loadFile($filename, $iIndex)
{
if ($iIndex < 0)
return false;
$this->data = @file_get_contents($filename);
if ($this->data === false)
return false;
// Tell the header to load up....
$len = 0;
if (!$this->header->load($this->data, $len))
return false;
$this->data = substr($this->data, $len);
// Keep reading (at least once) so we get to the actual image we're looking for.
for ($j = 0; $j <= $iIndex; $j++)
{
$imgLen = 0;
if (!$this->image->load($this->data, $imgLen))
return false;
$this->data = substr($this->data, $imgLen);
}
$this->loaded = true;
return true;
}
public function get_png_data($background_color)
{
if (!$this->loaded)
return false;
// Prepare the color table.
if ($this->image->m_gih->m_bLocalClr)
{
$colors = $this->image->m_gih->m_nTableSize;
$pal = $this->image->m_gih->m_colorTable->toString();
if ($background_color != -1)
$background_color = $this->image->m_gih->m_colorTable->colorIndex($background_color);
}
elseif ($this->header->m_bGlobalClr)
{
$colors = $this->header->m_nTableSize;
$pal = $this->header->m_colorTable->toString();
if ($background_color != -1)
$background_color = $this->header->m_colorTable->colorIndex($background_color);
}
else
{
$colors = 0;
$background_color = -1;
}
if ($background_color == -1)
$background_color = $this->header->m_nBgColor;
$data = &$this->image->m_data;
$header = &$this->image->m_gih;
$i = 0;
$bmp = '';
// Prepare the bitmap itself.
for ($y = 0; $y < $this->header->m_nHeight; $y++)
{
$bmp .= "\x00";
for ($x = 0; $x < $this->header->m_nWidth; $x++, $i++)
{
// Is this in the proper range? If so, get the specific pixel data...
if ($x >= $header->m_nLeft && $y >= $header->m_nTop && $x < ($header->m_nLeft + $header->m_nWidth) && $y < ($header->m_nTop + $header->m_nHeight))
$bmp .= $data{$i};
// Otherwise, this is background...
else
$bmp .= chr($background_color);
}
}
$bmp = gzcompress($bmp, 9);
// Output the basic signature first of all.
$out = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
// Now, we want the header...
$out .= "\x00\x00\x00\x0D";
$tmp = 'IHDR' . pack('N', (int) $this->header->m_nWidth) . pack('N', (int) $this->header->m_nHeight) . "\x08\x03\x00\x00\x00";
$out .= $tmp . pack('N', smf_crc32($tmp));
// The palette, assuming we have one to speak of...
if ($colors > 0)
{
$out .= pack('N', (int) $colors * 3);
$tmp = 'PLTE' . $pal;
$out .= $tmp . pack('N', smf_crc32($tmp));
}
// Do we have any transparency we want to make available?
if ($this->image->m_bTrans && $colors > 0)
{
$out .= pack('N', (int) $colors);
$tmp = 'tRNS';
// Stick each color on - full transparency or none.
for ($i = 0; $i < $colors; $i++)
$tmp .= $i == $this->image->m_nTrans ? "\x00" : "\xFF";
$out .= $tmp . pack('N', smf_crc32($tmp));
}
// Here's the data itself!
$out .= pack('N', strlen($bmp));
$tmp = 'IDAT' . $bmp;
$out .= $tmp . pack('N', smf_crc32($tmp));
// EOF marker...
$out .= "\x00\x00\x00\x00" . 'IEND' . "\xAE\x42\x60\x82";
return $out;
}
}
// crc32 doesn't work as expected on 64-bit functions - make our own.
// http://www.php.net/crc32#79567
if (!function_exists('smf_crc32'))
{
function smf_crc32($number)
{
$crc = crc32($number);
if ($crc & 0x80000000)
{
$crc ^= 0xffffffff;
$crc += 1;
$crc = -$crc;
}
return $crc;
}
}
?>

1019
Sources/Class-Package.php Normal file

File diff suppressed because it is too large Load Diff

454
Sources/DbExtra-mysql.php Normal file
View File

@ -0,0 +1,454 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file contains rarely used extended database functionality.
void db_extra_init()
- add this file's functions to the $smcFunc array.
resource smf_db_backup_table($table, $backup_table)
- backup $table to $backup_table.
- returns the request handle to the table creation query
string function smf_db_get_version()
- get the version number.
string db_insert_sql(string table_name)
- gets all the necessary INSERTs for the table named table_name.
- goes in 250 row segments.
- returns the query to insert the data back in.
- returns an empty string if the table was empty.
array smf_db_list_tables($db = false, $filter = false)
- lists all tables in the database
- could be filtered according to $filter
- returns an array of table names. (strings)
float smf_db_optimize_table($table)
- optimize a table
- $table - the table to be optimized
- returns how much it was gained
string db_table_sql(string table_name)
- dumps the CREATE for the specified table. (by table_name.)
- returns the CREATE statement.
*/
// Add the file functions to the $smcFunc array.
function db_extra_init()
{
global $smcFunc;
if (!isset($smcFunc['db_backup_table']) || $smcFunc['db_backup_table'] != 'smf_db_backup_table')
$smcFunc += array(
'db_backup_table' => 'smf_db_backup_table',
'db_optimize_table' => 'smf_db_optimize_table',
'db_insert_sql' => 'smf_db_insert_sql',
'db_table_sql' => 'smf_db_table_sql',
'db_list_tables' => 'smf_db_list_tables',
'db_get_version' => 'smf_db_get_version',
);
}
// Backup $table to $backup_table.
function smf_db_backup_table($table, $backup_table)
{
global $smcFunc, $db_prefix;
$table = str_replace('{db_prefix}', $db_prefix, $table);
// First, get rid of the old table.
$smcFunc['db_query']('', '
DROP TABLE IF EXISTS {raw:backup_table}',
array(
'backup_table' => $backup_table,
)
);
// Can we do this the quick way?
$result = $smcFunc['db_query']('', '
CREATE TABLE {raw:backup_table} LIKE {raw:table}',
array(
'backup_table' => $backup_table,
'table' => $table
));
// If this failed, we go old school.
if ($result)
{
$request = $smcFunc['db_query']('', '
INSERT INTO {raw:backup_table}
SELECT *
FROM {raw:table}',
array(
'backup_table' => $backup_table,
'table' => $table
));
// Old school or no school?
if ($request)
return $request;
}
// At this point, the quick method failed.
$result = $smcFunc['db_query']('', '
SHOW CREATE TABLE {raw:table}',
array(
'table' => $table,
)
);
list (, $create) = $smcFunc['db_fetch_row']($result);
$smcFunc['db_free_result']($result);
$create = preg_split('/[\n\r]/', $create);
$auto_inc = '';
// Default engine type.
$engine = 'MyISAM';
$charset = '';
$collate = '';
foreach ($create as $k => $l)
{
// Get the name of the auto_increment column.
if (strpos($l, 'auto_increment'))
$auto_inc = trim($l);
// For the engine type, see if we can work out what it is.
if (strpos($l, 'ENGINE') !== false || strpos($l, 'TYPE') !== false)
{
// Extract the engine type.
preg_match('~(ENGINE|TYPE)=(\w+)(\sDEFAULT)?(\sCHARSET=(\w+))?(\sCOLLATE=(\w+))?~', $l, $match);
if (!empty($match[1]))
$engine = $match[1];
if (!empty($match[2]))
$engine = $match[2];
if (!empty($match[5]))
$charset = $match[5];
if (!empty($match[7]))
$collate = $match[7];
}
// Skip everything but keys...
if (strpos($l, 'KEY') === false)
unset($create[$k]);
}
if (!empty($create))
$create = '(
' . implode('
', $create) . ')';
else
$create = '';
$request = $smcFunc['db_query']('', '
CREATE TABLE {raw:backup_table} {raw:create}
ENGINE={raw:engine}' . (empty($charset) ? '' : ' CHARACTER SET {raw:charset}' . (empty($collate) ? '' : ' COLLATE {raw:collate}')) . '
SELECT *
FROM {raw:table}',
array(
'backup_table' => $backup_table,
'table' => $table,
'create' => $create,
'engine' => $engine,
'charset' => empty($charset) ? '' : $charset,
'collate' => empty($collate) ? '' : $collate,
)
);
if ($auto_inc != '')
{
if (preg_match('~\`(.+?)\`\s~', $auto_inc, $match) != 0 && substr($auto_inc, -1, 1) == ',')
$auto_inc = substr($auto_inc, 0, -1);
$smcFunc['db_query']('', '
ALTER TABLE {raw:backup_table}
CHANGE COLUMN {raw:column_detail} {raw:auto_inc}',
array(
'backup_table' => $backup_table,
'column_detail' => $match[1],
'auto_inc' => $auto_inc,
)
);
}
return $request;
}
// Optimize a table - return data freed!
function smf_db_optimize_table($table)
{
global $smcFunc, $db_name, $db_prefix;
$table = str_replace('{db_prefix}', $db_prefix, $table);
// Get how much overhead there is.
$request = $smcFunc['db_query']('', '
SHOW TABLE STATUS LIKE {string:table_name}',
array(
'table_name' => str_replace('_', '\_', $table),
)
);
$row = $smcFunc['db_fetch_assoc']($request);
$smcFunc['db_free_result']($request);
$data_before = isset($row['Data_free']) ? $row['Data_free'] : 0;
$request = $smcFunc['db_query']('', '
OPTIMIZE TABLE `{raw:table}`',
array(
'table' => $table,
)
);
if (!$request)
return -1;
// How much left?
$request = $smcFunc['db_query']('', '
SHOW TABLE STATUS LIKE {string:table}',
array(
'table' => str_replace('_', '\_', $table),
)
);
$row = $smcFunc['db_fetch_assoc']($request);
$smcFunc['db_free_result']($request);
$total_change = isset($row['Data_free']) && $data_before > $row['Data_free'] ? $data_before / 1024 : 0;
return $total_change;
}
// List all the tables in the database.
function smf_db_list_tables($db = false, $filter = false)
{
global $db_name, $smcFunc;
$db = $db == false ? $db_name : $db;
$db = trim($db);
$filter = $filter == false ? '' : ' LIKE \'' . $filter . '\'';
$request = $smcFunc['db_query']('', '
SHOW TABLES
FROM `{raw:db}`
{raw:filter}',
array(
'db' => $db[0] == '`' ? strtr($db, array('`' => '')) : $db,
'filter' => $filter,
)
);
$tables = array();
while ($row = $smcFunc['db_fetch_row']($request))
$tables[] = $row[0];
$smcFunc['db_free_result']($request);
return $tables;
}
// Get the content (INSERTs) for a table.
function smf_db_insert_sql($tableName)
{
global $smcFunc, $db_prefix;
$tableName = str_replace('{db_prefix}', $db_prefix, $tableName);
// This will be handy...
$crlf = "\r\n";
// Get everything from the table.
$result = $smcFunc['db_query']('', '
SELECT /*!40001 SQL_NO_CACHE */ *
FROM `{raw:table}`',
array(
'table' => $tableName,
)
);
// The number of rows, just for record keeping and breaking INSERTs up.
$num_rows = $smcFunc['db_num_rows']($result);
$current_row = 0;
if ($num_rows == 0)
return '';
$fields = array_keys($smcFunc['db_fetch_assoc']($result));
$smcFunc['db_data_seek']($result, 0);
// Start it off with the basic INSERT INTO.
$data = 'INSERT INTO `' . $tableName . '`' . $crlf . "\t" . '(`' . implode('`, `', $fields) . '`)' . $crlf . 'VALUES ';
// Loop through each row.
while ($row = $smcFunc['db_fetch_row']($result))
{
$current_row++;
// Get the fields in this row...
$field_list = array();
for ($j = 0; $j < $smcFunc['db_num_fields']($result); $j++)
{
// Try to figure out the type of each field. (NULL, number, or 'string'.)
if (!isset($row[$j]))
$field_list[] = 'NULL';
elseif (is_numeric($row[$j]) && (int) $row[$j] == $row[$j])
$field_list[] = $row[$j];
else
$field_list[] = '\'' . $smcFunc['db_escape_string']($row[$j]) . '\'';
}
// 'Insert' the data.
$data .= '(' . implode(', ', $field_list) . ')';
// All done!
if ($current_row == $num_rows)
$data .= ';' . $crlf;
// Start a new INSERT statement after every 250....
elseif ($current_row > 249 && $current_row % 250 == 0)
$data .= ';' . $crlf . 'INSERT INTO `' . $tableName . '`' . $crlf . "\t" . '(`' . implode('`, `', $fields) . '`)' . $crlf . 'VALUES ';
// Otherwise, go to the next line.
else
$data .= ',' . $crlf . "\t";
}
$smcFunc['db_free_result']($result);
// Return an empty string if there were no rows.
return $num_rows == 0 ? '' : $data;
}
// Get the schema (CREATE) for a table.
function smf_db_table_sql($tableName)
{
global $smcFunc, $db_prefix;
$tableName = str_replace('{db_prefix}', $db_prefix, $tableName);
// This will be needed...
$crlf = "\r\n";
// Drop it if it exists.
$schema_create = 'DROP TABLE IF EXISTS `' . $tableName . '`;' . $crlf . $crlf;
// Start the create table...
$schema_create .= 'CREATE TABLE `' . $tableName . '` (' . $crlf;
// Find all the fields.
$result = $smcFunc['db_query']('', '
SHOW FIELDS
FROM `{raw:table}`',
array(
'table' => $tableName,
)
);
while ($row = $smcFunc['db_fetch_assoc']($result))
{
// Make the CREATE for this column.
$schema_create .= ' `' . $row['Field'] . '` ' . $row['Type'] . ($row['Null'] != 'YES' ? ' NOT NULL' : '');
// Add a default...?
if (!empty($row['Default']) || $row['Null'] !== 'YES')
{
// Make a special case of auto-timestamp.
if ($row['Default'] == 'CURRENT_TIMESTAMP')
$schema_create .= ' /*!40102 NOT NULL default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP */';
// Text shouldn't have a default.
elseif ($row['Default'] !== null)
{
// If this field is numeric the default needs no escaping.
$type = strtolower($row['Type']);
$isNumericColumn = strpos($type, 'int') !== false || strpos($type, 'bool') !== false || strpos($type, 'bit') !== false || strpos($type, 'float') !== false || strpos($type, 'double') !== false || strpos($type, 'decimal') !== false;
$schema_create .= ' default ' . ($isNumericColumn ? $row['Default'] : '\'' . $smcFunc['db_escape_string']($row['Default']) . '\'');
}
}
// And now any extra information. (such as auto_increment.)
$schema_create .= ($row['Extra'] != '' ? ' ' . $row['Extra'] : '') . ',' . $crlf;
}
$smcFunc['db_free_result']($result);
// Take off the last comma.
$schema_create = substr($schema_create, 0, -strlen($crlf) - 1);
// Find the keys.
$result = $smcFunc['db_query']('', '
SHOW KEYS
FROM `{raw:table}`',
array(
'table' => $tableName,
)
);
$indexes = array();
while ($row = $smcFunc['db_fetch_assoc']($result))
{
// IS this a primary key, unique index, or regular index?
$row['Key_name'] = $row['Key_name'] == 'PRIMARY' ? 'PRIMARY KEY' : (empty($row['Non_unique']) ? 'UNIQUE ' : ($row['Comment'] == 'FULLTEXT' || (isset($row['Index_type']) && $row['Index_type'] == 'FULLTEXT') ? 'FULLTEXT ' : 'KEY ')) . '`' . $row['Key_name'] . '`';
// Is this the first column in the index?
if (empty($indexes[$row['Key_name']]))
$indexes[$row['Key_name']] = array();
// A sub part, like only indexing 15 characters of a varchar.
if (!empty($row['Sub_part']))
$indexes[$row['Key_name']][$row['Seq_in_index']] = '`' . $row['Column_name'] . '`(' . $row['Sub_part'] . ')';
else
$indexes[$row['Key_name']][$row['Seq_in_index']] = '`' . $row['Column_name'] . '`';
}
$smcFunc['db_free_result']($result);
// Build the CREATEs for the keys.
foreach ($indexes as $keyname => $columns)
{
// Ensure the columns are in proper order.
ksort($columns);
$schema_create .= ',' . $crlf . ' ' . $keyname . ' (' . implode($columns, ', ') . ')';
}
// Now just get the comment and type... (MyISAM, etc.)
$result = $smcFunc['db_query']('', '
SHOW TABLE STATUS
LIKE {string:table}',
array(
'table' => strtr($tableName, array('_' => '\\_', '%' => '\\%')),
)
);
$row = $smcFunc['db_fetch_assoc']($result);
$smcFunc['db_free_result']($result);
// Probably MyISAM.... and it might have a comment.
$schema_create .= $crlf . ') ENGINE=' . (isset($row['Type']) ? $row['Type'] : $row['Engine']) . ($row['Comment'] != '' ? ' COMMENT="' . $row['Comment'] . '"' : '');
return $schema_create;
}
// Get the version number.
function smf_db_get_version()
{
global $smcFunc;
$request = $smcFunc['db_query']('', '
SELECT VERSION()',
array(
)
);
list ($ver) = $smcFunc['db_fetch_row']($request);
$smcFunc['db_free_result']($request);
return $ver;
}
?>

View File

@ -0,0 +1,328 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file contains rarely used extended database functionality.
void db_extra_init()
- add this file's functions to the $smcFunc array.
resource smf_db_backup_table($table, $backup_table)
- backup $table to $backup_table.
- returns the request handle to the table creation query
string function smf_db_get_version()
- get the version number.
string db_insert_sql(string table_name)
- gets all the necessary INSERTs for the table named table_name.
- goes in 250 row segments.
- returns the query to insert the data back in.
- returns an empty string if the table was empty.
array smf_db_list_tables($db = false, $filter = false)
- lists all tables in the database
- could be filtered according to $filter
- returns an array of table names. (strings)
float smf_db_optimize_table($table)
- optimize a table
- $table - the table to be optimized
- returns how much it was gained
string db_table_sql(string table_name)
- dumps the CREATE for the specified table. (by table_name.)
- returns the CREATE statement.
*/
// Add the file functions to the $smcFunc array.
function db_extra_init()
{
global $smcFunc;
if (!isset($smcFunc['db_backup_table']) || $smcFunc['db_backup_table'] != 'smf_db_backup_table')
$smcFunc += array(
'db_backup_table' => 'smf_db_backup_table',
'db_optimize_table' => 'smf_db_optimize_table',
'db_insert_sql' => 'smf_db_insert_sql',
'db_table_sql' => 'smf_db_table_sql',
'db_list_tables' => 'smf_db_list_tables',
'db_get_version' => 'smf_db_get_version',
);
}
// Backup $table to $backup_table.
function smf_db_backup_table($table, $backup_table)
{
global $smcFunc, $db_prefix;
$table = str_replace('{db_prefix}', $db_prefix, $table);
// Do we need to drop it first?
$tables = smf_db_list_tables(false, $backup_table);
if (!empty($tables))
$smcFunc['db_query']('', '
DROP TABLE {raw:backup_table}',
array(
'backup_table' => $backup_table,
)
);
//!!! Should we create backups of sequences as well?
$smcFunc['db_query']('', '
CREATE TABLE {raw:backup_table}
(
LIKE {raw:table}
INCLUDING DEFAULTS
)',
array(
'backup_table' => $backup_table,
'table' => $table,
)
);
$smcFunc['db_query']('', '
INSERT INTO {raw:backup_table}
SELECT * FROM {raw:table}',
array(
'backup_table' => $backup_table,
'table' => $table,
)
);
}
// Optimize a table - return data freed!
function smf_db_optimize_table($table)
{
global $smcFunc, $db_prefix;
$table = str_replace('{db_prefix}', $db_prefix, $table);
$request = $smcFunc['db_query']('', '
VACUUM ANALYZE {raw:table}',
array(
'table' => $table,
)
);
if (!$request)
return -1;
$row = $smcFunc['db_fetch_assoc']($request);
$smcFunc['db_free_result']($request);
if (isset($row['Data_free']))
return $row['Data_free'] / 1024;
else
return 0;
}
// List all the tables in the database.
function smf_db_list_tables($db = false, $filter = false)
{
global $smcFunc;
$request = $smcFunc['db_query']('', '
SELECT tablename
FROM pg_tables
WHERE schemaname = {string:schema_public}' . ($filter == false ? '' : '
AND tablename LIKE {string:filter}') . '
ORDER BY tablename',
array(
'schema_public' => 'public',
'filter' => $filter,
)
);
$tables = array();
while ($row = $smcFunc['db_fetch_row']($request))
$tables[] = $row[0];
$smcFunc['db_free_result']($request);
return $tables;
}
// Get the content (INSERTs) for a table.
function smf_db_insert_sql($tableName)
{
global $smcFunc, $db_prefix;
$tableName = str_replace('{db_prefix}', $db_prefix, $tableName);
// This will be handy...
$crlf = "\r\n";
// Get everything from the table.
$result = $smcFunc['db_query']('', '
SELECT *
FROM {raw:table}',
array(
'table' => $tableName,
)
);
// The number of rows, just for record keeping and breaking INSERTs up.
$num_rows = $smcFunc['db_num_rows']($result);
if ($num_rows == 0)
return '';
$fields = array_keys($smcFunc['db_fetch_assoc']($result));
$smcFunc['db_data_seek']($result, 0);
// Start it off with the basic INSERT INTO.
$data = '';
$insert_msg = $crlf . 'INSERT INTO ' . $tableName . $crlf . "\t" . '(' . implode(', ', $fields) . ')' . $crlf . 'VALUES ' . $crlf . "\t";
// Loop through each row.
while ($row = $smcFunc['db_fetch_row']($result))
{
// Get the fields in this row...
$field_list = array();
for ($j = 0; $j < $smcFunc['db_num_fields']($result); $j++)
{
// Try to figure out the type of each field. (NULL, number, or 'string'.)
if (!isset($row[$j]))
$field_list[] = 'NULL';
elseif (is_numeric($row[$j]) && (int) $row[$j] == $row[$j])
$field_list[] = $row[$j];
else
$field_list[] = '\'' . $smcFunc['db_escape_string']($row[$j]) . '\'';
}
// 'Insert' the data.
$data .= $insert_msg . '(' . implode(', ', $field_list) . ');';
}
$smcFunc['db_free_result']($result);
// Return an empty string if there were no rows.
return $num_rows == 0 ? '' : $data;
}
// Get the schema (CREATE) for a table.
function smf_db_table_sql($tableName)
{
global $smcFunc, $db_prefix;
$tableName = str_replace('{db_prefix}', $db_prefix, $tableName);
// This will be needed...
$crlf = "\r\n";
// Start the create table...
$schema_create = 'CREATE TABLE ' . $tableName . ' (' . $crlf;
$index_create = '';
$seq_create = '';
// Find all the fields.
$result = $smcFunc['db_query']('', '
SELECT column_name, column_default, is_nullable, data_type, character_maximum_length
FROM information_schema.columns
WHERE table_name = {string:table}
ORDER BY ordinal_position',
array(
'table' => $tableName,
)
);
while ($row = $smcFunc['db_fetch_assoc']($result))
{
if ($row['data_type'] == 'character varying')
$row['data_type'] = 'varchar';
elseif ($row['data_type'] == 'character')
$row['data_type'] = 'char';
if ($row['character_maximum_length'])
$row['data_type'] .= '(' . $row['character_maximum_length'] . ')';
// Make the CREATE for this column.
$schema_create .= ' "' . $row['column_name'] . '" ' . $row['data_type'] . ($row['is_nullable'] != 'YES' ? ' NOT NULL' : '');
// Add a default...?
if (trim($row['column_default']) != '')
{
$schema_create .= ' default ' . $row['column_default'] . '';
// Auto increment?
if (preg_match('~nextval\(\'(.+?)\'(.+?)*\)~i', $row['column_default'], $matches) != 0)
{
// Get to find the next variable first!
$count_req = $smcFunc['db_query']('', '
SELECT MAX("{raw:column}")
FROM {raw:table}',
array(
'column' => $row['column_name'],
'table' => $tableName,
)
);
list ($max_ind) = $smcFunc['db_fetch_row']($count_req);
$smcFunc['db_free_result']($count_req);
// Get the right bloody start!
$seq_create .= 'CREATE SEQUENCE ' . $matches[1] . ' START WITH ' . ($max_ind + 1) . ';' . $crlf . $crlf;
}
}
$schema_create .= ',' . $crlf;
}
$smcFunc['db_free_result']($result);
// Take off the last comma.
$schema_create = substr($schema_create, 0, -strlen($crlf) - 1);
$result = $smcFunc['db_query']('', '
SELECT CASE WHEN i.indisprimary THEN 1 ELSE 0 END AS is_primary, pg_get_indexdef(i.indexrelid) AS inddef
FROM pg_class AS c
INNER JOIN pg_index AS i ON (i.indrelid = c.oid)
INNER JOIN pg_class AS c2 ON (c2.oid = i.indexrelid)
WHERE c.relname = {string:table}',
array(
'table' => $tableName,
)
);
$indexes = array();
while ($row = $smcFunc['db_fetch_assoc']($result))
{
if ($row['is_primary'])
{
if (preg_match('~\(([^\)]+?)\)~i', $row['inddef'], $matches) == 0)
continue;
$index_create .= $crlf . 'ALTER TABLE ' . $tableName . ' ADD PRIMARY KEY ("' . $matches[1] . '");';
}
else
$index_create .= $crlf . $row['inddef'] . ';';
}
$smcFunc['db_free_result']($result);
// Finish it off!
$schema_create .= $crlf . ');';
return $seq_create . $schema_create . $index_create;
}
// Get the version number.
function smf_db_get_version()
{
global $smcFunc;
$request = $smcFunc['db_query']('', '
SHOW server_version',
array(
)
);
list ($ver) = $smcFunc['db_fetch_row']($request);
$smcFunc['db_free_result']($request);
return $ver;
}
?>

346
Sources/DbExtra-sqlite.php Normal file
View File

@ -0,0 +1,346 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file contains rarely used extended database functionality.
void db_extra_init()
- add this file's functions to the $smcFunc array.
resource smf_db_backup_table($table, $backup_table)
- backup $table to $backup_table.
- returns the request handle to the table creation query
string function smf_db_get_version()
- get the version number.
string db_insert_sql(string table_name)
- gets all the necessary INSERTs for the table named table_name.
- goes in 250 row segments.
- returns the query to insert the data back in.
- returns an empty string if the table was empty.
array smf_db_list_tables($db = false, $filter = false)
- lists all tables in the database
- could be filtered according to $filter
- returns an array of table names. (strings)
float smf_db_optimize_table($table)
- optimize a table
- $table - the table to be optimized
- returns how much it was gained
string db_table_sql(string table_name)
- dumps the CREATE for the specified table. (by table_name.)
- returns the CREATE statement.
*/
// Add the file functions to the $smcFunc array.
function db_extra_init()
{
global $smcFunc;
if (!isset($smcFunc['db_backup_table']) || $smcFunc['db_backup_table'] != 'smf_db_backup_table')
$smcFunc += array(
'db_backup_table' => 'smf_db_backup_table',
'db_optimize_table' => 'smf_db_optimize_table',
'db_insert_sql' => 'smf_db_insert_sql',
'db_table_sql' => 'smf_db_table_sql',
'db_list_tables' => 'smf_db_list_tables',
'db_get_backup' => 'smf_db_get_backup',
'db_get_version' => 'smf_db_get_version',
);
}
// Backup $table to $backup_table.
function smf_db_backup_table($table, $backup_table)
{
global $smcFunc, $db_prefix;
$table = str_replace('{db_prefix}', $db_prefix, $table);
$result = $smcFunc['db_query']('', '
SELECT sql
FROM sqlite_master
WHERE type = {string:txttable}
AND name = {string:table}',
array(
'table' => $table,
'txttable' => 'table'
)
);
list ($create) = $smcFunc['db_fetch_row']($result);
$smcFunc['db_free_result']($result);
$create = preg_split('/[\n\r]/', $create);
$auto_inc = '';
// Remove the first line and check to see if the second one contain useless info.
unset($create[0]);
if (trim($create[1]) == '(')
unset($create[1]);
if (trim($create[count($create)]) == ')')
unset($create[count($create)]);
foreach ($create as $k => $l)
{
// Get the name of the auto_increment column.
if (strpos($l, 'primary') || strpos($l, 'PRIMARY'))
$auto_inc = trim($l);
// Skip everything but keys...
if ((strpos($l, 'KEY') !== false && strpos($l, 'PRIMARY KEY') === false) || strpos($l, $table) !== false || strpos(trim($l), 'PRIMARY KEY') === 0)
unset($create[$k]);
}
if (!empty($create))
$create = '(
' . implode('
', $create) . ')';
else
$create = '';
// Is there an extra junk at the end?
if (substr($create, -2, 1) == ',')
$create = substr($create, 0, -2) . ')';
if (substr($create, -2) == '))')
$create = substr($create, 0, -1);
$smcFunc['db_query']('', '
DROP TABLE {raw:backup_table}',
array(
'backup_table' => $backup_table,
'db_error_skip' => true,
)
);
$request = $smcFunc['db_quote']('
CREATE TABLE {raw:backup_table} {raw:create}',
array(
'backup_table' => $backup_table,
'create' => $create,
));
$smcFunc['db_query']('', '
CREATE TABLE {raw:backup_table} {raw:create}',
array(
'backup_table' => $backup_table,
'create' => $create,
));
$request = $smcFunc['db_query']('', '
INSERT INTO {raw:backup_table}
SELECT *
FROM {raw:table}',
array(
'backup_table' => $backup_table,
'table' => $table,
));
return $request;
}
// Optimize a table - return data freed!
function smf_db_optimize_table($table)
{
global $smcFunc, $db_prefix;
$table = str_replace('{db_prefix}', $db_prefix, $table);
$request = $smcFunc['db_query']('', '
VACUUM {raw:table}',
array(
'table' => $table,
)
);
if (!$request)
return -1;
$row = $smcFunc['db_fetch_assoc']($request);
$smcFunc['db_free_result']($request);
// The function returns nothing.
return 0;
}
// List all the tables in the database.
function smf_db_list_tables($db = false, $filter = false)
{
global $smcFunc;
$filter = $filter == false ? '' : ' AND name LIKE \'' . str_replace("\_", "_", $filter) . '\'';
$request = $smcFunc['db_query']('', '
SELECT name
FROM sqlite_master
WHERE type = {string:type}
{raw:filter}
ORDER BY name',
array(
'type' => 'table',
'filter' => $filter,
)
);
$tables = array();
while ($row = $smcFunc['db_fetch_row']($request))
$tables[] = $row[0];
$smcFunc['db_free_result']($request);
return $tables;
}
// Get the content (INSERTs) for a table.
function smf_db_insert_sql($tableName)
{
global $smcFunc, $db_prefix;
$tableName = str_replace('{db_prefix}', $db_prefix, $tableName);
// This will be handy...
$crlf = "\r\n";
// Get everything from the table.
$result = $smcFunc['db_query']('', '
SELECT *
FROM {raw:table}',
array(
'table' => $tableName,
)
);
// The number of rows, just for record keeping and breaking INSERTs up.
$num_rows = $smcFunc['db_num_rows']($result);
if ($num_rows == 0)
return '';
$fields = array_keys($smcFunc['db_fetch_assoc']($result));
// SQLite fetches an array so we need to filter out the numberic index for the columns.
foreach ($fields as $key => $name)
if (is_numeric($name))
unset($fields[$key]);
$smcFunc['db_data_seek']($result, 0);
// Start it off with the basic INSERT INTO.
$data = 'BEGIN TRANSACTION;' . $crlf;
// Loop through each row.
while ($row = $smcFunc['db_fetch_row']($result))
{
// Get the fields in this row...
$field_list = array();
for ($j = 0; $j < $smcFunc['db_num_fields']($result); $j++)
{
// Try to figure out the type of each field. (NULL, number, or 'string'.)
if (!isset($row[$j]))
$field_list[] = 'NULL';
elseif (is_numeric($row[$j]) && (int) $row[$j] == $row[$j])
$field_list[] = $row[$j];
else
$field_list[] = '\'' . $smcFunc['db_escape_string']($row[$j]) . '\'';
}
$data .= 'INSERT INTO ' . $tableName . ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $field_list) . ');' . $crlf;
}
$smcFunc['db_free_result']($result);
// Return an empty string if there were no rows.
return $num_rows == 0 ? '' : $data . 'COMMIT;' . $crlf;
}
// Get the schema (CREATE) for a table.
function smf_db_table_sql($tableName)
{
global $smcFunc, $db_prefix;
$tableName = str_replace('{db_prefix}', $db_prefix, $tableName);
// This will be needed...
$crlf = "\r\n";
// Start the create table...
$schema_create = '';
$index_create = '';
// Let's get the create statement directly from SQLite.
$result = $smcFunc['db_query']('', '
SELECT sql
FROM sqlite_master
WHERE type = {string:type}
AND name = {string:table_name}',
array(
'type' => 'table',
'table_name' => $tableName,
)
);
list ($schema_create) = $smcFunc['db_fetch_row']($result);
$smcFunc['db_free_result']($result);
// Now the indexes.
$result = $smcFunc['db_query']('', '
SELECT sql
FROM sqlite_master
WHERE type = {string:type}
AND tbl_name = {string:table_name}',
array(
'type' => 'index',
'table_name' => $tableName,
)
);
$indexes = array();
while ($row = $smcFunc['db_fetch_assoc']($result))
if (trim($row['sql']) != '')
$indexes[] = $row['sql'];
$smcFunc['db_free_result']($result);
$index_create .= implode(';' . $crlf, $indexes);
$schema_create = empty($indexes) ? rtrim($schema_create) : $schema_create . ';' . $crlf . $crlf;
return $schema_create . $index_create;
}
// Get the version number.
function smf_db_get_version()
{
return sqlite_libversion();
}
// Simple return the database - and die!
function smf_db_get_backup()
{
global $db_name;
$db_file = substr($db_name, -3) === '.db' ? $db_name : $db_name . '.db';
// Add more info if zipped...
$ext = '';
if (isset($_REQUEST['compress']) && function_exists('gzencode'))
$ext = '.gz';
// Do the remaining headers.
header('Content-Disposition: attachment; filename="' . $db_file . $ext . '"');
header('Cache-Control: private');
header('Connection: close');
// Literally dump the contents. Try reading the file first.
if (@readfile($db_file) == null)
echo file_get_contents($db_file);
obExit(false);
}
?>

View File

@ -0,0 +1,582 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file contains database functionality specifically designed for packages to utilize.
bool smf_db_create_table(string table_name, array columns, array indexes = array(),
array parameters = array(), string if_exists = 'ignore')
- Can be used to create a table without worrying about schema compatabilities.
- If the table exists will, by default, do nothing.
- Builds table with columns as passed to it - at least one column must be sent.
The columns array should have one sub-array for each column - these sub arrays contain:
+ 'name' = Column name
+ 'type' = Type of column - values from (smallint,mediumint,int,text,varchar,char,tinytext,mediumtext,largetext)
+ 'size' => Size of column (If applicable) - for example 255 for a large varchar, 10 for an int etc. If not
set SMF will pick a size.
+ 'default' = Default value - do not set if no default required.
+ 'null' => Can it be null (true or false) - if not set default will be false.
+ 'auto' => Set to true to make it an auto incrementing column. Set to a numerical value to set
from what it should begin counting.
- Adds indexes as specified within indexes parameter. Each index should be a member of $indexes. Values are:
+ 'name' => Index name (If left empty SMF will generate).
+ 'type' => Type of index. Choose from 'primary', 'unique' or 'index'. If not set will default to 'index'.
+ 'columns' => Array containing columns that form part of key - in the order the index is to be created.
- parameters: (None yet)
- if_exists values:
+ 'ignore' will do nothing if the table exists. (And will return true)
+ 'overwrite' will drop any existing table of the same name.
+ 'error' will return false if the table already exists.
*/
// Add the file functions to the $smcFunc array.
function db_packages_init()
{
global $smcFunc, $reservedTables, $db_package_log, $db_prefix;
if (!isset($smcFunc['db_create_table']) || $smcFunc['db_create_table'] != 'smf_db_create_table')
{
$smcFunc += array(
'db_add_column' => 'smf_db_add_column',
'db_add_index' => 'smf_db_add_index',
'db_calculate_type' => 'smf_db_calculate_type',
'db_change_column' => 'smf_db_change_column',
'db_create_table' => 'smf_db_create_table',
'db_drop_table' => 'smf_db_drop_table',
'db_table_structure' => 'smf_db_table_structure',
'db_list_columns' => 'smf_db_list_columns',
'db_list_indexes' => 'smf_db_list_indexes',
'db_remove_column' => 'smf_db_remove_column',
'db_remove_index' => 'smf_db_remove_index',
);
$db_package_log = array();
}
// We setup an array of SMF tables we can't do auto-remove on - in case a mod writer cocks it up!
$reservedTables = array('admin_info_files', 'approval_queue', 'attachments', 'ban_groups', 'ban_items',
'board_permissions', 'boards', 'calendar', 'calendar_holidays', 'categories', 'collapsed_categories',
'custom_fields', 'group_moderators', 'log_actions', 'log_activity', 'log_banned', 'log_boards',
'log_digest', 'log_errors', 'log_floodcontrol', 'log_group_requests', 'log_karma', 'log_mark_read',
'log_notify', 'log_online', 'log_packages', 'log_polls', 'log_reported', 'log_reported_comments',
'log_scheduled_tasks', 'log_search_messages', 'log_search_results', 'log_search_subjects',
'log_search_topics', 'log_topics', 'mail_queue', 'membergroups', 'members', 'message_icons',
'messages', 'moderators', 'package_servers', 'permission_profiles', 'permissions', 'personal_messages',
'pm_recipients', 'poll_choices', 'polls', 'scheduled_tasks', 'sessions', 'settings', 'smileys',
'themes', 'topics');
foreach ($reservedTables as $k => $table_name)
$reservedTables[$k] = strtolower($db_prefix . $table_name);
// We in turn may need the extra stuff.
db_extend('extra');
}
// Create a table.
function smf_db_create_table($table_name, $columns, $indexes = array(), $parameters = array(), $if_exists = 'ignore', $error = 'fatal')
{
global $reservedTables, $smcFunc, $db_package_log, $db_prefix, $db_character_set;
// Strip out the table name, we might not need it in some cases
$real_prefix = preg_match('~^(`?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix;
// With or without the database name, the fullname looks like this.
$full_table_name = str_replace('{db_prefix}', $real_prefix, $table_name);
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// First - no way do we touch SMF tables.
if (in_array(strtolower($table_name), $reservedTables))
return false;
// Log that we'll want to remove this on uninstall.
$db_package_log[] = array('remove_table', $table_name);
// Slightly easier on MySQL than the others...
$tables = $smcFunc['db_list_tables']();
if (in_array($full_table_name, $tables))
{
// This is a sad day... drop the table? If not, return false (error) by default.
if ($if_exists == 'overwrite')
$smcFunc['db_drop_table']($table_name);
else
return $if_exists == 'ignore';
}
// Righty - let's do the damn thing!
$table_query = 'CREATE TABLE ' . $table_name . "\n" . '(';
foreach ($columns as $column)
{
// Auto increment is easy here!
if (!empty($column['auto']))
{
$default = 'auto_increment';
}
elseif (isset($column['default']) && $column['default'] !== null)
$default = 'default \'' . $smcFunc['db_escape_string']($column['default']) . '\'';
else
$default = '';
// Sort out the size... and stuff...
$column['size'] = isset($column['size']) && is_numeric($column['size']) ? $column['size'] : null;
list ($type, $size) = $smcFunc['db_calculate_type']($column['type'], $column['size']);
// Allow unsigned integers (mysql only)
$unsigned = in_array($type, array('int', 'tinyint', 'smallint', 'mediumint', 'bigint')) && !empty($column['unsigned']) ? 'unsigned ' : '';
if ($size !== null)
$type = $type . '(' . $size . ')';
// Now just put it together!
$table_query .= "\n\t`" .$column['name'] . '` ' . $type . ' ' . (!empty($unsigned) ? $unsigned : '') . (!empty($column['null']) ? '' : 'NOT NULL') . ' ' . $default . ',';
}
// Loop through the indexes next...
foreach ($indexes as $index)
{
$columns = implode(',', $index['columns']);
// Is it the primary?
if (isset($index['type']) && $index['type'] == 'primary')
$table_query .= "\n\t" . 'PRIMARY KEY (' . implode(',', $index['columns']) . '),';
else
{
if (empty($index['name']))
$index['name'] = implode('_', $index['columns']);
$table_query .= "\n\t" . (isset($index['type']) && $index['type'] == 'unique' ? 'UNIQUE' : 'KEY') . ' ' . $index['name'] . ' (' . $columns . '),';
}
}
// No trailing commas!
if (substr($table_query, -1) == ',')
$table_query = substr($table_query, 0, -1);
$table_query .= ') ENGINE=MyISAM';
if (!empty($db_character_set) && $db_character_set == 'utf8')
$table_query .= ' DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci';
// Create the table!
$smcFunc['db_query']('', $table_query,
array(
'security_override' => true,
)
);
}
// Drop a table.
function smf_db_drop_table($table_name, $parameters = array(), $error = 'fatal')
{
global $reservedTables, $smcFunc, $db_prefix;
// After stripping away the database name, this is what's left.
$real_prefix = preg_match('~^(`?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix;
// Get some aliases.
$full_table_name = str_replace('{db_prefix}', $real_prefix, $table_name);
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// God no - dropping one of these = bad.
if (in_array(strtolower($table_name), $reservedTables))
return false;
// Does it exist?
if (in_array($full_table_name, $smcFunc['db_list_tables']()))
{
$query = 'DROP TABLE ' . $table_name;
$smcFunc['db_query']('',
$query,
array(
'security_override' => true,
)
);
return true;
}
// Otherwise do 'nout.
return false;
}
// Add a column.
function smf_db_add_column($table_name, $column_info, $parameters = array(), $if_exists = 'update', $error = 'fatal')
{
global $smcFunc, $db_package_log, $txt, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// Log that we will want to uninstall this!
$db_package_log[] = array('remove_column', $table_name, $column_info['name']);
// Does it exist - if so don't add it again!
$columns = $smcFunc['db_list_columns']($table_name, false);
foreach ($columns as $column)
if ($column == $column_info['name'])
{
// If we're going to overwrite then use change column.
if ($if_exists == 'update')
return $smcFunc['db_change_column']($table_name, $column_info['name'], $column_info);
else
return false;
}
// Get the specifics...
$column_info['size'] = isset($column_info['size']) && is_numeric($column_info['size']) ? $column_info['size'] : null;
list ($type, $size) = $smcFunc['db_calculate_type']($column_info['type'], $column_info['size']);
// Allow unsigned integers (mysql only)
$unsigned = in_array($type, array('int', 'tinyint', 'smallint', 'mediumint', 'bigint')) && !empty($column_info['unsigned']) ? 'unsigned ' : '';
if ($size !== null)
$type = $type . '(' . $size . ')';
// Now add the thing!
$query = '
ALTER TABLE ' . $table_name . '
ADD `' . $column_info['name'] . '` ' . $type . ' ' . (!empty($unsigned) ? $unsigned : '') . (empty($column_info['null']) ? 'NOT NULL' : '') . ' ' .
(!isset($column_info['default']) ? '' : 'default \'' . $smcFunc['db_escape_string']($column_info['default']) . '\'') . ' ' .
(empty($column_info['auto']) ? '' : 'auto_increment primary key') . ' ';
$smcFunc['db_query']('', $query,
array(
'security_override' => true,
)
);
return true;
}
// Remove a column.
function smf_db_remove_column($table_name, $column_name, $parameters = array(), $error = 'fatal')
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// Does it exist?
$columns = $smcFunc['db_list_columns']($table_name, true);
foreach ($columns as $column)
if ($column['name'] == $column_name)
{
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
DROP COLUMN ' . $column_name,
array(
'security_override' => true,
)
);
return true;
}
// If here we didn't have to work - joy!
return false;
}
// Change a column.
function smf_db_change_column($table_name, $old_column, $column_info, $parameters = array(), $error = 'fatal')
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// Check it does exist!
$columns = $smcFunc['db_list_columns']($table_name, true);
$old_info = null;
foreach ($columns as $column)
if ($column['name'] == $old_column)
$old_info = $column;
// Nothing?
if ($old_info == null)
return false;
// Get the right bits.
if (!isset($column_info['name']))
$column_info['name'] = $old_column;
if (!isset($column_info['default']))
$column_info['default'] = $old_info['default'];
if (!isset($column_info['null']))
$column_info['null'] = $old_info['null'];
if (!isset($column_info['auto']))
$column_info['auto'] = $old_info['auto'];
if (!isset($column_info['type']))
$column_info['type'] = $old_info['type'];
if (!isset($column_info['size']) || !is_numeric($column_info['size']))
$column_info['size'] = $old_info['size'];
if (!isset($column_info['unsigned']) || !in_array($column_info['type'], array('int', 'tinyint', 'smallint', 'mediumint', 'bigint')))
$column_info['unsigned'] = '';
list ($type, $size) = $smcFunc['db_calculate_type']($column_info['type'], $column_info['size']);
// Allow for unsigned integers (mysql only)
$unsigned = in_array($type, array('int', 'tinyint', 'smallint', 'mediumint', 'bigint')) && !empty($column_info['unsigned']) ? 'unsigned ' : '';
if ($size !== null)
$type = $type . '(' . $size . ')';
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
CHANGE COLUMN `' . $old_column . '` `' . $column_info['name'] . '` ' . $type . ' ' . (!empty($unsigned) ? $unsigned : '') . (empty($column_info['null']) ? 'NOT NULL' : '') . ' ' .
(!isset($column_info['default']) ? '' : 'default \'' . $smcFunc['db_escape_string']($column_info['default']) . '\'') . ' ' .
(empty($column_info['auto']) ? '' : 'auto_increment') . ' ',
array(
'security_override' => true,
)
);
}
// Add an index.
function smf_db_add_index($table_name, $index_info, $parameters = array(), $if_exists = 'update', $error = 'fatal')
{
global $smcFunc, $db_package_log, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// No columns = no index.
if (empty($index_info['columns']))
return false;
$columns = implode(',', $index_info['columns']);
// No name - make it up!
if (empty($index_info['name']))
{
// No need for primary.
if (isset($index_info['type']) && $index_info['type'] == 'primary')
$index_info['name'] = '';
else
$index_info['name'] = implode('_', $index_info['columns']);
}
else
$index_info['name'] = $index_info['name'];
// Log that we are going to want to remove this!
$db_package_log[] = array('remove_index', $table_name, $index_info['name']);
// Let's get all our indexes.
$indexes = $smcFunc['db_list_indexes']($table_name, true);
// Do we already have it?
foreach ($indexes as $index)
{
if ($index['name'] == $index_info['name'] || ($index['type'] == 'primary' && isset($index_info['type']) && $index_info['type'] == 'primary'))
{
// If we want to overwrite simply remove the current one then continue.
if ($if_exists != 'update' || $index['type'] == 'primary')
return false;
else
$smcFunc['db_remove_index']($table_name, $index_info['name']);
}
}
// If we're here we know we don't have the index - so just add it.
if (!empty($index_info['type']) && $index_info['type'] == 'primary')
{
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
ADD PRIMARY KEY (' . $columns . ')',
array(
'security_override' => true,
)
);
}
else
{
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
ADD ' . (isset($index_info['type']) && $index_info['type'] == 'unique' ? 'UNIQUE' : 'INDEX') . ' ' . $index_info['name'] . ' (' . $columns . ')',
array(
'security_override' => true,
)
);
}
}
// Remove an index.
function smf_db_remove_index($table_name, $index_name, $parameters = array(), $error = 'fatal')
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// Better exist!
$indexes = $smcFunc['db_list_indexes']($table_name, true);
foreach ($indexes as $index)
{
// If the name is primary we want the primary key!
if ($index['type'] == 'primary' && $index_name == 'primary')
{
// Dropping primary key?
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
DROP PRIMARY KEY',
array(
'security_override' => true,
)
);
return true;
}
if ($index['name'] == $index_name)
{
// Drop the bugger...
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
DROP INDEX ' . $index_name,
array(
'security_override' => true,
)
);
return true;
}
}
// Not to be found ;(
return false;
}
// Get the schema formatted name for a type.
function smf_db_calculate_type($type_name, $type_size = null, $reverse = false)
{
// MySQL is actually the generic baseline.
return array($type_name, $type_size);
}
// Get table structure.
function smf_db_table_structure($table_name, $parameters = array())
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
return array(
'name' => $table_name,
'columns' => $smcFunc['db_list_columns']($table_name, true),
'indexes' => $smcFunc['db_list_indexes']($table_name, true),
);
}
// Return column information for a table.
function smf_db_list_columns($table_name, $detail = false, $parameters = array())
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
$result = $smcFunc['db_query']('', '
SHOW FIELDS
FROM {raw:table_name}',
array(
'table_name' => substr($table_name, 0, 1) == '`' ? $table_name : '`' . $table_name . '`',
)
);
$columns = array();
while ($row = $smcFunc['db_fetch_assoc']($result))
{
if (!$detail)
{
$columns[] = $row['Field'];
}
else
{
// Is there an auto_increment?
$auto = strpos($row['Extra'], 'auto_increment') !== false ? true : false;
// Can we split out the size?
if (preg_match('~(.+?)\s*\((\d+)\)(?:(?:\s*)?(unsigned))?~i', $row['Type'], $matches) === 1)
{
$type = $matches[1];
$size = $matches[2];
if (!empty($matches[3]) && $matches[3] == 'unsigned')
$unsigned = true;
}
else
{
$type = $row['Type'];
$size = null;
}
$columns[$row['Field']] = array(
'name' => $row['Field'],
'null' => $row['Null'] != 'YES' ? false : true,
'default' => isset($row['Default']) ? $row['Default'] : null,
'type' => $type,
'size' => $size,
'auto' => $auto,
);
if (isset($unsigned))
{
$columns[$row['Field']]['unsigned'] = $unsigned;
unset($unsigned);
}
}
}
$smcFunc['db_free_result']($result);
return $columns;
}
// What about some index information?
function smf_db_list_indexes($table_name, $detail = false, $parameters = array())
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
$result = $smcFunc['db_query']('', '
SHOW KEYS
FROM {raw:table_name}',
array(
'table_name' => substr($table_name, 0, 1) == '`' ? $table_name : '`' . $table_name . '`',
)
);
$indexes = array();
while ($row = $smcFunc['db_fetch_assoc']($result))
{
if (!$detail)
$indexes[] = $row['Key_name'];
else
{
// What is the type?
if ($row['Key_name'] == 'PRIMARY')
$type = 'primary';
elseif (empty($row['Non_unique']))
$type = 'unique';
elseif (isset($row['Index_type']) && $row['Index_type'] == 'FULLTEXT')
$type = 'fulltext';
else
$type = 'index';
// This is the first column we've seen?
if (empty($indexes[$row['Key_name']]))
{
$indexes[$row['Key_name']] = array(
'name' => $row['Key_name'],
'type' => $type,
'columns' => array(),
);
}
// Is it a partial index?
if (!empty($row['Sub_part']))
$indexes[$row['Key_name']]['columns'][] = $row['Column_name'] . '(' . $row['Sub_part'] . ')';
else
$indexes[$row['Key_name']]['columns'][] = $row['Column_name'];
}
}
$smcFunc['db_free_result']($result);
return $indexes;
}
?>

View File

@ -0,0 +1,746 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file contains database functionality specifically designed for packages to utilize.
bool smf_db_create_table(string table_name, array columns, array indexes = array(),
array parameters = array(), string if_exists = 'ignore')
- Can be used to create a table without worrying about schema compatabilities.
- If the table exists will, by default, do nothing.
- Builds table with columns as passed to it - at least one column must be sent.
The columns array should have one sub-array for each column - these sub arrays contain:
+ 'name' = Column name
+ 'type' = Type of column - values from (smallint,mediumint,int,text,varchar,char,tinytext,mediumtext,largetext)
+ 'size' => Size of column (If applicable) - for example 255 for a large varchar, 10 for an int etc. If not
set SMF will pick a size.
+ 'default' = Default value - do not set if no default required.
+ 'null' => Can it be null (true or false) - if not set default will be false.
+ 'auto' => Set to true to make it an auto incrementing column. Set to a numerical value to set
from what it should begin counting.
- Adds indexes as specified within indexes parameter. Each index should be a member of $indexes. Values are:
+ 'name' => Index name (If left empty SMF will generate).
+ 'type' => Type of index. Choose from 'primary', 'unique' or 'index'. If not set will default to 'index'.
+ 'columns' => Array containing columns that form part of key - in the order the index is to be created.
- parameters: (None yet)
- if_exists values:
+ 'ignore' will do nothing if the table exists. (And will return true)
+ 'overwrite' will drop any existing table of the same name.
+ 'error' will return false if the table already exists.
*/
// Add the file functions to the $smcFunc array.
function db_packages_init()
{
global $smcFunc, $reservedTables, $db_package_log, $db_prefix;
if (!isset($smcFunc['db_create_table']) || $smcFunc['db_create_table'] != 'smf_db_create_table')
{
$smcFunc += array(
'db_add_column' => 'smf_db_add_column',
'db_add_index' => 'smf_db_add_index',
'db_calculate_type' => 'smf_db_calculate_type',
'db_change_column' => 'smf_db_change_column',
'db_create_table' => 'smf_db_create_table',
'db_drop_table' => 'smf_db_drop_table',
'db_table_structure' => 'smf_db_table_structure',
'db_list_columns' => 'smf_db_list_columns',
'db_list_indexes' => 'smf_db_list_indexes',
'db_remove_column' => 'smf_db_remove_column',
'db_remove_index' => 'smf_db_remove_index',
);
$db_package_log = array();
}
// We setup an array of SMF tables we can't do auto-remove on - in case a mod writer cocks it up!
$reservedTables = array('admin_info_files', 'approval_queue', 'attachments', 'ban_groups', 'ban_items',
'board_permissions', 'boards', 'calendar', 'calendar_holidays', 'categories', 'collapsed_categories',
'custom_fields', 'group_moderators', 'log_actions', 'log_activity', 'log_banned', 'log_boards',
'log_digest', 'log_errors', 'log_floodcontrol', 'log_group_requests', 'log_karma', 'log_mark_read',
'log_notify', 'log_online', 'log_packages', 'log_polls', 'log_reported', 'log_reported_comments',
'log_scheduled_tasks', 'log_search_messages', 'log_search_results', 'log_search_subjects',
'log_search_topics', 'log_topics', 'mail_queue', 'membergroups', 'members', 'message_icons',
'messages', 'moderators', 'package_servers', 'permission_profiles', 'permissions', 'personal_messages',
'pm_recipients', 'poll_choices', 'polls', 'scheduled_tasks', 'sessions', 'settings', 'smileys',
'themes', 'topics');
foreach ($reservedTables as $k => $table_name)
$reservedTables[$k] = strtolower($db_prefix . $table_name);
// We in turn may need the extra stuff.
db_extend('extra');
}
// Create a table.
function smf_db_create_table($table_name, $columns, $indexes = array(), $parameters = array(), $if_exists = 'ignore', $error = 'fatal')
{
global $reservedTables, $smcFunc, $db_package_log, $db_prefix;
// Strip out the table name, we might not need it in some cases
$real_prefix = preg_match('~^("?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix;
// With or without the database name, the fullname looks like this.
$full_table_name = str_replace('{db_prefix}', $real_prefix, $table_name);
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// First - no way do we touch SMF tables.
if (in_array(strtolower($table_name), $reservedTables))
return false;
// Log that we'll want to remove this on uninstall.
$db_package_log[] = array('remove_table', $table_name);
// This... my friends... is a function in a half - let's start by checking if the table exists!
$tables = $smcFunc['db_list_tables']();
if (in_array($full_table_name, $tables))
{
// This is a sad day... drop the table? If not, return false (error) by default.
if ($if_exists == 'overwrite')
$smcFunc['db_drop_table']($table_name);
else
return $if_exists == 'ignore';
}
// If we've got this far - good news - no table exists. We can build our own!
$smcFunc['db_transaction']('begin');
$table_query = 'CREATE TABLE ' . $table_name . "\n" . '(';
foreach ($columns as $column)
{
// If we have an auto increment do it!
if (!empty($column['auto']))
{
$smcFunc['db_query']('', '
CREATE SEQUENCE ' . $table_name . '_seq',
array(
'security_override' => true,
)
);
$default = 'default nextval(\'' . $table_name . '_seq\')';
}
elseif (isset($column['default']) && $column['default'] !== null)
$default = 'default \'' . $smcFunc['db_escape_string']($column['default']) . '\'';
else
$default = '';
// Sort out the size...
$column['size'] = isset($column['size']) && is_numeric($column['size']) ? $column['size'] : null;
list ($type, $size) = $smcFunc['db_calculate_type']($column['type'], $column['size']);
if ($size !== null)
$type = $type . '(' . $size . ')';
// Now just put it together!
$table_query .= "\n\t\"" . $column['name'] . '" ' . $type . ' ' . (!empty($column['null']) ? '' : 'NOT NULL') . ' ' . $default . ',';
}
// Loop through the indexes a sec...
$index_queries = array();
foreach ($indexes as $index)
{
$columns = implode(',', $index['columns']);
// Primary goes in the table...
if (isset($index['type']) && $index['type'] == 'primary')
$table_query .= "\n\t" . 'PRIMARY KEY (' . implode(',', $index['columns']) . '),';
else
{
if (empty($index['name']))
$index['name'] = implode('_', $index['columns']);
$index_queries[] = 'CREATE ' . (isset($index['type']) && $index['type'] == 'unique' ? 'UNIQUE' : '') . ' INDEX ' . $table_name . '_' . $index['name'] . ' ON ' . $table_name . ' (' . $columns . ')';
}
}
// No trailing commas!
if (substr($table_query, -1) == ',')
$table_query = substr($table_query, 0, -1);
$table_query .= ')';
// Create the table!
$smcFunc['db_query']('', $table_query,
array(
'security_override' => true,
)
);
// And the indexes...
foreach ($index_queries as $query)
$smcFunc['db_query']('', $query,
array(
'security_override' => true,
)
);
// Go, go power rangers!
$smcFunc['db_transaction']('commit');
}
// Drop a table.
function smf_db_drop_table($table_name, $parameters = array(), $error = 'fatal')
{
global $reservedTables, $smcFunc, $db_prefix;
// After stripping away the database name, this is what's left.
$real_prefix = preg_match('~^("?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix;
// Get some aliases.
$full_table_name = str_replace('{db_prefix}', $real_prefix, $table_name);
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// God no - dropping one of these = bad.
if (in_array(strtolower($table_name), $reservedTables))
return false;
// Does it exist?
if (in_array($full_table_name, $smcFunc['db_list_tables']()))
{
// We can then drop the table.
$smcFunc['db_transaction']('begin');
// the table
$table_query = 'DROP TABLE ' . $table_name;
// and the assosciated sequence, if any
$sequence_query = 'DROP SEQUENCE IF EXISTS ' . $table_name . '_seq';
// drop them
$smcFunc['db_query']('',
$table_query,
array(
'security_override' => true,
)
);
$smcFunc['db_query']('',
$sequence_query,
array(
'security_override' => true,
)
);
$smcFunc['db_transaction']('commit');
return true;
}
// Otherwise do 'nout.
return false;
}
// Add a column.
function smf_db_add_column($table_name, $column_info, $parameters = array(), $if_exists = 'update', $error = 'fatal')
{
global $smcFunc, $db_package_log, $txt, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// Log that we will want to uninstall this!
$db_package_log[] = array('remove_column', $table_name, $column_info['name']);
// Does it exist - if so don't add it again!
$columns = $smcFunc['db_list_columns']($table_name, false);
foreach ($columns as $column)
if ($column == $column_info['name'])
{
// If we're going to overwrite then use change column.
if ($if_exists == 'update')
return $smcFunc['db_change_column']($table_name, $column_info['name'], $column_info);
else
return false;
}
// Get the specifics...
$column_info['size'] = isset($column_info['size']) && is_numeric($column_info['size']) ? $column_info['size'] : null;
list ($type, $size) = $smcFunc['db_calculate_type']($column_info['type'], $column_info['size']);
if ($size !== null)
$type = $type . '(' . $size . ')';
// Now add the thing!
$query = '
ALTER TABLE ' . $table_name . '
ADD COLUMN ' . $column_info['name'] . ' ' . $type;
$smcFunc['db_query']('', $query,
array(
'security_override' => true,
)
);
// If there's more attributes they need to be done via a change on PostgreSQL.
unset($column_info['type'], $column_info['size']);
if (count($column_info) != 1)
return $smcFunc['db_change_column']($table_name, $column_info['name'], $column_info);
else
return true;
}
// Remove a column.
function smf_db_remove_column($table_name, $column_name, $parameters = array(), $error = 'fatal')
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// Does it exist?
$columns = $smcFunc['db_list_columns']($table_name, true);
foreach ($columns as $column)
if ($column['name'] == $column_name)
{
// If there is an auto we need remove it!
if ($column['auto'])
$smcFunc['db_query']('',
'DROP SEQUENCE ' . $table_name . '_seq',
array(
'security_override' => true,
)
);
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
DROP COLUMN ' . $column_name,
array(
'security_override' => true,
)
);
return true;
}
// If here we didn't have to work - joy!
return false;
}
// Change a column.
function smf_db_change_column($table_name, $old_column, $column_info, $parameters = array(), $error = 'fatal')
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// Check it does exist!
$columns = $smcFunc['db_list_columns']($table_name, true);
$old_info = null;
foreach ($columns as $column)
if ($column['name'] == $old_column)
$old_info = $column;
// Nothing?
if ($old_info == null)
return false;
// Now we check each bit individually and ALTER as required.
if (isset($column_info['name']) && $column_info['name'] != $old_column)
{
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
RENAME COLUMN ' . $old_column . ' TO ' . $column_info['name'],
array(
'security_override' => true,
)
);
}
// Different default?
if (isset($column_info['default']) && $column_info['default'] != $old_info['default'])
{
$action = $column_info['default'] !== null ? 'SET DEFAULT \'' . $smcFunc['db_escape_string']($column_info['default']) . '\'' : 'DROP DEFAULT';
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
ALTER COLUMN ' . $column_info['name'] . ' ' . $action,
array(
'security_override' => true,
)
);
}
// Is it null - or otherwise?
if (isset($column_info['null']) && $column_info['null'] != $old_info['null'])
{
$action = $column_info['null'] ? 'DROP' : 'SET';
$smcFunc['db_transaction']('begin');
if (!$column_info['null'])
{
// We have to set it to something if we are making it NOT NULL.
$setTo = isset($column_info['default']) ? $column_info['default'] : '';
$smcFunc['db_query']('', '
UPDATE ' . $table_name . '
SET ' . $column_info['name'] . ' = \'' . $setTo . '\'
WHERE ' . $column_info['name'] . ' = NULL',
array(
'security_override' => true,
)
);
}
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
ALTER COLUMN ' . $column_info['name'] . ' ' . $action . ' NOT NULL',
array(
'security_override' => true,
)
);
$smcFunc['db_transaction']('commit');
}
// What about a change in type?
if (isset($column_info['type']) && ($column_info['type'] != $old_info['type'] || (isset($column_info['size']) && $column_info['size'] != $old_info['size'])))
{
$column_info['size'] = isset($column_info['size']) && is_numeric($column_info['size']) ? $column_info['size'] : null;
list ($type, $size) = $smcFunc['db_calculate_type']($column_info['type'], $column_info['size']);
if ($size !== null)
$type = $type . '(' . $size . ')';
// The alter is a pain.
$smcFunc['db_transaction']('begin');
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
ADD COLUMN ' . $column_info['name'] . '_tempxx ' . $type,
array(
'security_override' => true,
)
);
$smcFunc['db_query']('', '
UPDATE ' . $table_name . '
SET ' . $column_info['name'] . '_tempxx = CAST(' . $column_info['name'] . ' AS ' . $type . ')',
array(
'security_override' => true,
)
);
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
DROP COLUMN ' . $column_info['name'],
array(
'security_override' => true,
)
);
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
RENAME COLUMN ' . $column_info['name'] . '_tempxx TO ' . $column_info['name'],
array(
'security_override' => true,
)
);
$smcFunc['db_transaction']('commit');
}
// Finally - auto increment?!
if (isset($column_info['auto']) && $column_info['auto'] != $old_info['auto'])
{
// Are we removing an old one?
if ($old_info['auto'])
{
// Alter the table first - then drop the sequence.
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
ALTER COLUMN ' . $column_info['name'] . ' SET DEFAULT \'0\'',
array(
'security_override' => true,
)
);
$smcFunc['db_query']('', '
DROP SEQUENCE ' . $table_name . '_seq',
array(
'security_override' => true,
)
);
}
// Otherwise add it!
else
{
$smcFunc['db_query']('', '
CREATE SEQUENCE ' . $table_name . '_seq',
array(
'security_override' => true,
)
);
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
ALTER COLUMN ' . $column_info['name'] . ' SET DEFAULT nextval(\'' . $table_name . '_seq\')',
array(
'security_override' => true,
)
);
}
}
}
// Add an index.
function smf_db_add_index($table_name, $index_info, $parameters = array(), $if_exists = 'update', $error = 'fatal')
{
global $smcFunc, $db_package_log, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// No columns = no index.
if (empty($index_info['columns']))
return false;
$columns = implode(',', $index_info['columns']);
// No name - make it up!
if (empty($index_info['name']))
{
// No need for primary.
if (isset($index_info['type']) && $index_info['type'] == 'primary')
$index_info['name'] = '';
else
$index_info['name'] = $table_name . implode('_', $index_info['columns']);
}
else
$index_info['name'] = $table_name . $index_info['name'];
// Log that we are going to want to remove this!
$db_package_log[] = array('remove_index', $table_name, $index_info['name']);
// Let's get all our indexes.
$indexes = $smcFunc['db_list_indexes']($table_name, true);
// Do we already have it?
foreach ($indexes as $index)
{
if ($index['name'] == $index_info['name'] || ($index['type'] == 'primary' && isset($index_info['type']) && $index_info['type'] == 'primary'))
{
// If we want to overwrite simply remove the current one then continue.
if ($if_exists != 'update' || $index['type'] == 'primary')
return false;
else
$smcFunc['db_remove_index']($table_name, $index_info['name']);
}
}
// If we're here we know we don't have the index - so just add it.
if (!empty($index_info['type']) && $index_info['type'] == 'primary')
{
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
ADD PRIMARY KEY (' . $columns . ')',
array(
'security_override' => true,
)
);
}
else
{
$smcFunc['db_query']('', '
CREATE ' . (isset($index_info['type']) && $index_info['type'] == 'unique' ? 'UNIQUE' : '') . ' INDEX ' . $index_info['name'] . ' ON ' . $table_name . ' (' . $columns . ')',
array(
'security_override' => true,
)
);
}
}
// Remove an index.
function smf_db_remove_index($table_name, $index_name, $parameters = array(), $error = 'fatal')
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// Better exist!
$indexes = $smcFunc['db_list_indexes']($table_name, true);
if ($index_name != 'primary')
$index_name = $table_name . '_' . $index_name;
foreach ($indexes as $index)
{
// If the name is primary we want the primary key!
if ($index['type'] == 'primary' && $index_name == 'primary')
{
// Dropping primary key is odd...
$smcFunc['db_query']('', '
ALTER TABLE ' . $table_name . '
DROP CONSTRAINT ' . $index['name'],
array(
'security_override' => true,
)
);
return true;
}
if ($index['name'] == $index_name)
{
// Drop the bugger...
$smcFunc['db_query']('', '
DROP INDEX ' . $index_name,
array(
'security_override' => true,
)
);
return true;
}
}
// Not to be found ;(
return false;
}
// Get the schema formatted name for a type.
function smf_db_calculate_type($type_name, $type_size = null, $reverse = false)
{
// Generic => Specific.
if (!$reverse)
{
$types = array(
'varchar' => 'character varying',
'char' => 'character',
'mediumint' => 'int',
'tinyint' => 'smallint',
'tinytext' => 'character varying',
'mediumtext' => 'text',
'largetext' => 'text',
);
}
else
{
$types = array(
'character varying' => 'varchar',
'character' => 'char',
'integer' => 'int',
);
}
// Got it? Change it!
if (isset($types[$type_name]))
{
if ($type_name == 'tinytext')
$type_size = 255;
$type_name = $types[$type_name];
}
// Numbers don't have a size.
if (strpos($type_name, 'int') !== false)
$type_size = null;
return array($type_name, $type_size);
}
// Get table structure.
function smf_db_table_structure($table_name, $parameters = array())
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
return array(
'name' => $table_name,
'columns' => $smcFunc['db_list_columns']($table_name, true),
'indexes' => $smcFunc['db_list_indexes']($table_name, true),
);
}
// Return column information for a table.
function smf_db_list_columns($table_name, $detail = false, $parameters = array())
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
$result = $smcFunc['db_query']('', '
SELECT column_name, column_default, is_nullable, data_type, character_maximum_length
FROM information_schema.columns
WHERE table_name = \'' . $table_name . '\'
ORDER BY ordinal_position',
array(
'security_override' => true,
)
);
$columns = array();
while ($row = $smcFunc['db_fetch_assoc']($result))
{
if (!$detail)
{
$columns[] = $row['column_name'];
}
else
{
$auto = false;
// What is the default?
if (preg_match('~nextval\(\'(.+?)\'(.+?)*\)~i', $row['column_default'], $matches) != 0)
{
$default = null;
$auto = true;
}
elseif (trim($row['column_default']) != '')
$default = strpos($row['column_default'], '::') === false ? $row['column_default'] : substr($row['column_default'], 0, strpos($row['column_default'], '::'));
else
$default = null;
// Make the type generic.
list ($type, $size) = $smcFunc['db_calculate_type']($row['data_type'], $row['character_maximum_length'], true);
$columns[$row['column_name']] = array(
'name' => $row['column_name'],
'null' => $row['is_nullable'] ? true : false,
'default' => $default,
'type' => $type,
'size' => $size,
'auto' => $auto,
);
}
}
$smcFunc['db_free_result']($result);
return $columns;
}
// What about some index information?
function smf_db_list_indexes($table_name, $detail = false, $parameters = array())
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
$result = $smcFunc['db_query']('', '
SELECT CASE WHEN i.indisprimary THEN 1 ELSE 0 END AS is_primary,
CASE WHEN i.indisunique THEN 1 ELSE 0 END AS is_unique,
c2.relname AS name,
pg_get_indexdef(i.indexrelid) AS inddef
FROM pg_class AS c, pg_class AS c2, pg_index AS i
WHERE c.relname = \'' . $table_name . '\'
AND c.oid = i.indrelid
AND i.indexrelid = c2.oid',
array(
'security_override' => true,
)
);
$indexes = array();
while ($row = $smcFunc['db_fetch_assoc']($result))
{
// Try get the columns that make it up.
if (preg_match('~\(([^\)]+?)\)~i', $row['inddef'], $matches) == 0)
continue;
$columns = explode(',', $matches[1]);
if (empty($columns))
continue;
foreach ($columns as $k => $v)
$columns[$k] = trim($v);
// Fix up the name to be consistent cross databases
if (substr($row['name'], -5) == '_pkey' && $row['is_primary'] == 1)
$row['name'] = 'PRIMARY';
else
$row['name'] = str_replace($table_name . '_', '', $row['name']);
if (!$detail)
$indexes[] = $row['name'];
else
{
$indexes[$row['name']] = array(
'name' => $row['name'],
'type' => $row['is_primary'] ? 'primary' : ($row['is_unique'] ? 'unique' : 'index'),
'columns' => $columns,
);
}
}
$smcFunc['db_free_result']($result);
return $indexes;
}
?>

View File

@ -0,0 +1,736 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file contains database functionality specifically designed for packages to utilize.
bool smf_db_create_table(string table_name, array columns, array indexes = array(),
array parameters = array(), string if_exists = 'ignore')
- Can be used to create a table without worrying about schema compatabilities.
- If the table exists will, by default, do nothing.
- Builds table with columns as passed to it - at least one column must be sent.
The columns array should have one sub-array for each column - these sub arrays contain:
+ 'name' = Column name
+ 'type' = Type of column - values from (smallint,mediumint,int,text,varchar,char,tinytext,mediumtext,largetext)
+ 'size' => Size of column (If applicable) - for example 255 for a large varchar, 10 for an int etc. If not
set SMF will pick a size.
+ 'default' = Default value - do not set if no default required.
+ 'null' => Can it be null (true or false) - if not set default will be false.
+ 'auto' => Set to true to make it an auto incrementing column. Set to a numerical value to set
from what it should begin counting.
- Adds indexes as specified within indexes parameter. Each index should be a member of $indexes. Values are:
+ 'name' => Index name (If left empty SMF will generate).
+ 'type' => Type of index. Choose from 'primary', 'unique' or 'index'. If not set will default to 'index'.
+ 'columns' => Array containing columns that form part of key - in the order the index is to be created.
- parameters: (None yet)
- if_exists values:
+ 'ignore' will do nothing if the table exists. (And will return true)
+ 'overwrite' will drop any existing table of the same name.
+ 'error' will return false if the table already exists.
*/
// Add the file functions to the $smcFunc array.
function db_packages_init()
{
global $smcFunc, $reservedTables, $db_package_log, $db_prefix;
if (!isset($smcFunc['db_create_table']) || $smcFunc['db_create_table'] != 'smf_db_create_table')
{
$smcFunc += array(
'db_add_column' => 'smf_db_add_column',
'db_add_index' => 'smf_db_add_index',
'db_alter_table' => 'smf_db_alter_table',
'db_calculate_type' => 'smf_db_calculate_type',
'db_change_column' => 'smf_db_change_column',
'db_create_table' => 'smf_db_create_table',
'db_drop_table' => 'smf_db_drop_table',
'db_table_structure' => 'smf_db_table_structure',
'db_list_columns' => 'smf_db_list_columns',
'db_list_indexes' => 'smf_db_list_indexes',
'db_remove_column' => 'smf_db_remove_column',
'db_remove_index' => 'smf_db_remove_index',
);
$db_package_log = array();
}
// We setup an array of SMF tables we can't do auto-remove on - in case a mod writer cocks it up!
$reservedTables = array('admin_info_files', 'approval_queue', 'attachments', 'ban_groups', 'ban_items',
'board_permissions', 'boards', 'calendar', 'calendar_holidays', 'categories', 'collapsed_categories',
'custom_fields', 'group_moderators', 'log_actions', 'log_activity', 'log_banned', 'log_boards',
'log_digest', 'log_errors', 'log_floodcontrol', 'log_group_requests', 'log_karma', 'log_mark_read',
'log_notify', 'log_online', 'log_packages', 'log_polls', 'log_reported', 'log_reported_comments',
'log_scheduled_tasks', 'log_search_messages', 'log_search_results', 'log_search_subjects',
'log_search_topics', 'log_topics', 'mail_queue', 'membergroups', 'members', 'message_icons',
'messages', 'moderators', 'package_servers', 'permission_profiles', 'permissions', 'personal_messages',
'pm_recipients', 'poll_choices', 'polls', 'scheduled_tasks', 'sessions', 'settings', 'smileys',
'themes', 'topics');
foreach ($reservedTables as $k => $table_name)
$reservedTables[$k] = strtolower($db_prefix . $table_name);
// We in turn may need the extra stuff.
db_extend('extra');
}
// Create a table.
function smf_db_create_table($table_name, $columns, $indexes = array(), $parameters = array(), $if_exists = 'ignore', $error = 'fatal')
{
global $reservedTables, $smcFunc, $db_package_log, $db_prefix;
// With or without the database name, the full name looks like this.
$real_prefix = preg_match('~^(`?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix;
$full_table_name = str_replace('{db_prefix}', $real_prefix, $table_name);
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// First - no way do we touch SMF tables.
// Commented out for now. We need to alter SMF tables in order to use this in the upgrade.
/*
if (in_array(strtolower($table_name), $reservedTables))
return false;
*/
// Log that we'll want to remove this on uninstall.
$db_package_log[] = array('remove_table', $table_name);
// Does this table exist or not?
$tables = $smcFunc['db_list_tables']();
if (in_array($full_table_name, $tables))
{
// This is a sad day... drop the table? If not, return false (error) by default.
if ($if_exists == 'overwrite')
$smcFunc['db_drop_table']($table_name);
else
return $if_exists == 'ignore';
}
// Righty - let's do the damn thing!
$table_query = 'CREATE TABLE ' . $table_name . "\n" . '(';
$done_primary = false;
foreach ($columns as $column)
{
// Auto increment is special
if (!empty($column['auto']))
{
$table_query .= "\n" . $column['name'] . ' integer PRIMARY KEY,';
$done_primary = true;
continue;
}
elseif (isset($column['default']) && $column['default'] !== null)
$default = 'default \'' . $smcFunc['db_escape_string']($column['default']) . '\'';
else
$default = '';
// Sort out the size... and stuff...
$column['size'] = isset($column['size']) && is_numeric($column['size']) ? $column['size'] : null;
list ($type, $size) = $smcFunc['db_calculate_type']($column['type'], $column['size']);
if ($size !== null)
$type = $type . '(' . $size . ')';
// Now just put it together!
$table_query .= "\n\t" . $column['name'] . ' ' . $type . ' ' . (!empty($column['null']) ? '' : 'NOT NULL') . ' ' . $default . ',';
}
// Loop through the indexes next...
$index_queries = array();
foreach ($indexes as $index)
{
$columns = implode(',', $index['columns']);
// Is it the primary?
if (isset($index['type']) && $index['type'] == 'primary')
{
// If we've done the primary via auto_inc, don't do it again!
if (!$done_primary)
$table_query .= "\n\t" . 'PRIMARY KEY (' . implode(',', $index['columns']) . '),';
}
else
{
if (empty($index['name']))
$index['name'] = implode('_', $index['columns']);
$index_queries[] = 'CREATE ' . (isset($index['type']) && $index['type'] == 'unique' ? 'UNIQUE' : '') . ' INDEX ' . $table_name . '_' . $index['name'] . ' ON ' . $table_name . ' (' . $columns . ')';
}
}
// No trailing commas!
if (substr($table_query, -1) == ',')
$table_query = substr($table_query, 0, -1);
$table_query .= ')';
if (empty($parameters['skip_transaction']))
$smcFunc['db_transaction']('begin');
// Do the table and indexes...
$smcFunc['db_query']('', $table_query,
array(
'security_override' => true,
)
);
foreach ($index_queries as $query)
$smcFunc['db_query']('', $query,
array(
'security_override' => true,
)
);
if (empty($parameters['skip_transaction']))
$smcFunc['db_transaction']('commit');
}
// Drop a table.
function smf_db_drop_table($table_name, $parameters = array(), $error = 'fatal')
{
global $reservedTables, $smcFunc, $db_prefix;
// Strip out the table name, we might not need it in some cases
$real_prefix = preg_match('~^(`?)(.+?)\\1\\.(.*?)$~', $db_prefix, $match) === 1 ? $match[3] : $db_prefix;
$full_table_name = str_replace('{db_prefix}', $real_prefix, $table_name);
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// God no - dropping one of these = bad.
if (in_array(strtolower($table_name), $reservedTables))
return false;
// Does it exist?
if (in_array($full_table_name, $smcFunc['db_list_tables']()))
{
$query = 'DROP TABLE ' . $table_name;
$smcFunc['db_query']('', $query,
array(
'security_override' => true,
)
);
return true;
}
// Otherwise do 'nout.
return false;
}
// Add a column.
function smf_db_add_column($table_name, $column_info, $parameters = array(), $if_exists = 'update', $error = 'fatal')
{
global $smcFunc, $db_package_log, $txt, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// Log that we will want to uninstall this!
$db_package_log[] = array('remove_column', $table_name, $column_info['name']);
// Does it exist - if so don't add it again!
$columns = $smcFunc['db_list_columns']($table_name, false);
foreach ($columns as $column)
if ($column == $column_info['name'])
{
// If we're going to overwrite then use change column.
if ($if_exists == 'update')
return $smcFunc['db_change_column']($table_name, $column_info['name'], $column_info);
else
return false;
}
// Alter the table to add the column.
if ($smcFunc['db_alter_table']($table_name, array('add' => array($column_info))) === false)
return false;
return true;
}
// We can't reliably do this on SQLite - damn!
function smf_db_remove_column($table_name, $column_name, $parameters = array(), $error = 'fatal')
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
if ($smcFunc['db_alter_table']($table_name, array('remove' => array(array('name' => $column_name)))))
return true;
else
return false;
}
// Change a column.
function smf_db_change_column($table_name, $old_column, $column_info, $parameters = array(), $error = 'fatal')
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
if ($smcFunc['db_alter_table']($table_name, array('change' => array(array('name' => $old_column) + $column_info))))
return true;
else
return false;
}
// Add an index.
function smf_db_add_index($table_name, $index_info, $parameters = array(), $if_exists = 'update', $error = 'fatal')
{
global $smcFunc, $db_package_log, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// No columns = no index.
if (empty($index_info['columns']))
return false;
$columns = implode(',', $index_info['columns']);
// No name - make it up!
if (empty($index_info['name']))
{
// No need for primary.
if (isset($index_info['type']) && $index_info['type'] == 'primary')
$index_info['name'] = '';
else
$index_info['name'] = implode('_', $index_info['columns']);
}
else
$index_info['name'] = $index_info['name'];
// Log that we are going to want to remove this!
$db_package_log[] = array('remove_index', $table_name, $index_info['name']);
// Let's get all our indexes.
$indexes = $smcFunc['db_list_indexes']($table_name, true);
// Do we already have it?
foreach ($indexes as $index)
{
if ($index['name'] == $index_info['name'] || ($index['type'] == 'primary' && isset($index_info['type']) && $index_info['type'] == 'primary'))
{
// If we want to overwrite simply remove the current one then continue.
if ($if_exists != 'update' || $index['type'] == 'primary')
return false;
else
$smcFunc['db_remove_index']($table_name, $index_info['name']);
}
}
// If we're here we know we don't have the index - so just add it.
if (!empty($index_info['type']) && $index_info['type'] == 'primary')
{
//!!! Doesn't work with PRIMARY KEY yet.
}
else
{
$smcFunc['db_query']('', '
CREATE ' . (isset($index_info['type']) && $index_info['type'] == 'unique' ? 'UNIQUE' : '') . ' INDEX ' . $index_info['name'] . ' ON ' . $table_name . ' (' . $columns . ')',
array(
'security_override' => true,
)
);
}
}
// Remove an index.
function smf_db_remove_index($table_name, $index_name, $parameters = array(), $error = 'fatal')
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// Better exist!
$indexes = $smcFunc['db_list_indexes']($table_name, true);
foreach ($indexes as $index)
{
//!!! Doesn't do primary key at the moment!
if ($index['type'] != 'primary' && $index['name'] == $index_name)
{
// Drop the bugger...
$smcFunc['db_query']('', '
DROP INDEX ' . $index_name,
array(
'security_override' => true,
)
);
return true;
}
}
// Not to be found ;(
return false;
}
// Get the schema formatted name for a type.
function smf_db_calculate_type($type_name, $type_size = null, $reverse = false)
{
// Generic => Specific.
if (!$reverse)
{
$types = array(
'mediumint' => 'int',
'tinyint' => 'smallint',
'mediumtext' => 'text',
'largetext' => 'text',
);
}
else
{
$types = array(
'integer' => 'int',
);
}
// Got it? Change it!
if (isset($types[$type_name]))
{
if ($type_name == 'tinytext')
$type_size = 255;
$type_name = $types[$type_name];
}
// Numbers don't have a size.
if (strpos($type_name, 'int') !== false)
$type_size = null;
return array($type_name, $type_size);
}
// Get table structure.
function smf_db_table_structure($table_name, $parameters = array())
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
return array(
'name' => $table_name,
'columns' => $smcFunc['db_list_columns']($table_name, true),
'indexes' => $smcFunc['db_list_indexes']($table_name, true),
);
}
// Harder than it should be on sqlite!
function smf_db_list_columns($table_name, $detail = false, $parameters = array())
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
$result = $smcFunc['db_query']('', '
PRAGMA table_info(' . $table_name . ')',
array(
'security_override' => true,
)
);
$columns = array();
$primaries = array();
while ($row = $smcFunc['db_fetch_assoc']($result))
{
if (!$detail)
{
$columns[] = $row['name'];
}
else
{
// Auto increment is hard to tell really... if there's only one primary it probably is.
if ($row['pk'])
$primaries[] = $row['name'];
// Can we split out the size?
if (preg_match('~(.+?)\s*\((\d+)\)~i', $row['type'], $matches))
{
$type = $matches[1];
$size = $matches[2];
}
else
{
$type = $row['type'];
$size = null;
}
$columns[$row['name']] = array(
'name' => $row['name'],
'null' => $row['notnull'] ? false : true,
'default' => $row['dflt_value'],
'type' => $type,
'size' => $size,
'auto' => false,
);
}
}
$smcFunc['db_free_result']($result);
// Put in our guess at auto_inc.
if (count($primaries) == 1)
$columns[$primaries[0]]['auto'] = true;
return $columns;
}
// What about some index information?
function smf_db_list_indexes($table_name, $detail = false, $parameters = array())
{
global $smcFunc, $db_prefix;
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
$result = $smcFunc['db_query']('', '
PRAGMA index_list(' . $table_name . ')',
array(
'security_override' => true,
)
);
$indexes = array();
while ($row = $smcFunc['db_fetch_assoc']($result))
{
if (!$detail)
$indexes[] = $row['name'];
else
{
$result2 = $smcFunc['db_query']('', '
PRAGMA index_info(' . $row['name'] . ')',
array(
'security_override' => true,
)
);
while ($row2 = $smcFunc['db_fetch_assoc']($result2))
{
// What is the type?
if ($row['unique'])
$type = 'unique';
else
$type = 'index';
// This is the first column we've seen?
if (empty($indexes[$row['name']]))
{
$indexes[$row['name']] = array(
'name' => $row['name'],
'type' => $type,
'columns' => array(),
);
}
// Add the column...
$indexes[$row['name']]['columns'][] = $row2['name'];
}
$smcFunc['db_free_result']($result2);
}
}
$smcFunc['db_free_result']($result);
return $indexes;
}
function smf_db_alter_table($table_name, $columns)
{
global $smcFunc, $db_prefix, $db_name, $boarddir;
$db_file = substr($db_name, -3) === '.db' ? $db_name : $db_name . '.db';
$table_name = str_replace('{db_prefix}', $db_prefix, $table_name);
// Let's get the current columns for the table.
$current_columns = $smcFunc['db_list_columns']($table_name, true);
// Let's get a list of columns for the temp table.
$temp_table_columns = array();
// Let's see if we have columns to remove or columns that are being added that already exist.
foreach ($current_columns as $key => $column)
{
$exists = false;
if (isset($columns['remove']))
foreach ($columns['remove'] as $drop)
if ($drop['name'] == $column['name'])
{
$exists = true;
break;
}
if (isset($columns['add']))
foreach ($columns['add'] as $key2 => $add)
if ($add['name'] == $column['name'])
{
unset($columns['add'][$key2]);
break;
}
// Doesn't exist then we 'remove'.
if (!$exists)
$temp_table_columns[] = $column['name'];
}
// If they are equal then that means that the column that we are adding exists or it doesn't exist and we are not looking to change any one of them.
if (count($temp_table_columns) == count($current_columns) && empty($columns['change']) && empty($columns['add']))
return true;
// Drop the temp table.
$smcFunc['db_query']('', '
DROP TABLE {raw:temp_table_name}',
array(
'temp_table_name' => $table_name . '_tmp',
'db_error_skip' => true,
)
);
// Let's make a backup of the current database.
// We only want the first backup of a table modification. So if there is a backup file and older than an hour just delete and back up again
$db_backup_file = $boarddir . '/Packages/backups/backup_' . $table_name . '_' . basename($db_file) . md5($table_name . $db_file);
if (file_exists($db_backup_file) && time() - filemtime($db_backup_file) > 3600)
{
@unlink($db_backup_file);
@copy($db_file, $db_backup_file);
}
elseif (!file_exists($db_backup_file))
@copy($db_file, $db_backup_file);
// If we don't have temp tables then everything crapped out. Just exit.
if (empty($temp_table_columns))
return false;
// Start
$smcFunc['db_transaction']('begin');
// Let's create the temporary table.
$createTempTable = $smcFunc['db_query']('', '
CREATE TEMPORARY TABLE {raw:temp_table_name}
(
{raw:columns}
);',
array(
'temp_table_name' => $table_name . '_tmp',
'columns' => implode(', ', $temp_table_columns),
'db_error_skip' => true,
)
) !== false;
if (!$createTempTable)
return false;
// Insert into temp table.
$smcFunc['db_query']('', '
INSERT INTO {raw:temp_table_name}
({raw:columns})
SELECT {raw:columns}
FROM {raw:table_name}',
array(
'table_name' => $table_name,
'columns' => implode(', ', $temp_table_columns),
'temp_table_name' => $table_name . '_tmp',
)
);
// Drop the current table.
$dropTable = $smcFunc['db_query']('', '
DROP TABLE {raw:table_name}',
array(
'table_name' => $table_name,
'db_error_skip' => true,
)
) !== false;
// If you can't drop the main table then there is no where to go from here. Just return.
if (!$dropTable)
return false;
// We need to keep track of the structure for the current columns and the new columns.
$new_columns = array();
$column_names = array();
// Let's get the ones that we already have first.
foreach ($current_columns as $name => $column)
{
if (in_array($name, $temp_table_columns))
{
$new_columns[$name] = array(
'name' => $name,
'type' => $column['type'],
'size' => isset($column['size']) ? (int) $column['size'] : null,
'null' => !empty($column['null']),
'auto' => isset($column['auto']) ? $column['auto'] : false,
'default' => isset($column['default']) ? $column['default'] : '',
);
// Lets keep track of the name for the column.
$column_names[$name] = $name;
}
}
// Now the new.
if (!empty($columns['add']))
foreach ($columns['add'] as $add)
{
$new_columns[$add['name']] = array(
'name' => $add['name'],
'type' => $add['type'],
'size' => isset($add['size']) ? (int) $add['size'] : null,
'null' => !empty($add['null']),
'auto' => isset($add['auto']) ? $add['auto'] : false,
'default' => isset($add['default']) ? $add['default'] : '',
);
// Let's keep track of the name for the column.
$column_names[$add['name']] = strstr('int', $add['type']) ? ' 0 AS ' . $add['name'] : ' {string:empty_string} AS ' . $add['name'];
}
// Now to change a column. Not drop but change it.
if (isset($columns['change']))
foreach ($columns['change'] as $change)
if (isset($new_columns[$change['name']]))
$new_columns[$change['name']] = array(
'name' => $change['name'],
'type' => $change['type'],
'size' => isset($change['size']) ? (int) $change['size'] : null,
'null' => !empty($change['null']),
'auto' => isset($change['auto']) ? $change['auto'] : false,
'default' => isset($change['default']) ? $change['default'] : '',
);
// Now let's create the table.
$createTable = $smcFunc['db_create_table']($table_name, $new_columns, array(), array('skip_transaction' => true));
// Did it create correctly?
if ($createTable === false)
return false;
// Back to it's original table.
$insertData = $smcFunc['db_query']('', '
INSERT INTO {raw:table_name}
({raw:columns})
SELECT ' . implode(', ', $column_names) . '
FROM {raw:temp_table_name}',
array(
'table_name' => $table_name,
'columns' => implode(', ', array_keys($new_columns)),
'columns_select' => implode(', ', $column_names),
'temp_table_name' => $table_name . '_tmp',
'empty_string' => '',
)
);
// Did everything insert correctly?
if (!$insertData)
return false;
// Drop the temp table.
$smcFunc['db_query']('', '
DROP TABLE {raw:temp_table_name}',
array(
'temp_table_name' => $table_name . '_tmp',
'db_error_skip' => true,
)
);
// Commit or else there is no point in doing the previous steps.
$smcFunc['db_transaction']('commit');
// We got here so we're good. The temp table should be deleted, if not it will be gone later on >:D.
return true;
}
?>

View File

@ -0,0 +1,77 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file contains database functions specific to search related activity.
void db_search_init()
- adds the functions in this file to the $smcFunc array
boolean smf_db_search_support($search_type)
- whether this database type support the search type $search_type
void smf_db_create_word_search($size)
- create the custom word index table
*/
// Add the file functions to the $smcFunc array.
function db_search_init()
{
global $smcFunc;
if (!isset($smcFunc['db_search_query']) || $smcFunc['db_search_query'] != 'smf_db_query')
$smcFunc += array(
'db_search_query' => 'smf_db_query',
'db_search_support' => 'smf_db_search_support',
'db_create_word_search' => 'smf_db_create_word_search',
'db_support_ignore' => true,
);
}
// Does this database type support this search type?
function smf_db_search_support($search_type)
{
$supported_types = array('fulltext');
return in_array($search_type, $supported_types);
}
// Highly specific - create the custom word index table!
function smf_db_create_word_search($size)
{
global $smcFunc;
if ($size == 'small')
$size = 'smallint(5)';
elseif ($size == 'medium')
$size = 'mediumint(8)';
else
$size = 'int(10)';
$smcFunc['db_query']('', '
CREATE TABLE {db_prefix}log_search_words (
id_word {raw:size} unsigned NOT NULL default {string:string_zero},
id_msg int(10) unsigned NOT NULL default {string:string_zero},
PRIMARY KEY (id_word, id_msg)
) ENGINE=InnoDB',
array(
'string_zero' => '0',
'size' => $size,
)
);
}
?>

View File

@ -0,0 +1,122 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0.7
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file contains database functions specific to search related activity.
void db_search_init()
- adds the functions in this file to the $smcFunc array
boolean smf_db_search_support($search_type)
- whether this database type support the search type $search_type
void smf_db_create_word_search($size)
- create the custom word index table
resource smf_db_search_query($identifier, $db_string, $db_values = array(), $connection = null)
- returns the correct query for this search type.
*/
// Add the file functions to the $smcFunc array.
function db_search_init()
{
global $smcFunc;
if (!isset($smcFunc['db_search_query']) || $smcFunc['db_search_query'] != 'smf_db_search_query')
$smcFunc += array(
'db_search_query' => 'smf_db_search_query',
'db_search_support' => 'smf_db_search_support',
'db_create_word_search' => 'smf_db_create_word_search',
'db_support_ignore' => false,
);
}
// Does this database type support this search type?
function smf_db_search_support($search_type)
{
$supported_types = array('custom');
return in_array($search_type, $supported_types);
}
// Returns the correct query for this search type.
function smf_db_search_query($identifier, $db_string, $db_values = array(), $connection = null)
{
global $smcFunc;
$replacements = array(
'create_tmp_log_search_topics' => array(
'~mediumint\(\d\)~i' => 'int',
'~unsigned~i' => '',
'~ENGINE=MEMORY~i' => '',
),
'create_tmp_log_search_messages' => array(
'~mediumint\(\d\)' => 'int',
'~unsigned~i' => '',
'~TYPE=HEAP~i' => '',
),
'drop_tmp_log_search_topics' => array(
'~IF\sEXISTS~i' => '',
),
'drop_tmp_log_search_messages' => array(
'~IF\sEXISTS~i' => '',
),
'insert_into_log_messages_fulltext' => array(
'~NOT\sRLIKE~i' => '!~*',
'~RLIKE~i' => '~*',
),
'insert_log_search_results_subject' => array(
'~NOT\sRLIKE~i' => '!~*',
'~RLIKE~i' => '~*',
),
);
if (isset($replacements[$identifier]))
$db_string = preg_replace(array_keys($replacements[$identifier]), array_values($replacements[$identifier]), $db_string);
elseif (preg_match('~^\s*INSERT\sIGNORE~i', $db_string) != 0)
{
$db_string = preg_replace('~^\s*INSERT\sIGNORE~i', 'INSERT', $db_string);
// Don't error on multi-insert.
$db_values['db_error_skip'] = true;
}
$return = $smcFunc['db_query']('', $db_string,
$db_values, $connection
);
return $return;
}
// Highly specific - create the custom word index table!
function smf_db_create_word_search($size)
{
global $smcFunc;
$size = 'int';
$smcFunc['db_query']('', '
CREATE TABLE {db_prefix}log_search_words (
id_word {raw:size} NOT NULL default {string:string_zero},
id_msg int NOT NULL default {string:string_zero},
PRIMARY KEY (id_word, id_msg)
)',
array(
'size' => $size,
'string_zero' => '0',
)
);
}
?>

106
Sources/DbSearch-sqlite.php Normal file
View File

@ -0,0 +1,106 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0.7
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file contains database functions specific to search related activity.
void db_search_init()
- adds the functions in this file to the $smcFunc array
boolean smf_db_search_support($search_type)
- whether this database type support the search type $search_type
void smf_db_create_word_search($size)
- create the custom word index table
resource smf_db_search_query($identifier, $db_string, $db_values = array(), $connection = null)
- returns the correct query for this search type.
*/
// Add the file functions to the $smcFunc array.
function db_search_init()
{
global $smcFunc;
if (!isset($smcFunc['db_search_query']) || $smcFunc['db_search_query'] != 'smf_db_search_query')
$smcFunc += array(
'db_search_query' => 'smf_db_search_query',
'db_search_support' => 'smf_db_search_support',
'db_create_word_search' => 'smf_db_create_word_search',
'db_support_ignore' => false,
);
}
// Does this database type support this search type?
function smf_db_search_support($search_type)
{
$supported_types = array('custom');
return in_array($search_type, $supported_types);
}
// Returns the correct query for this search type.
function smf_db_search_query($identifier, $db_string, $db_values = array(), $connection = null)
{
global $smcFunc;
$replacements = array(
'create_tmp_log_search_topics' => array(
'~mediumint\(\d\)~i' => 'int',
'~ENGINE=MEMORY~i' => '',
),
'create_tmp_log_search_messages' => array(
'~mediumint\(\d\)~i' => 'int',
'~TYPE=HEAP~i' => '',
),
);
if (isset($replacements[$identifier]))
$db_string = preg_replace(array_keys($replacements[$identifier]), array_values($replacements[$identifier]), $db_string);
elseif (preg_match('~^\s*INSERT\sIGNORE~i', $db_string) != 0)
{
$db_string = preg_replace('~^\s*INSERT\sIGNORE~i', 'INSERT', $db_string);
// Don't error on multi-insert.
$db_values['db_error_skip'] = true;
}
$return = $smcFunc['db_query']('', $db_string,
$db_values, $connection
);
return $return;
}
// Highly specific - create the custom word index table!
function smf_db_create_word_search($size)
{
global $smcFunc;
$size = 'int';
$smcFunc['db_query']('', '
CREATE TABLE {db_prefix}log_search_words (
id_word {raw:size} NOT NULL default {string:string_zero},
id_msg int(10) NOT NULL default {string:string_zero},
PRIMARY KEY (id_word, id_msg)
)',
array(
'size' => $size,
'string_zero' => '0',
)
);
}
?>

1727
Sources/Display.php Normal file

File diff suppressed because it is too large Load Diff

182
Sources/DumpDatabase.php Normal file
View File

@ -0,0 +1,182 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/*
This file has a single job - database backup.
void DumpDatabase2()
- writes all of the database to standard output.
- uses gzip compression if compress is set in the URL/post data.
- may possibly time out in some cases.
- the data dumped depends on whether "struct" and "data" are passed.
- requires an administrator and the session hash by post.
- is called from ManageMaintenance.php.
*/
// Dumps the database to a file.
function DumpDatabase2()
{
global $db_name, $scripturl, $context, $modSettings, $crlf, $smcFunc, $db_prefix;
// Administrators only!
if (!allowedTo('admin_forum'))
fatal_lang_error('no_dump_database', 'critical');
// You can't dump nothing!
if (!isset($_REQUEST['struct']) && !isset($_REQUEST['data']))
$_REQUEST['data'] = true;
checkSession('post');
// We will need this, badly!
db_extend();
// Attempt to stop from dying...
@set_time_limit(600);
if (@ini_get('memory_limit') < 256)
@ini_set('memory_limit', '256M');
// Start saving the output... (don't do it otherwise for memory reasons.)
if (isset($_REQUEST['compress']) && function_exists('gzencode'))
{
// Make sure we're gzipping output, but then say we're not in the header ^_^.
if (empty($modSettings['enableCompressedOutput']))
@ob_start('ob_gzhandler');
// Try to clean any data already outputted.
elseif (ob_get_length() != 0)
{
ob_end_clean();
@ob_start('ob_gzhandler');
}
// Send faked headers so it will just save the compressed output as a gzip.
header('Content-Type: application/x-gzip');
header('Accept-Ranges: bytes');
header('Content-Encoding: none');
// Gecko browsers... don't like this. (Mozilla, Firefox, etc.)
if (!$context['browser']['is_gecko'])
header('Content-Transfer-Encoding: binary');
// The file extension will include .gz...
$extension = '.sql.gz';
}
else
{
// Get rid of the gzipping alreading being done.
if (!empty($modSettings['enableCompressedOutput']))
@ob_end_clean();
// If we can, clean anything already sent from the output buffer...
elseif (function_exists('ob_clean') && ob_get_length() != 0)
ob_clean();
// Tell the client to save this file, even though it's text.
header('Content-Type: ' . ($context['browser']['is_ie'] || $context['browser']['is_opera'] ? 'application/octetstream' : 'application/octet-stream'));
header('Content-Encoding: none');
// This time the extension should just be .sql.
$extension = '.sql';
}
// This should turn off the session URL parser.
$scripturl = '';
// If this database is flat file and has a handler function pass it to that.
if (!empty($smcFunc['db_get_backup']))
{
$smcFunc['db_get_backup']();
exit;
}
// Send the proper headers to let them download this file.
header('Content-Disposition: filename="' . $db_name . '-' . (empty($_REQUEST['struct']) ? 'data' : (empty($_REQUEST['data']) ? 'structure' : 'complete')) . '_' . strftime('%Y-%m-%d') . $extension . '"');
header('Cache-Control: private');
header('Connection: close');
// This makes things simpler when using it so very very often.
$crlf = "\r\n";
// SQL Dump Header.
echo
'-- ==========================================================', $crlf,
'--', $crlf,
'-- Database dump of tables in `', $db_name, '`', $crlf,
'-- ', timeformat(time(), false), $crlf,
'--', $crlf,
'-- ==========================================================', $crlf,
$crlf;
// Get all tables in the database....
if (preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) != 0)
{
$db = strtr($match[1], array('`' => ''));
$dbp = str_replace('_', '\_', $match[2]);
}
else
{
$db = false;
$dbp = $db_prefix;
}
// Dump each table.
$tables = $smcFunc['db_list_tables'](false, $db_prefix . '%');
foreach ($tables as $tableName)
{
if (function_exists('apache_reset_timeout'))
@apache_reset_timeout();
// Are we dumping the structures?
if (isset($_REQUEST['struct']))
{
echo
$crlf,
'--', $crlf,
'-- Table structure for table `', $tableName, '`', $crlf,
'--', $crlf,
$crlf,
$smcFunc['db_table_sql']($tableName), ';', $crlf;
}
// How about the data?
if (!isset($_REQUEST['data']) || substr($tableName, -10) == 'log_errors')
continue;
// Are there any rows in this table?
$get_rows = $smcFunc['db_insert_sql']($tableName);
// No rows to get - skip it.
if (empty($get_rows))
continue;
echo
$crlf,
'--', $crlf,
'-- Dumping data in `', $tableName, '`', $crlf,
'--', $crlf,
$crlf,
$get_rows,
'-- --------------------------------------------------------', $crlf;
}
echo
$crlf,
'-- Done', $crlf;
exit;
}
?>

420
Sources/Errors.php Normal file
View File

@ -0,0 +1,420 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0.4
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* The purpose of this file is... errors. (hard to guess, huh?) It takes
care of logging, error messages, error handling, database errors, and
error log administration. It does this with:
bool db_fatal_error(bool loadavg = false)
- calls show_db_error().
- this is used for database connection error handling.
- loadavg means this is a load average problem, not a database error.
string log_error(string error_message, string error_type = general,
string filename = none, int line = none)
- logs an error, if error logging is enabled.
- depends on the enableErrorLogging setting.
- filename and line should be __FILE__ and __LINE__, respectively.
- returns the error message. (ie. die(log_error($msg));)
void fatal_error(string error_message, mixed (bool or string) log = general)
- stops execution and displays an error message.
- logs the error message if log is missing or true.
void fatal_lang_error(string error_message_key, mixed (bool or string) log = general,
array sprintf = array())
- stops execution and displays an error message by key.
- uses the string with the error_message_key key.
- loads the Errors language file.
- applies the sprintf information if specified.
- the information is logged if log is true or missing.
- logs the error in the forum's default language while displaying the error
message in the user's language
void error_handler(int error_level, string error_string, string filename,
int line)
- this is a standard PHP error handler replacement.
- dies with fatal_error() if the error_level matches with
error_reporting.
void setup_fatal_error_context(string error_message)
- uses the fatal_error sub template of the Errors template - or the
error sub template in the Wireless template.
- used by fatal_error() and fatal_lang_error()
void show_db_error(bool loadavg = false)
- called by db_fatal_error() function
- shows a complete page independent of language files or themes.
- used only if there's no way to connect to the database or the
load averages are too high to do so.
- loadavg means this is a load average problem, not a database error.
- stops further execution of the script.
*/
// Handle fatal errors - like connection errors or load average problems
function db_fatal_error($loadavg = false)
{
global $sourcedir;
show_db_error($loadavg);
// Since we use "or db_fatal_error();" this is needed...
return false;
}
// Log an error, if the option is on.
function log_error($error_message, $error_type = 'general', $file = null, $line = null)
{
global $txt, $modSettings, $sc, $user_info, $smcFunc, $scripturl, $last_error;
// Check if error logging is actually on.
if (empty($modSettings['enableErrorLogging']))
return $error_message;
// Basically, htmlspecialchars it minus &. (for entities!)
$error_message = strtr($error_message, array('<' => '&lt;', '>' => '&gt;', '"' => '&quot;'));
$error_message = strtr($error_message, array('&lt;br /&gt;' => '<br />', '&lt;b&gt;' => '<strong>', '&lt;/b&gt;' => '</strong>', "\n" => '<br />'));
// Add a file and line to the error message?
// Don't use the actual txt entries for file and line but instead use %1$s for file and %2$s for line
if ($file == null)
$file = '';
else
// Window style slashes don't play well, lets convert them to the unix style.
$file = str_replace('\\', '/', $file);
if ($line == null)
$line = 0;
else
$line = (int) $line;
// Just in case there's no id_member or IP set yet.
if (empty($user_info['id']))
$user_info['id'] = 0;
if (empty($user_info['ip']))
$user_info['ip'] = '';
// Find the best query string we can...
$query_string = empty($_SERVER['QUERY_STRING']) ? (empty($_SERVER['REQUEST_URL']) ? '' : str_replace($scripturl, '', $_SERVER['REQUEST_URL'])) : $_SERVER['QUERY_STRING'];
// Don't log the session hash in the url twice, it's a waste.
$query_string = htmlspecialchars((SMF == 'SSI' ? '' : '?') . preg_replace(array('~;sesc=[^&;]+~', '~' . session_name() . '=' . session_id() . '[&;]~'), array(';sesc', ''), $query_string));
// Just so we know what board error messages are from.
if (isset($_POST['board']) && !isset($_GET['board']))
$query_string .= ($query_string == '' ? 'board=' : ';board=') . $_POST['board'];
// What types of categories do we have?
$known_error_types = array(
'general',
'critical',
'database',
'undefined_vars',
'user',
'template',
'debug',
);
// Make sure the category that was specified is a valid one
$error_type = in_array($error_type, $known_error_types) && $error_type !== true ? $error_type : 'general';
// Don't log the same error countless times, as we can get in a cycle of depression...
$error_info = array($user_info['id'], time(), $user_info['ip'], $query_string, $error_message, (string) $sc, $error_type, $file, $line);
if (empty($last_error) || $last_error != $error_info)
{
// Insert the error into the database.
$smcFunc['db_insert']('',
'{db_prefix}log_errors',
array('id_member' => 'int', 'log_time' => 'int', 'ip' => 'string-16', 'url' => 'string-65534', 'message' => 'string-65534', 'session' => 'string', 'error_type' => 'string', 'file' => 'string-255', 'line' => 'int'),
$error_info,
array('id_error')
);
$last_error = $error_info;
}
// Return the message to make things simpler.
return $error_message;
}
// An irrecoverable error.
function fatal_error($error, $log = 'general')
{
global $txt, $context, $modSettings;
// We don't have $txt yet, but that's okay...
if (empty($txt))
die($error);
setup_fatal_error_context($log || (!empty($modSettings['enableErrorLogging']) && $modSettings['enableErrorLogging'] == 2) ? log_error($error, $log) : $error);
}
// A fatal error with a message stored in the language file.
function fatal_lang_error($error, $log = 'general', $sprintf = array())
{
global $txt, $language, $modSettings, $user_info, $context;
static $fatal_error_called = false;
// Try to load a theme if we don't have one.
if (empty($context['theme_loaded']) && empty($fatal_error_called))
{
$fatal_error_called = true;
loadTheme();
}
// If we have no theme stuff we can't have the language file...
if (empty($context['theme_loaded']))
die($error);
$reload_lang_file = true;
// Log the error in the forum's language, but don't waste the time if we aren't logging
if ($log || (!empty($modSettings['enableErrorLogging']) && $modSettings['enableErrorLogging'] == 2))
{
loadLanguage('Errors', $language);
$reload_lang_file = $language != $user_info['language'];
$error_message = empty($sprintf) ? $txt[$error] : vsprintf($txt[$error], $sprintf);
log_error($error_message, $log);
}
// Load the language file, only if it needs to be reloaded
if ($reload_lang_file)
{
loadLanguage('Errors');
$error_message = empty($sprintf) ? $txt[$error] : vsprintf($txt[$error], $sprintf);
}
setup_fatal_error_context($error_message);
}
// Handler for standard error messages.
function error_handler($error_level, $error_string, $file, $line)
{
global $settings, $modSettings, $db_show_debug;
// Ignore errors if we're ignoring them or they are strict notices from PHP 5 (which cannot be solved without breaking PHP 4.)
if (error_reporting() == 0 || (defined('E_STRICT') && $error_level == E_STRICT && (empty($modSettings['enableErrorLogging']) || $modSettings['enableErrorLogging'] != 2)))
return;
if (strpos($file, 'eval()') !== false && !empty($settings['current_include_filename']))
{
if (function_exists('debug_backtrace'))
{
$array = debug_backtrace();
for ($i = 0; $i < count($array); $i++)
{
if ($array[$i]['function'] != 'loadSubTemplate')
continue;
// This is a bug in PHP, with eval, it seems!
if (empty($array[$i]['args']))
$i++;
break;
}
if (isset($array[$i]) && !empty($array[$i]['args']))
$file = realpath($settings['current_include_filename']) . ' (' . $array[$i]['args'][0] . ' sub template - eval?)';
else
$file = realpath($settings['current_include_filename']) . ' (eval?)';
}
else
$file = realpath($settings['current_include_filename']) . ' (eval?)';
}
if (isset($db_show_debug) && $db_show_debug === true)
{
// Commonly, undefined indexes will occur inside attributes; try to show them anyway!
if ($error_level % 255 != E_ERROR)
{
$temporary = ob_get_contents();
if (substr($temporary, -2) == '="')
echo '"';
}
// Debugging! This should look like a PHP error message.
echo '<br />
<strong>', $error_level % 255 == E_ERROR ? 'Error' : ($error_level % 255 == E_WARNING ? 'Warning' : 'Notice'), '</strong>: ', $error_string, ' in <strong>', $file, '</strong> on line <strong>', $line, '</strong><br />';
}
$error_type = strpos(strtolower($error_string), 'undefined') !== false ? 'undefined_vars' : 'general';
$message = log_error($error_level . ': ' . $error_string, $error_type, $file, $line);
// Let's give integrations a chance to ouput a bit differently
call_integration_hook('integrate_output_error', array($message, $error_type, $error_level, $file, $line));
// Dying on these errors only causes MORE problems (blank pages!)
if ($file == 'Unknown')
return;
// If this is an E_ERROR or E_USER_ERROR.... die. Violently so.
if ($error_level % 255 == E_ERROR)
obExit(false);
else
return;
// If this is an E_ERROR, E_USER_ERROR, E_WARNING, or E_USER_WARNING.... die. Violently so.
if ($error_level % 255 == E_ERROR || $error_level % 255 == E_WARNING)
fatal_error(allowedTo('admin_forum') ? $message : $error_string, false);
// We should NEVER get to this point. Any fatal error MUST quit, or very bad things can happen.
if ($error_level % 255 == E_ERROR)
die('Hacking attempt...');
}
function setup_fatal_error_context($error_message)
{
global $context, $txt, $ssi_on_error_method;
static $level = 0;
// Attempt to prevent a recursive loop.
++$level;
if ($level > 1)
return false;
// Maybe they came from dlattach or similar?
if (SMF != 'SSI' && empty($context['theme_loaded']))
loadTheme();
// Don't bother indexing errors mate...
$context['robot_no_index'] = true;
if (!isset($context['error_title']))
$context['error_title'] = $txt['error_occured'];
$context['error_message'] = isset($context['error_message']) ? $context['error_message'] : $error_message;
if (empty($context['page_title']))
$context['page_title'] = $context['error_title'];
// Display the error message - wireless?
if (defined('WIRELESS') && WIRELESS)
$context['sub_template'] = WIRELESS_PROTOCOL . '_error';
// Load the template and set the sub template.
else
{
loadTemplate('Errors');
$context['sub_template'] = 'fatal_error';
}
// If this is SSI, what do they want us to do?
if (SMF == 'SSI')
{
if (!empty($ssi_on_error_method) && $ssi_on_error_method !== true && is_callable($ssi_on_error_method))
$ssi_on_error_method();
elseif (empty($ssi_on_error_method) || $ssi_on_error_method !== true)
loadSubTemplate('fatal_error');
// No layers?
if (empty($ssi_on_error_method) || $ssi_on_error_method !== true)
exit;
}
// We want whatever for the header, and a footer. (footer includes sub template!)
obExit(null, true, false, true);
/* DO NOT IGNORE:
If you are creating a bridge to SMF or modifying this function, you MUST
make ABSOLUTELY SURE that this function quits and DOES NOT RETURN TO NORMAL
PROGRAM FLOW. Otherwise, security error messages will not be shown, and
your forum will be in a very easily hackable state.
*/
trigger_error('Hacking attempt...', E_USER_ERROR);
}
// Show an error message for the connection problems.
function show_db_error($loadavg = false)
{
global $sourcedir, $mbname, $maintenance, $mtitle, $mmessage, $modSettings;
global $db_connection, $webmaster_email, $db_last_error, $db_error_send, $smcFunc;
// Just check we're not in any buffers, just in case.
for ($i = ob_get_level(); $i > 0; $i--)
@ob_end_clean();
// Don't cache this page!
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-cache');
// Send the right error codes.
header('HTTP/1.1 503 Service Temporarily Unavailable');
header('Status: 503 Service Temporarily Unavailable');
header('Retry-After: 3600');
if ($loadavg == false)
{
// For our purposes, we're gonna want this on if at all possible.
$modSettings['cache_enable'] = '1';
if (($temp = cache_get_data('db_last_error', 600)) !== null)
$db_last_error = max($db_last_error, $temp);
if ($db_last_error < time() - 3600 * 24 * 3 && empty($maintenance) && !empty($db_error_send))
{
require_once($sourcedir . '/Subs-Admin.php');
// Avoid writing to the Settings.php file if at all possible; use shared memory instead.
cache_put_data('db_last_error', time(), 600);
if (($temp = cache_get_data('db_last_error', 600)) == null)
updateLastDatabaseError();
// Language files aren't loaded yet :(.
$db_error = @$smcFunc['db_error']($db_connection);
@mail($webmaster_email, $mbname . ': SMF Database Error!', 'There has been a problem with the database!' . ($db_error == '' ? '' : "\n" . $smcFunc['db_title'] . ' reported:' . "\n" . $db_error) . "\n\n" . 'This is a notice email to let you know that SMF could not connect to the database, contact your host if this continues.');
}
}
if (!empty($maintenance))
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="robots" content="noindex" />
<title>', $mtitle, '</title>
</head>
<body>
<h3>', $mtitle, '</h3>
', $mmessage, '
</body>
</html>';
// If this is a load average problem, display an appropriate message (but we still don't have language files!)
elseif ($loadavg)
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="robots" content="noindex" />
<title>Temporarily Unavailable</title>
</head>
<body>
<h3>Temporarily Unavailable</h3>
Due to high stress on the server the forum is temporarily unavailable. Please try again later.
</body>
</html>';
// What to do? Language files haven't and can't be loaded yet...
else
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="robots" content="noindex" />
<title>Connection Problems</title>
</head>
<body>
<h3>Connection Problems</h3>
Sorry, SMF was unable to connect to the database. This may be caused by the server being busy. Please try again later.
</body>
</html>';
die;
}
?>

967
Sources/Groups.php Normal file
View File

@ -0,0 +1,967 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file currently just shows group info, and allows certain privaledged members to add/remove members.
void Groups()
- allows moderators and users to access the group showing functions.
- handles permission checks, and puts the moderation bar on as required.
void MembergroupMembers()
- can be called from ManageMembergroups if it needs templating within the admin environment.
- show a list of members that are part of a given membergroup.
- called by ?action=moderate;area=viewgroups;sa=members;group=x
- requires the manage_membergroups permission.
- uses the group_members sub template of ManageMembergroups.
- allows to add and remove members from the selected membergroup.
- allows sorting on several columns.
- redirects to itself.
int list_getGroupRequestCount(string where)
- callback function for createList()
- returns the count of group requests
array list_getGroupRequests(int start, int items_per_page, string sort, string where)
- callback function for createList()
- returns an array of group requests
- each group request has:
'id'
'member_link'
'group_link'
'reason'
'time_submitted'
*/
// Entry point, permission checks, admin bars, etc.
function Groups()
{
global $context, $txt, $scripturl, $sourcedir, $user_info;
// The sub-actions that we can do. Format "Function Name, Mod Bar Index if appropriate".
$subActions = array(
'index' => array('GroupList', 'view_groups'),
'members' => array('MembergroupMembers', 'view_groups'),
'requests' => array('GroupRequests', 'group_requests'),
);
// Default to sub action 'index' or 'settings' depending on permissions.
$_REQUEST['sa'] = isset($_REQUEST['sa']) && isset($subActions[$_REQUEST['sa']]) ? $_REQUEST['sa'] : 'index';
// Get the template stuff up and running.
loadLanguage('ManageMembers');
loadLanguage('ModerationCenter');
loadTemplate('ManageMembergroups');
// If we can see the moderation center, and this has a mod bar entry, add the mod center bar.
if (allowedTo('access_mod_center') || $user_info['mod_cache']['bq'] != '0=1' || $user_info['mod_cache']['gq'] != '0=1' || allowedTo('manage_membergroups'))
{
require_once($sourcedir . '/ModerationCenter.php');
$_GET['area'] = $_REQUEST['sa'] == 'requests' ? 'groups' : 'viewgroups';
ModerationMain(true);
}
// Otherwise add something to the link tree, for normal people.
else
{
isAllowedTo('view_mlist');
$context['linktree'][] = array(
'url' => $scripturl . '?action=groups',
'name' => $txt['groups'],
);
}
// Call the actual function.
$subActions[$_REQUEST['sa']][0]();
}
// This very simply lists the groups, nothing snazy.
function GroupList()
{
global $txt, $scripturl, $user_profile, $user_info, $context, $settings, $modSettings, $smcFunc, $sourcedir;
// Yep, find the groups...
$request = $smcFunc['db_query']('', '
SELECT mg.id_group, mg.group_name, mg.description, mg.group_type, mg.online_color, mg.hidden,
mg.stars, IFNULL(gm.id_member, 0) AS can_moderate
FROM {db_prefix}membergroups AS mg
LEFT JOIN {db_prefix}group_moderators AS gm ON (gm.id_group = mg.id_group AND gm.id_member = {int:current_member})
WHERE mg.min_posts = {int:min_posts}
AND mg.id_group != {int:mod_group}' . (allowedTo('admin_forum') ? '' : '
AND mg.group_type != {int:is_protected}') . '
ORDER BY group_name',
array(
'current_member' => $user_info['id'],
'min_posts' => -1,
'mod_group' => 3,
'is_protected' => 1,
)
);
// This is where we store our groups.
$context['groups'] = array();
$group_ids = array();
$context['can_moderate'] = allowedTo('manage_membergroups');
while ($row = $smcFunc['db_fetch_assoc']($request))
{
// We only list the groups they can see.
if ($row['hidden'] && !$row['can_moderate'] && !allowedTo('manage_membergroups'))
continue;
$row['stars'] = explode('#', $row['stars']);
$context['groups'][$row['id_group']] = array(
'id' => $row['id_group'],
'name' => $row['group_name'],
'desc' => $row['description'],
'color' => $row['online_color'],
'type' => $row['group_type'],
'num_members' => 0,
'stars' => !empty($row['stars'][0]) && !empty($row['stars'][1]) ? str_repeat('<img src="' . $settings['images_url'] . '/' . $row['stars'][1] . '" alt="*" />', $row['stars'][0]) : '',
);
$context['can_moderate'] |= $row['can_moderate'];
$group_ids[] = $row['id_group'];
}
$smcFunc['db_free_result']($request);
// Count up the members separately...
if (!empty($group_ids))
{
$query = $smcFunc['db_query']('', '
SELECT id_group, COUNT(*) AS num_members
FROM {db_prefix}members
WHERE id_group IN ({array_int:group_list})
GROUP BY id_group',
array(
'group_list' => $group_ids,
)
);
while ($row = $smcFunc['db_fetch_assoc']($query))
$context['groups'][$row['id_group']]['num_members'] += $row['num_members'];
$smcFunc['db_free_result']($query);
// Only do additional groups if we can moderate...
if ($context['can_moderate'])
{
$query = $smcFunc['db_query']('', '
SELECT mg.id_group, COUNT(*) AS num_members
FROM {db_prefix}membergroups AS mg
INNER JOIN {db_prefix}members AS mem ON (mem.additional_groups != {string:blank_screen}
AND mem.id_group != mg.id_group
AND FIND_IN_SET(mg.id_group, mem.additional_groups) != 0)
WHERE mg.id_group IN ({array_int:group_list})
GROUP BY mg.id_group',
array(
'group_list' => $group_ids,
'blank_screen' => '',
)
);
while ($row = $smcFunc['db_fetch_assoc']($query))
$context['groups'][$row['id_group']]['num_members'] += $row['num_members'];
$smcFunc['db_free_result']($query);
}
}
$context['sub_template'] = 'group_index';
$context['page_title'] = $txt['viewing_groups'];
// Making a list is not hard with this beauty.
require_once($sourcedir . '/Subs-List.php');
// Use the standard templates for showing this.
$listOptions = array(
'id' => 'group_lists',
'title' => $context['page_title'],
'get_items' => array(
'function' => 'list_getGroups',
),
'columns' => array(
'group' => array(
'header' => array(
'value' => $txt['name'],
),
'data' => array(
'function' => create_function('$group', '
global $scripturl, $context;
$output = \'<a href="\' . $scripturl . \'?action=\' . $context[\'current_action\'] . (isset($context[\'admin_area\']) ? \';area=\' . $context[\'admin_area\'] : \'\') . \';sa=members;group=\' . $group[\'id\'] . \'" \' . ($group[\'color\'] ? \'style="color: \' . $group[\'color\'] . \';"\' : \'\') . \'>\' . $group[\'name\'] . \'</a>\';
if ($group[\'desc\'])
$output .= \'<div class="smalltext">\' . $group[\'desc\'] . \'</div>\';
return $output;
'),
'style' => 'width: 50%;',
),
),
'stars' => array(
'header' => array(
'value' => $txt['membergroups_stars'],
),
'data' => array(
'db' => 'stars',
),
),
'moderators' => array(
'header' => array(
'value' => $txt['moderators'],
),
'data' => array(
'function' => create_function('$group', '
global $txt;
return empty($group[\'moderators\']) ? \'<em>\' . $txt[\'membergroups_new_copy_none\'] . \'</em>\' : implode(\', \', $group[\'moderators\']);
'),
),
),
'members' => array(
'header' => array(
'value' => $txt['membergroups_members_top'],
),
'data' => array(
'comma_format' => true,
'db' => 'num_members',
),
),
),
);
// Create the request list.
createList($listOptions);
$context['sub_template'] = 'show_list';
$context['default_list'] = 'group_lists';
}
// Get the group information for the list.
function list_getGroups($start, $items_per_page, $sort)
{
global $smcFunc, $txt, $scripturl, $user_info, $settings;
// Yep, find the groups...
$request = $smcFunc['db_query']('', '
SELECT mg.id_group, mg.group_name, mg.description, mg.group_type, mg.online_color, mg.hidden,
mg.stars, IFNULL(gm.id_member, 0) AS can_moderate
FROM {db_prefix}membergroups AS mg
LEFT JOIN {db_prefix}group_moderators AS gm ON (gm.id_group = mg.id_group AND gm.id_member = {int:current_member})
WHERE mg.min_posts = {int:min_posts}
AND mg.id_group != {int:mod_group}' . (allowedTo('admin_forum') ? '' : '
AND mg.group_type != {int:is_protected}') . '
ORDER BY group_name',
array(
'current_member' => $user_info['id'],
'min_posts' => -1,
'mod_group' => 3,
'is_protected' => 1,
)
);
// Start collecting the data.
$groups = array();
$group_ids = array();
$context['can_moderate'] = allowedTo('manage_membergroups');
while ($row = $smcFunc['db_fetch_assoc']($request))
{
// We only list the groups they can see.
if ($row['hidden'] && !$row['can_moderate'] && !allowedTo('manage_membergroups'))
continue;
$row['stars'] = explode('#', $row['stars']);
$groups[$row['id_group']] = array(
'id' => $row['id_group'],
'name' => $row['group_name'],
'desc' => $row['description'],
'color' => $row['online_color'],
'type' => $row['group_type'],
'num_members' => 0,
'moderators' => array(),
'stars' => !empty($row['stars'][0]) && !empty($row['stars'][1]) ? str_repeat('<img src="' . $settings['images_url'] . '/' . $row['stars'][1] . '" alt="*" />', $row['stars'][0]) : '',
);
$context['can_moderate'] |= $row['can_moderate'];
$group_ids[] = $row['id_group'];
}
$smcFunc['db_free_result']($request);
// Count up the members separately...
if (!empty($group_ids))
{
$query = $smcFunc['db_query']('', '
SELECT id_group, COUNT(*) AS num_members
FROM {db_prefix}members
WHERE id_group IN ({array_int:group_list})
GROUP BY id_group',
array(
'group_list' => $group_ids,
)
);
while ($row = $smcFunc['db_fetch_assoc']($query))
$groups[$row['id_group']]['num_members'] += $row['num_members'];
$smcFunc['db_free_result']($query);
// Only do additional groups if we can moderate...
if ($context['can_moderate'])
{
$query = $smcFunc['db_query']('', '
SELECT mg.id_group, COUNT(*) AS num_members
FROM {db_prefix}membergroups AS mg
INNER JOIN {db_prefix}members AS mem ON (mem.additional_groups != {string:blank_screen}
AND mem.id_group != mg.id_group
AND FIND_IN_SET(mg.id_group, mem.additional_groups) != 0)
WHERE mg.id_group IN ({array_int:group_list})
GROUP BY mg.id_group',
array(
'group_list' => $group_ids,
'blank_screen' => '',
)
);
while ($row = $smcFunc['db_fetch_assoc']($query))
$groups[$row['id_group']]['num_members'] += $row['num_members'];
$smcFunc['db_free_result']($query);
}
}
// Get any group moderators.
// Count up the members separately...
if (!empty($group_ids))
{
$query = $smcFunc['db_query']('', '
SELECT mods.id_group, mods.id_member, mem.member_name, mem.real_name
FROM {db_prefix}group_moderators AS mods
INNER JOIN {db_prefix}members AS mem ON (mem.id_member = mods.id_member)
WHERE mods.id_group IN ({array_int:group_list})',
array(
'group_list' => $group_ids,
)
);
while ($row = $smcFunc['db_fetch_assoc']($query))
$groups[$row['id_group']]['moderators'][] = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>';
$smcFunc['db_free_result']($query);
}
return $groups;
}
// How many groups are there that are visible?
function list_getGroupCount()
{
global $smcFunc;
$request = $smcFunc['db_query']('', '
SELECT COUNT(id_group) AS group_count
FROM {db_prefix}membergroups
WHERE mg.min_posts = {int:min_posts}
AND mg.id_group != {int:mod_group}' . (allowedTo('admin_forum') ? '' : '
AND mg.group_type != {int:is_protected}'),
array(
'min_posts' => -1,
'mod_group' => 3,
'is_protected' => 1,
)
);
list ($group_count) = $smcFunc['db_fetch_row']($request);
$smcFunc['db_free_result']($request);
return $group_count;
}
// Display members of a group, and allow adding of members to a group. Silly function name though ;)
function MembergroupMembers()
{
global $txt, $scripturl, $context, $modSettings, $sourcedir, $user_info, $settings, $smcFunc;
$_REQUEST['group'] = isset($_REQUEST['group']) ? (int) $_REQUEST['group'] : 0;
// No browsing of guests, membergroup 0 or moderators.
if (in_array($_REQUEST['group'], array(-1, 0, 3)))
fatal_lang_error('membergroup_does_not_exist', false);
// Load up the group details.
$request = $smcFunc['db_query']('', '
SELECT id_group AS id, group_name AS name, CASE WHEN min_posts = {int:min_posts} THEN 1 ELSE 0 END AS assignable, hidden, online_color,
stars, description, CASE WHEN min_posts != {int:min_posts} THEN 1 ELSE 0 END AS is_post_group, group_type
FROM {db_prefix}membergroups
WHERE id_group = {int:id_group}
LIMIT 1',
array(
'min_posts' => -1,
'id_group' => $_REQUEST['group'],
)
);
// Doesn't exist?
if ($smcFunc['db_num_rows']($request) == 0)
fatal_lang_error('membergroup_does_not_exist', false);
$context['group'] = $smcFunc['db_fetch_assoc']($request);
$smcFunc['db_free_result']($request);
// Fix the stars.
$context['group']['stars'] = explode('#', $context['group']['stars']);
$context['group']['stars'] = !empty($context['group']['stars'][0]) && !empty($context['group']['stars'][1]) ? str_repeat('<img src="' . $settings['images_url'] . '/' . $context['group']['stars'][1] . '" alt="*" />', $context['group']['stars'][0]) : '';
$context['group']['can_moderate'] = allowedTo('manage_membergroups') && (allowedTo('admin_forum') || $context['group']['group_type'] != 1);
$context['linktree'][] = array(
'url' => $scripturl . '?action=groups;sa=members;group=' . $context['group']['id'],
'name' => $context['group']['name'],
);
// Load all the group moderators, for fun.
$request = $smcFunc['db_query']('', '
SELECT mem.id_member, mem.real_name
FROM {db_prefix}group_moderators AS mods
INNER JOIN {db_prefix}members AS mem ON (mem.id_member = mods.id_member)
WHERE mods.id_group = {int:id_group}',
array(
'id_group' => $_REQUEST['group'],
)
);
$context['group']['moderators'] = array();
while ($row = $smcFunc['db_fetch_assoc']($request))
{
$context['group']['moderators'][] = array(
'id' => $row['id_member'],
'name' => $row['real_name']
);
if ($user_info['id'] == $row['id_member'] && $context['group']['group_type'] != 1)
$context['group']['can_moderate'] = true;
}
$smcFunc['db_free_result']($request);
// If this group is hidden then it can only "exists" if the user can moderate it!
if ($context['group']['hidden'] && !$context['group']['can_moderate'])
fatal_lang_error('membergroup_does_not_exist', false);
// You can only assign membership if you are the moderator and/or can manage groups!
if (!$context['group']['can_moderate'])
$context['group']['assignable'] = 0;
// Non-admins cannot assign admins.
elseif ($context['group']['id'] == 1 && !allowedTo('admin_forum'))
$context['group']['assignable'] = 0;
// Removing member from group?
if (isset($_POST['remove']) && !empty($_REQUEST['rem']) && is_array($_REQUEST['rem']) && $context['group']['assignable'])
{
checkSession();
// Make sure we're dealing with integers only.
foreach ($_REQUEST['rem'] as $key => $group)
$_REQUEST['rem'][$key] = (int) $group;
require_once($sourcedir . '/Subs-Membergroups.php');
removeMembersFromGroups($_REQUEST['rem'], $_REQUEST['group'], true);
}
// Must be adding new members to the group...
elseif (isset($_REQUEST['add']) && (!empty($_REQUEST['toAdd']) || !empty($_REQUEST['member_add'])) && $context['group']['assignable'])
{
checkSession();
$member_query = array();
$member_parameters = array();
// Get all the members to be added... taking into account names can be quoted ;)
$_REQUEST['toAdd'] = strtr($smcFunc['htmlspecialchars']($_REQUEST['toAdd'], ENT_QUOTES), array('&quot;' => '"'));
preg_match_all('~"([^"]+)"~', $_REQUEST['toAdd'], $matches);
$member_names = array_unique(array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $_REQUEST['toAdd']))));
foreach ($member_names as $index => $member_name)
{
$member_names[$index] = trim($smcFunc['strtolower']($member_names[$index]));
if (strlen($member_names[$index]) == 0)
unset($member_names[$index]);
}
// Any passed by ID?
$member_ids = array();
if (!empty($_REQUEST['member_add']))
foreach ($_REQUEST['member_add'] as $id)
if ($id > 0)
$member_ids[] = (int) $id;
// Construct the query pelements.
if (!empty($member_ids))
{
$member_query[] = 'id_member IN ({array_int:member_ids})';
$member_parameters['member_ids'] = $member_ids;
}
if (!empty($member_names))
{
$member_query[] = 'LOWER(member_name) IN ({array_string:member_names})';
$member_query[] = 'LOWER(real_name) IN ({array_string:member_names})';
$member_parameters['member_names'] = $member_names;
}
$members = array();
if (!empty($member_query))
{
$request = $smcFunc['db_query']('', '
SELECT id_member
FROM {db_prefix}members
WHERE (' . implode(' OR ', $member_query) . ')
AND id_group != {int:id_group}
AND FIND_IN_SET({int:id_group}, additional_groups) = 0',
array_merge($member_parameters, array(
'id_group' => $_REQUEST['group'],
))
);
while ($row = $smcFunc['db_fetch_assoc']($request))
$members[] = $row['id_member'];
$smcFunc['db_free_result']($request);
}
// !!! Add $_POST['additional'] to templates!
// Do the updates...
if (!empty($members))
{
require_once($sourcedir . '/Subs-Membergroups.php');
addMembersToGroup($members, $_REQUEST['group'], isset($_POST['additional']) || $context['group']['hidden'] ? 'only_additional' : 'auto', true);
}
}
// Sort out the sorting!
$sort_methods = array(
'name' => 'real_name',
'email' => allowedTo('moderate_forum') ? 'email_address' : 'hide_email ' . (isset($_REQUEST['desc']) ? 'DESC' : 'ASC') . ', email_address',
'active' => 'last_login',
'registered' => 'date_registered',
'posts' => 'posts',
);
// They didn't pick one, default to by name..
if (!isset($_REQUEST['sort']) || !isset($sort_methods[$_REQUEST['sort']]))
{
$context['sort_by'] = 'name';
$querySort = 'real_name';
}
// Otherwise default to ascending.
else
{
$context['sort_by'] = $_REQUEST['sort'];
$querySort = $sort_methods[$_REQUEST['sort']];
}
$context['sort_direction'] = isset($_REQUEST['desc']) ? 'down' : 'up';
// The where on the query is interesting. Non-moderators should only see people who are in this group as primary.
if ($context['group']['can_moderate'])
$where = $context['group']['is_post_group'] ? 'id_post_group = {int:group}' : 'id_group = {int:group} OR FIND_IN_SET({int:group}, additional_groups) != 0';
else
$where = $context['group']['is_post_group'] ? 'id_post_group = {int:group}' : 'id_group = {int:group}';
// Count members of the group.
$request = $smcFunc['db_query']('', '
SELECT COUNT(*)
FROM {db_prefix}members
WHERE ' . $where,
array(
'group' => $_REQUEST['group'],
)
);
list ($context['total_members']) = $smcFunc['db_fetch_row']($request);
$smcFunc['db_free_result']($request);
$context['total_members'] = comma_format($context['total_members']);
// Create the page index.
$context['page_index'] = constructPageIndex($scripturl . '?action=' . ($context['group']['can_moderate'] ? 'moderate;area=viewgroups' : 'groups') . ';sa=members;group=' . $_REQUEST['group'] . ';sort=' . $context['sort_by'] . (isset($_REQUEST['desc']) ? ';desc' : ''), $_REQUEST['start'], $context['total_members'], $modSettings['defaultMaxMembers']);
$context['start'] = $_REQUEST['start'];
$context['can_moderate_forum'] = allowedTo('moderate_forum');
// Load up all members of this group.
$request = $smcFunc['db_query']('', '
SELECT id_member, member_name, real_name, email_address, member_ip, date_registered, last_login,
hide_email, posts, is_activated, real_name
FROM {db_prefix}members
WHERE ' . $where . '
ORDER BY ' . $querySort . ' ' . ($context['sort_direction'] == 'down' ? 'DESC' : 'ASC') . '
LIMIT ' . $context['start'] . ', ' . $modSettings['defaultMaxMembers'],
array(
'group' => $_REQUEST['group'],
)
);
$context['members'] = array();
while ($row = $smcFunc['db_fetch_assoc']($request))
{
$last_online = empty($row['last_login']) ? $txt['never'] : timeformat($row['last_login']);
// Italicize the online note if they aren't activated.
if ($row['is_activated'] % 10 != 1)
$last_online = '<em title="' . $txt['not_activated'] . '">' . $last_online . '</em>';
$context['members'][] = array(
'id' => $row['id_member'],
'name' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>',
'email' => $row['email_address'],
'show_email' => showEmailAddress(!empty($row['hide_email']), $row['id_member']),
'ip' => '<a href="' . $scripturl . '?action=trackip;searchip=' . $row['member_ip'] . '">' . $row['member_ip'] . '</a>',
'registered' => timeformat($row['date_registered']),
'last_online' => $last_online,
'posts' => comma_format($row['posts']),
'is_activated' => $row['is_activated'] % 10 == 1,
);
}
$smcFunc['db_free_result']($request);
// Select the template.
$context['sub_template'] = 'group_members';
$context['page_title'] = $txt['membergroups_members_title'] . ': ' . $context['group']['name'];
}
// Show and manage all group requests.
function GroupRequests()
{
global $txt, $context, $scripturl, $user_info, $sourcedir, $smcFunc, $modSettings, $language;
// Set up the template stuff...
$context['page_title'] = $txt['mc_group_requests'];
$context['sub_template'] = 'show_list';
// Verify we can be here.
if ($user_info['mod_cache']['gq'] == '0=1')
isAllowedTo('manage_membergroups');
// Normally, we act normally...
$where = $user_info['mod_cache']['gq'] == '1=1' || $user_info['mod_cache']['gq'] == '0=1' ? $user_info['mod_cache']['gq'] : 'lgr.' . $user_info['mod_cache']['gq'];
$where_parameters = array();
// We've submitted?
if (isset($_POST[$context['session_var']]) && !empty($_POST['groupr']) && !empty($_POST['req_action']))
{
checkSession('post');
// Clean the values.
foreach ($_POST['groupr'] as $k => $request)
$_POST['groupr'][$k] = (int) $request;
// If we are giving a reason (And why shouldn't we?), then we don't actually do much.
if ($_POST['req_action'] == 'reason')
{
// Different sub template...
$context['sub_template'] = 'group_request_reason';
// And a limitation. We don't care that the page number bit makes no sense, as we don't need it!
$where .= ' AND lgr.id_request IN ({array_int:request_ids})';
$where_parameters['request_ids'] = $_POST['groupr'];
$context['group_requests'] = list_getGroupRequests(0, $modSettings['defaultMaxMessages'], 'lgr.id_request', $where, $where_parameters);
// Let obExit etc sort things out.
obExit();
}
// Otherwise we do something!
else
{
// Get the details of all the members concerned...
$request = $smcFunc['db_query']('', '
SELECT lgr.id_request, lgr.id_member, lgr.id_group, mem.email_address, mem.id_group AS primary_group,
mem.additional_groups AS additional_groups, mem.lngfile, mem.member_name, mem.notify_types,
mg.hidden, mg.group_name
FROM {db_prefix}log_group_requests AS lgr
INNER JOIN {db_prefix}members AS mem ON (mem.id_member = lgr.id_member)
INNER JOIN {db_prefix}membergroups AS mg ON (mg.id_group = lgr.id_group)
WHERE ' . $where . '
AND lgr.id_request IN ({array_int:request_list})
ORDER BY mem.lngfile',
array(
'request_list' => $_POST['groupr'],
)
);
$email_details = array();
$group_changes = array();
while ($row = $smcFunc['db_fetch_assoc']($request))
{
$row['lngfile'] = empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile'];
// If we are approving work out what their new group is.
if ($_POST['req_action'] == 'approve')
{
// For people with more than one request at once.
if (isset($group_changes[$row['id_member']]))
{
$row['additional_groups'] = $group_changes[$row['id_member']]['add'];
$row['primary_group'] = $group_changes[$row['id_member']]['primary'];
}
else
$row['additional_groups'] = explode(',', $row['additional_groups']);
// Don't have it already?
if ($row['primary_group'] == $row['id_group'] || in_array($row['id_group'], $row['additional_groups']))
continue;
// Should it become their primary?
if ($row['primary_group'] == 0 && $row['hidden'] == 0)
$row['primary_group'] = $row['id_group'];
else
$row['additional_groups'][] = $row['id_group'];
// Add them to the group master list.
$group_changes[$row['id_member']] = array(
'primary' => $row['primary_group'],
'add' => $row['additional_groups'],
);
}
// Add required information to email them.
if ($row['notify_types'] != 4)
$email_details[] = array(
'rid' => $row['id_request'],
'member_id' => $row['id_member'],
'member_name' => $row['member_name'],
'group_id' => $row['id_group'],
'group_name' => $row['group_name'],
'email' => $row['email_address'],
'language' => $row['lngfile'],
);
}
$smcFunc['db_free_result']($request);
// Remove the evidence...
$smcFunc['db_query']('', '
DELETE FROM {db_prefix}log_group_requests
WHERE id_request IN ({array_int:request_list})',
array(
'request_list' => $_POST['groupr'],
)
);
// Ensure everyone who is online gets their changes right away.
updateSettings(array('settings_updated' => time()));
if (!empty($email_details))
{
require_once($sourcedir . '/Subs-Post.php');
// They are being approved?
if ($_POST['req_action'] == 'approve')
{
// Make the group changes.
foreach ($group_changes as $id => $groups)
{
// Sanity check!
foreach ($groups['add'] as $key => $value)
if ($value == 0 || trim($value) == '')
unset($groups['add'][$key]);
$smcFunc['db_query']('', '
UPDATE {db_prefix}members
SET id_group = {int:primary_group}, additional_groups = {string:additional_groups}
WHERE id_member = {int:selected_member}',
array(
'primary_group' => $groups['primary'],
'selected_member' => $id,
'additional_groups' => implode(',', $groups['add']),
)
);
}
$lastLng = $user_info['language'];
foreach ($email_details as $email)
{
$replacements = array(
'USERNAME' => $email['member_name'],
'GROUPNAME' => $email['group_name'],
);
$emaildata = loadEmailTemplate('mc_group_approve', $replacements, $email['language']);
sendmail($email['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 2);
}
}
// Otherwise, they are getting rejected (With or without a reason).
else
{
// Same as for approving, kind of.
$lastLng = $user_info['language'];
foreach ($email_details as $email)
{
$custom_reason = isset($_POST['groupreason']) && isset($_POST['groupreason'][$email['rid']]) ? $_POST['groupreason'][$email['rid']] : '';
$replacements = array(
'USERNAME' => $email['member_name'],
'GROUPNAME' => $email['group_name'],
);
if (!empty($custom_reason))
$replacements['REASON'] = $custom_reason;
$emaildata = loadEmailTemplate(empty($custom_reason) ? 'mc_group_reject' : 'mc_group_reject_reason', $replacements, $email['language']);
sendmail($email['email'], $emaildata['subject'], $emaildata['body'], null, null, false, 2);
}
}
}
// Restore the current language.
loadLanguage('ModerationCenter');
}
}
// We're going to want this for making our list.
require_once($sourcedir . '/Subs-List.php');
// This is all the information required for a group listing.
$listOptions = array(
'id' => 'group_request_list',
'title' => $txt['mc_group_requests'],
'width' => '100%',
'items_per_page' => $modSettings['defaultMaxMessages'],
'no_items_label' => $txt['mc_groupr_none_found'],
'base_href' => $scripturl . '?action=groups;sa=requests',
'default_sort_col' => 'member',
'get_items' => array(
'function' => 'list_getGroupRequests',
'params' => array(
$where,
$where_parameters,
),
),
'get_count' => array(
'function' => 'list_getGroupRequestCount',
'params' => array(
$where,
$where_parameters,
),
),
'columns' => array(
'member' => array(
'header' => array(
'value' => $txt['mc_groupr_member'],
),
'data' => array(
'db' => 'member_link',
),
'sort' => array(
'default' => 'mem.member_name',
'reverse' => 'mem.member_name DESC',
),
),
'group' => array(
'header' => array(
'value' => $txt['mc_groupr_group'],
),
'data' => array(
'db' => 'group_link',
),
'sort' => array(
'default' => 'mg.group_name',
'reverse' => 'mg.group_name DESC',
),
),
'reason' => array(
'header' => array(
'value' => $txt['mc_groupr_reason'],
),
'data' => array(
'db' => 'reason',
),
),
'action' => array(
'header' => array(
'value' => '<input type="checkbox" class="input_check" onclick="invertAll(this, this.form);" />',
'style' => 'width: 4%;',
),
'data' => array(
'sprintf' => array(
'format' => '<input type="checkbox" name="groupr[]" value="%1$d" class="input_check" />',
'params' => array(
'id' => false,
),
),
'style' => 'text-align: center;',
),
),
),
'form' => array(
'href' => $scripturl . '?action=groups;sa=requests',
'include_sort' => true,
'include_start' => true,
'hidden_fields' => array(
$context['session_var'] => $context['session_id'],
),
),
'additional_rows' => array(
array(
'position' => 'bottom_of_list',
'value' => '
<select name="req_action" onchange="if (this.value != 0 &amp;&amp; (this.value == \'reason\' || confirm(\'' . $txt['mc_groupr_warning'] . '\'))) this.form.submit();">
<option value="0">' . $txt['with_selected'] . ':</option>
<option value="0">---------------------</option>
<option value="approve">' . $txt['mc_groupr_approve'] . '</option>
<option value="reject">' . $txt['mc_groupr_reject'] . '</option>
<option value="reason">' . $txt['mc_groupr_reject_w_reason'] . '</option>
</select>
<input type="submit" name="go" value="' . $txt['go'] . '" onclick="var sel = document.getElementById(\'req_action\'); if (sel.value != 0 &amp;&amp; sel.value != \'reason\' &amp;&amp; !confirm(\'' . $txt['mc_groupr_warning'] . '\')) return false;" class="button_submit" />',
'align' => 'right',
),
),
);
// Create the request list.
createList($listOptions);
$context['default_list'] = 'group_request_list';
}
function list_getGroupRequestCount($where, $where_parameters)
{
global $smcFunc;
$request = $smcFunc['db_query']('', '
SELECT COUNT(*)
FROM {db_prefix}log_group_requests AS lgr
WHERE ' . $where,
array_merge($where_parameters, array(
))
);
list ($totalRequests) = $smcFunc['db_fetch_row']($request);
$smcFunc['db_free_result']($request);
return $totalRequests;
}
function list_getGroupRequests($start, $items_per_page, $sort, $where, $where_parameters)
{
global $smcFunc, $txt, $scripturl;
$request = $smcFunc['db_query']('', '
SELECT lgr.id_request, lgr.id_member, lgr.id_group, lgr.time_applied, lgr.reason,
mem.member_name, mg.group_name, mg.online_color, mem.real_name
FROM {db_prefix}log_group_requests AS lgr
INNER JOIN {db_prefix}members AS mem ON (mem.id_member = lgr.id_member)
INNER JOIN {db_prefix}membergroups AS mg ON (mg.id_group = lgr.id_group)
WHERE ' . $where . '
ORDER BY {raw:sort}
LIMIT ' . $start . ', ' . $items_per_page,
array_merge($where_parameters, array(
'sort' => $sort,
))
);
$group_requests = array();
while ($row = $smcFunc['db_fetch_assoc']($request))
{
$group_requests[] = array(
'id' => $row['id_request'],
'member_link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>',
'group_link' => '<span style="color: ' . $row['online_color'] . '">' . $row['group_name'] . '</span>',
'reason' => censorText($row['reason']),
'time_submitted' => timeformat($row['time_applied']),
);
}
$smcFunc['db_free_result']($request);
return $group_requests;
}
?>

111
Sources/Help.php Normal file
View File

@ -0,0 +1,111 @@
<?php
/**
* Simple Machines Forum (SMF)
*
* @package SMF
* @author Simple Machines http://www.simplemachines.org
* @copyright 2011 Simple Machines
* @license http://www.simplemachines.org/about/smf/license.php BSD
*
* @version 2.0
*/
if (!defined('SMF'))
die('Hacking attempt...');
/* This file has the important job of taking care of help messages and the
help center. It does this with two simple functions:
void ShowHelp()
- loads information needed for the help section.
- accesed by ?action=help.
- uses the Help template and Manual language file.
void ShowAdminHelp()
- shows a popup for administrative or user help.
- uses the help parameter to decide what string to display and where
to get the string from. ($helptxt or $txt?)
- loads the ManagePermissions language file if the help starts with
permissionhelp.
- uses the Help template, popup sub template, no layers.
- accessed via ?action=helpadmin;help=??.
*/
// Redirect to the user help ;).
function ShowHelp()
{
global $scripturl, $context, $txt;
loadTemplate('Help');
loadLanguage('Manual');
// We need to know where our wiki is.
$context['wiki_url'] = 'http://wiki.simplemachines.org/smf';
// Sections were are going to link...
$context['manual_sections'] = array(
'registering' => 'Registering',
'logging_in' => 'Logging_In',
'profile' => 'Profile',
'search' => 'Search',
'posting' => 'Posting',
'bbc' => 'Bulletin_board_code',
'personal_messages' => 'Personal_messages',
'memberlist' => 'Memberlist',
'calendar' => 'Calendar',
'features' => 'Features',
);
// Build the link tree.
$context['linktree'][] = array(
'url' => $scripturl . '?action=help',
'name' => $txt['help'],
);
// Lastly, some minor template stuff.
$context['page_title'] = $txt['manual_smf_user_help'];
$context['sub_template'] = 'manual';
}
// Show some of the more detailed help to give the admin an idea...
function ShowAdminHelp()
{
global $txt, $helptxt, $context, $scripturl;
if (!isset($_GET['help']) || !is_string($_GET['help']))
fatal_lang_error('no_access', false);
if (!isset($helptxt))
$helptxt = array();
// Load the admin help language file and template.
loadLanguage('Help');
// Permission specific help?
if (isset($_GET['help']) && substr($_GET['help'], 0, 14) == 'permissionhelp')
loadLanguage('ManagePermissions');
loadTemplate('Help');
// Set the page title to something relevant.
$context['page_title'] = $context['forum_name'] . ' - ' . $txt['help'];
// Don't show any template layers, just the popup sub template.
$context['template_layers'] = array();
$context['sub_template'] = 'popup';
// What help string should be used?
if (isset($helptxt[$_GET['help']]))
$context['help_text'] = $helptxt[$_GET['help']];
elseif (isset($txt[$_GET['help']]))
$context['help_text'] = $txt[$_GET['help']];
else
$context['help_text'] = $_GET['help'];
// Does this text contain a link that we should fill in?
if (preg_match('~%([0-9]+\$)?s\?~', $context['help_text'], $match))
$context['help_text'] = sprintf($context['help_text'], $scripturl, $context['session_id'], $context['session_var']);
}
?>

Some files were not shown because too many files have changed in this diff Show More