# HG changeset patch # User Dan # Date 1222002087 14400 # Node ID f70d764aab339f41941f0e7bdae39131a5329347 # Parent 1fbce408813c50011fad46ac35dd0ca09952071d Added initial support for DST. Rules are defined in constants.php and are extensible. diff -r 1fbce408813c -r f70d764aab33 includes/common.php --- a/includes/common.php Tue Sep 16 08:22:47 2008 -0400 +++ b/includes/common.php Sun Sep 21 09:01:27 2008 -0400 @@ -170,6 +170,10 @@ global $timezone; $timezone = 0; +// DST settings +global $dst_params; +$dst_params = array(0, 0, 0, 0, 60); + // Divert to CLI loader if running from CLI if ( isset($argc) && isset($argv) ) { @@ -390,7 +394,7 @@ // One quick security check... if ( !is_valid_ip($_SERVER['REMOTE_ADDR']) ) { - die('SECURITY: spoofed IP address'); + die('SECURITY: spoofed IP address: ' . htmlspecialchars($_SERVER['REMOTE_ADDR'])); } // All checks passed! Start the main components up. diff -r 1fbce408813c -r f70d764aab33 includes/constants.php --- a/includes/constants.php Tue Sep 16 08:22:47 2008 -0400 +++ b/includes/constants.php Sun Sep 21 09:01:27 2008 -0400 @@ -92,6 +92,12 @@ define('TOKEN_PARENTHRIGHT', 4); define('TOKEN_NOT', 5); +// DST constants +define('FIRST_SUNDAY', 1); +define('SECOND_SUNDAY', 2); +define('THIRD_SUNDAY', 3); +define('LAST_SUNDAY', 4); + // // User types - don't touch these // @@ -617,3 +623,12 @@ 0xFE => "COM", 0x01 => "TEM", 0x02 => "RES", ); +// DST profiles +global $dst_profiles; +$dst_profiles = array( + 'off' => '0;0;0;0;60', + 'usa' => '3;' . SECOND_SUNDAY . ';11;' . FIRST_SUNDAY . ';60', + 'europe' => '3;' . LAST_SUNDAY . ';10;' . LAST_SUNDAY . ';60', + 'australia' => '10;' . LAST_SUNDAY . ';3;' . LAST_SUNDAY . ';60', + 'tasmania' => '10;' . FIRST_SUNDAY . ';3;' . LAST_SUNDAY . ';60' + ); diff -r 1fbce408813c -r f70d764aab33 includes/functions.php --- a/includes/functions.php Tue Sep 16 08:22:47 2008 -0400 +++ b/includes/functions.php Sun Sep 21 09:01:27 2008 -0400 @@ -271,31 +271,117 @@ if ( !is_int($timestamp) && !is_double($timestamp) && strval(intval($timestamp)) !== $timestamp ) $timestamp = time(); - /* - // List of valid characters for date() - $date_chars = 'dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZFcrU'; - // Split them into an array - $date_chars = enano_str_split($date_chars); - // Emulate date() formatting by replacing date characters with their - // percentage-signed counterparts, but not escaped characters which - // shouldn't be parsed. - foreach ( $date_chars as $char ) - { - $string = str_replace($char, "%$char", $string); - $string = str_replace("\\%$char", $char, $string); - } - */ - // perform timestamp offset global $timezone; // it's gonna be in minutes, so multiply by 60 to offset the unix timestamp $timestamp = $timestamp + ( $timezone * 60 ); + // are we in DST? + global $dst_params; + if ( check_timestamp_dst($timestamp, $dst_params[0], $dst_params[1], $dst_params[2], $dst_params[3]) ) + { + // offset for DST + $timestamp += ( $dst_params[4] * 60 ); + } + // Let PHP do the work for us =) return gmdate($string, $timestamp); } /** + * Determine if a timestamp is within DST. + * @param int Timestamp + * @param int Start month (1-12) of DST + * @param int Which Sunday DST starts on (*_SUNDAY constants) + * @param int End month of DST + * @param int Which Sunday DST ends on + * @return bool + */ + +function check_timestamp_dst($time, $start_month, $start_sunday, $end_month, $end_sunday) +{ + static $sundays = array(FIRST_SUNDAY, SECOND_SUNDAY, THIRD_SUNDAY, LAST_SUNDAY); + + // perform timestamp offset + global $timezone; + // it's gonna be in minutes, so multiply by 60 to offset the unix timestamp + $time = $time + ( $timezone * 60 ); + $year = intval(gmdate('Y', $time)); + + // one-pass validation + if ( !in_array($start_sunday, $sundays) || !in_array($end_sunday, $sundays) || + $start_month < 1 || $start_month > 12 || $end_month < 1 || $end_month > 12 ) + return false; + + // get timestamp of the selected sunday (start) + $dst_start = get_sunday_timestamp($start_month, $start_sunday, $year); + $dst_end = get_sunday_timestamp($end_month, $end_sunday, $year); + + if ( $dst_start > $dst_end ) + { + // start time is past the end time, this means we're in the southern hemisphere + // as a result, if we're within the range, DST is NOT in progress. + return !( $time >= $dst_start && $time <= $dst_end ); + } + + return $time >= $dst_start && $time <= $dst_end; +} + +/** + * Returns a timestamp for the given *_SUNDAY index. + * @param int Month + * @param int Which Sunday (FIRST, SECOND, THIRD, or LAST) + * @param int Year that we're doing our calculations in + * @return int + */ + +function get_sunday_timestamp($month, $sunday, $year) +{ + $days_in_month = array( + 1 => 31, + 2 => $year % 4 == 0 && ( $year % 100 != 0 || ( $year % 100 == 0 && $year % 400 == 0 ) ) ? 29 : 28, + 3 => 31, + 4 => 30, + 5 => 31, + 6 => 30, + 7 => 31, + 8 => 31, + 9 => 30, + 10 => 31, + 11 => 30, + 12 => 31 + ); + + $result = mktime(0, 0, 0, $month, 1, $year); + + // hack. allows a specific day of the month to be set instead of a sunday. not a good place to do this. + if ( is_string($sunday) && substr($sunday, -1) === 'd' ) + { + $result += 86400 * ( intval($sunday) - 1); + return $result; + } + + $tick = 0; + $days_remaining = $days_in_month[$month]; + while ( true ) + { + if ( date('D', $result) == 'Sun' ) + { + $tick++; + if ( ( $tick == 1 && $sunday == FIRST_SUNDAY ) || + ( $tick == 2 && $sunday == SECOND_SUNDAY ) || + ( $tick == 3 && $sunday == THIRD_SUNDAY ) || + ( $sunday == LAST_SUNDAY && $days_remaining < 7 ) ) + break; + } + $days_remaining--; + $result += 86400; + } + + return $result; +} + +/** * Tells you the title for the given page ID string * @param string Page ID string (ex: Special:Administration) * @param bool Optional. If true, and if the namespace turns out to be something other than Article, the namespace prefix will be prepended to the return value. diff -r 1fbce408813c -r f70d764aab33 includes/sessions.php --- a/includes/sessions.php Tue Sep 16 08:22:47 2008 -0400 +++ b/includes/sessions.php Sun Sep 21 09:01:27 2008 -0400 @@ -473,7 +473,15 @@ } } $user = true; + + // set timezone params $GLOBALS['timezone'] = $userdata['user_timezone']; + $GLOBALS['dst_params'] = explode(';', $userdata['user_dst']); + foreach ( $GLOBALS['dst_params'] as &$parm ) + { + if ( substr($parm, -1) != 'd' ) + $parm = intval($parm); + } // Set language if ( !defined('ENANO_ALLOW_LOAD_NOLANG') ) @@ -1038,7 +1046,7 @@ // using a normal call to $db->sql_query to avoid failing on errors here $query = $db->sql_query('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,' . "\n" . ' u.reg_time,u.account_active,u.activation_key,u.user_lang,u.user_title,k.source_ip,k.time,k.auth_level,k.key_type,COUNT(p.message_id) AS num_pms,' . "\n" - . ' u.user_timezone, x.* FROM '.table_prefix.'session_keys AS k' . "\n" + . ' u.user_timezone, u.user_dst, x.* FROM '.table_prefix.'session_keys AS k' . "\n" . ' LEFT JOIN '.table_prefix.'users AS u' . "\n" . ' ON ( u.user_id=k.user_id )' . "\n" . ' LEFT JOIN '.table_prefix.'users_extra AS x' . "\n" @@ -1051,7 +1059,7 @@ if ( !$query && ( defined('IN_ENANO_INSTALL') or defined('IN_ENANO_UPGRADE') ) ) { - $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms, 1440 AS user_timezone, ' . SK_SHORT . ' AS key_type FROM '.table_prefix.'session_keys AS k + $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms, 1440 AS user_timezone, \'0;0;0;0;60\' AS user_dst, ' . SK_SHORT . ' AS key_type FROM '.table_prefix.'session_keys AS k LEFT JOIN '.table_prefix.'users AS u ON ( u.user_id=k.user_id ) LEFT JOIN '.table_prefix.'privmsgs AS p @@ -2707,7 +2715,8 @@ if ( !$q ) $db->_die(); - $groups = array(); + // The l10n engine takes care of this later. + $groups = array(1 => 'Everyone'); if ( $row = $db->fetchrow() ) { @@ -2983,7 +2992,7 @@ { if ( isset($perm2[$i]) ) { - if ( $is_everyone && !$defaults_used[$i] ) + if ( $is_everyone && isset($defaults_used[$i]) && $defaults_used[$i] === false ) continue; // Decide precedence if ( isset($defaults_used[$i]) ) diff -r 1fbce408813c -r f70d764aab33 install/schemas/mysql_stage2.sql --- a/install/schemas/mysql_stage2.sql Tue Sep 16 08:22:47 2008 -0400 +++ b/install/schemas/mysql_stage2.sql Sun Sep 21 09:01:27 2008 -0400 @@ -115,6 +115,7 @@ user_timezone int(12) UNSIGNED NOT NULL DEFAULT 0, user_title varchar(64) DEFAULT NULL, user_group mediumint(5) NOT NULL DEFAULT 1, + user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60', PRIMARY KEY (user_id) ) CHARACTER SET `utf8` COLLATE `utf8_bin`; diff -r 1fbce408813c -r f70d764aab33 install/schemas/postgresql_stage2.sql --- a/install/schemas/postgresql_stage2.sql Tue Sep 16 08:22:47 2008 -0400 +++ b/install/schemas/postgresql_stage2.sql Sun Sep 21 09:01:27 2008 -0400 @@ -115,6 +115,7 @@ user_timezone int NOT NULL DEFAULT 0, user_title varchar(64) DEFAULT NULL, user_group int NOT NULL DEFAULT 1, + user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60', CHECK (avatar_type IN ('jpg', 'png', 'gif', 'grv')), PRIMARY KEY (user_id) ); diff -r 1fbce408813c -r f70d764aab33 install/schemas/upgrade/1.1.4-1.1.5-mysql.sql --- a/install/schemas/upgrade/1.1.4-1.1.5-mysql.sql Tue Sep 16 08:22:47 2008 -0400 +++ b/install/schemas/upgrade/1.1.4-1.1.5-mysql.sql Sun Sep 21 09:01:27 2008 -0400 @@ -1,2 +1,3 @@ ALTER TABLE {{TABLE_PREFIX}}session_keys ADD COLUMN key_type tinyint(1) NOT NULL DEFAULT 0; UPDATE {{TABLE_PREFIX}}session_keys SET key_type = 2 WHERE auth_level > 2; +ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60'; diff -r 1fbce408813c -r f70d764aab33 install/schemas/upgrade/1.1.4-1.1.5-postgresql.sql --- a/install/schemas/upgrade/1.1.4-1.1.5-postgresql.sql Tue Sep 16 08:22:47 2008 -0400 +++ b/install/schemas/upgrade/1.1.4-1.1.5-postgresql.sql Sun Sep 21 09:01:27 2008 -0400 @@ -1,3 +1,4 @@ ALTER TABLE {{TABLE_PREFIX}}session_keys ADD COLUMN key_type smallint NOT NULL DEFAULT 0; UPDATE {{TABLE_PREFIX}}session_keys SET key_type = 2 WHERE auth_level > 2; +ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60'; diff -r 1fbce408813c -r f70d764aab33 language/english/core.json --- a/language/english/core.json Tue Sep 16 08:22:47 2008 -0400 +++ b/language/english/core.json Sun Sep 21 09:01:27 2008 -0400 @@ -692,7 +692,14 @@ title_13: '[UTC + 13] Tonga Time, Phoenix Islands Time', title_14: '[UTC + 14] Line Island Time', // This is a JSON string that lists all the timezones that are defined here. - list: '{"n12":-12,"n11":-11,"n10":-10,"n9p5":-9.5,"n9":-9,"n8":-8,"n7":-7,"n6":-6,"n5":-5,"n4":-4,"n3p5":-3.5,"n3":-3,"n2":-2,"n1":-1,"0":0,"1":1,"2":2,"3":3,"3p5":3.5,"4":4,"4p5":4.5,"5":5,"5p5":5.5,"5p75":5.75,"6":6,"6p5":6.5,"7":7,"8":8,"8p75":8.75,"9":9,"9p5":9.5,"10":10,"10p5":10.5,"11":11,"11p5":11.5,"12":12,"12p75":12.75,"13":13,"14":14}' + list: '{"n12":-12,"n11":-11,"n10":-10,"n9p5":-9.5,"n9":-9,"n8":-8,"n7":-7,"n6":-6,"n5":-5,"n4":-4,"n3p5":-3.5,"n3":-3,"n2":-2,"n1":-1,"0":0,"1":1,"2":2,"3":3,"3p5":3.5,"4":4,"4p5":4.5,"5":5,"5p5":5.5,"5p75":5.75,"6":6,"6p5":6.5,"7":7,"8":8,"8p75":8.75,"9":9,"9p5":9.5,"10":10,"10p5":10.5,"11":11,"11p5":11.5,"12":12,"12p75":12.75,"13":13,"14":14}', + + // DST profiles + dst_off: 'My region doesn\'t use DST', + dst_usa: 'United States: second Sunday of March to first Sunday of November', + dst_europe: 'Europe: last Sunday of March to last Sunday of October', + dst_australia: 'Australia (except Tasmania): last Sunday of October to last Sunday of March', + dst_tasmania: 'Tasmania: first Sunday of October to last Sunday of March' }, etc: { redirect_title: 'Redirecting...', diff -r 1fbce408813c -r f70d764aab33 language/english/user.json --- a/language/english/user.json Tue Sep 16 08:22:47 2008 -0400 +++ b/language/english/user.json Sun Sep 21 09:01:27 2008 -0400 @@ -308,6 +308,7 @@ publicinfo_field_changetheme: 'Change my theme...', publicinfo_field_timezone: 'Time zone:', publicinfo_field_timezone_hint: 'Select the time zone you live in and when Daylight Savings Time occurs, if at all.', + publicinfo_field_dst: 'Daylight saving time:', publicinfo_field_usertitle_title: 'User title:', publicinfo_field_usertitle_hint: 'This can be some text that will be displayed underneath your username.', publicinfo_th_im: 'Instant messenger contact information', diff -r 1fbce408813c -r f70d764aab33 plugins/SpecialUserPrefs.php --- a/plugins/SpecialUserPrefs.php Tue Sep 16 08:22:47 2008 -0400 +++ b/plugins/SpecialUserPrefs.php Sun Sep 21 09:01:27 2008 -0400 @@ -652,6 +652,22 @@