system/classes/timezoneconfig.class.php
author Dirk Haun <dirk@haun-online.de>
Sun, 20 Sep 2009 19:07:20 +0200
branchHEAD
changeset 7432 3125f1336c8c
parent 7431 ecdf072e268e
child 7444 252d8d24012d
permissions -rw-r--r--
Added setUserTimeZone method
     1 <?php
     2 
     3 /* Reminder: always indent with 4 spaces (no tabs). */
     4 // +---------------------------------------------------------------------------+
     5 // | Geeklog 1.6                                                               |
     6 // +---------------------------------------------------------------------------+
     7 // | timezoneconfig.class.php                                                  |
     8 // |                                                                           |
     9 // | Helper class for time zone handling                                       |
    10 // +---------------------------------------------------------------------------+
    11 // | Copyright (C) 2009 by the following authors:                              |
    12 // |                                                                           |
    13 // | Authors: Dirk Haun             - dirk AT haun-online DOT de               |
    14 // | based on earlier work by Oliver Spiesshofer, Yew Loong, and others        |
    15 // +---------------------------------------------------------------------------+
    16 // |                                                                           |
    17 // | This program is free software; you can redistribute it and/or             |
    18 // | modify it under the terms of the GNU General Public License               |
    19 // | as published by the Free Software Foundation; either version 2            |
    20 // | of the License, or (at your option) any later version.                    |
    21 // |                                                                           |
    22 // | This program is distributed in the hope that it will be useful,           |
    23 // | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
    24 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             |
    25 // | GNU General Public License for more details.                              |
    26 // |                                                                           |
    27 // | You should have received a copy of the GNU General Public License         |
    28 // | along with this program; if not, write to the Free Software Foundation,   |
    29 // | Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.           |
    30 // |                                                                           |
    31 // +---------------------------------------------------------------------------+
    32 
    33 /**
    34 * Geeklog Time Zone Config class
    35 *
    36 * A collection of static (for now) methods dealing with time zone handling.
    37 *
    38 * For the original "Timezone Hack" discussion, see
    39 * @link http://www.geeklog.net/forum/viewtopic.php?showtopic=21232
    40 * 
    41 * @author Dirk Haun, dirk AT haun-online DOT de
    42 * 
    43 */
    44 class TimeZoneConfig {
    45 
    46     /**
    47     * Set the system's timezone
    48     *
    49     * @param    string  $tz     timezone to set; use $_CONF['timezone'] if empty
    50     * @return   void
    51     * @static
    52     *
    53     */
    54     function setSystemTimeZone($tz = '')
    55     {
    56         global $_CONF;
    57 
    58         static $system_timezone = '';
    59 
    60         if (empty($tz) && !empty($_CONF['timezone'])) {
    61             $tz = $_CONF['timezone'];
    62         }
    63 
    64         if (! empty($tz)) {
    65             if ($tz != $system_timezone) {
    66                 if (function_exists('date_default_timezone_set')) {
    67                     if (! @date_default_timezone_set($tz)) {
    68                         date_default_timezone_set('UTC');
    69                         COM_errorLog("Timezone '$tz' not valid - using 'UTC' instead", 1);
    70                         $system_timezone = 'UTC';
    71                     } else {
    72                         $system_timezone = $tz;
    73                     }
    74                 } elseif (!ini_get('safe_mode') && function_exists('putenv')) {
    75                     // aka "Timezone Hack"
    76                     putenv('TZ=' . $tz);
    77                     $system_timezone = $tz;
    78                 }
    79             }
    80         } elseif (function_exists('date_default_timezone_get')) {
    81             // this is not ideal but will stop PHP 5.3.0ff from complaining ...
    82             $system_timezone = @date_default_timezone_get();
    83             date_default_timezone_set($system_timezone);
    84         }
    85     }
    86 
    87     /**
    88     * Set the user's preferred timezone
    89     *
    90     * Note that does nothing if $_CONF['timezone'] is empty, i.e. if no
    91     * system timezone is defined, we don't set a user timezone either.
    92     *
    93     * @return void
    94     * @static
    95     *
    96     */
    97     function setUserTimeZone()
    98     {
    99         global $_CONF;
   100 
   101         if (! empty($_CONF['timezone'])) {
   102             $tz = TimeZoneConfig::getUserTimeZone();
   103             if (! empty($tz)) {
   104                 TimeZoneConfig::setSystemTimeZone($tz);
   105             }
   106         }
   107     }
   108 
   109     /**
   110     * Get the user's preferred timezone
   111     *
   112     * @return   string  name of the timezone
   113     * @static
   114     *
   115     */
   116     function getUserTimeZone()
   117     {
   118         global $_CONF, $_USER;
   119 
   120         // handle like the theme cookie, i.e. use if user is not logged in
   121         if (isset($_COOKIE[$_CONF['cookie_tzid']]) && empty($_USER['tzid'])) {
   122             $_USER['tzid'] = $_COOKIE[$_CONF['cookie_tzid']];
   123         }
   124 
   125         if (! empty($_USER['tzid'])) {
   126             $timezone = $_USER['tzid'];
   127         } elseif (! empty($_CONF['timezone'])) {
   128             $timezone = $_CONF['timezone'];
   129         } elseif (function_exists('date_default_timezone_get')) {
   130             $timezone = @date_default_timezone_get();
   131         } else {
   132             require_once 'Date/TimeZone.php';
   133 
   134             $tz_obj = Date_TimeZone::getDefault();
   135             $timezone = $tz_obj->id;
   136         }
   137 
   138         return $timezone;
   139     }
   140 
   141     /**
   142     * Provide a dropdown menu of the available timezones
   143     *
   144     * @return   string  HTML for the dropdown
   145     * @static
   146     *
   147     */
   148     function getTimeZoneDropDown($selected = '', $attributes = array())
   149     {
   150         $timezones = TimeZoneConfig::listAvailableTimeZones();
   151 
   152         $selection = '<select';
   153         foreach ($attributes as $name => $value) {
   154             $selection .= sprintf(' %s="%s"', $name, $value);
   155         }
   156         $selection .= '>' . LB;
   157 
   158         foreach ($timezones as $tzid => $tzdisplay) {
   159             $selection .= '<option value="' . $tzid . '"';
   160             if (!empty($selected) && ($selected == $tzid)) {
   161                 $selection .= ' selected="selected"';
   162             }
   163             $selection .= ">$tzdisplay</option>" . LB;
   164         }
   165         $selection .= '</select>';
   166 
   167         return $selection;
   168     }
   169 
   170     /**
   171     * Provide a list of available timezones
   172     *
   173     * @return   array   array of (timezone-short-name, timezone-long-name) pairs
   174     * @static
   175     *
   176     */
   177     function listAvailableTimeZones()
   178     {
   179         $timezones = array();
   180 
   181         // use only timezones that contain one of these
   182         $useonly = array('Africa', 'America', 'Antarctica', 'Arctic', 'Asia',
   183                          'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific',
   184                          'UTC');
   185 
   186         // check if we can use the DateTimeZone class
   187         $useDateTimeZone = false;
   188         if (class_exists('DateTimeZone') && class_exists('ReflectionClass')) {
   189             $rc = new ReflectionClass('DateTimeZone');
   190             if ($rc->hasMethod('listAbbreviations')) {
   191                 $useDateTimeZone = true;
   192             }
   193         }
   194 
   195         if ($useDateTimeZone) {
   196 
   197             $T = DateTimeZone::listAbbreviations();
   198             foreach ($T as $tzid => $entries) {
   199                 $shortname = strtoupper($tzid);
   200                 foreach ($entries as $data) {
   201                     $tzcheck = explode('/', $data['timezone_id']);
   202                     if (! in_array($tzcheck[0], $useonly)) {
   203                         continue;
   204                     }
   205 
   206                     $hours = $data['offset'] / 3600;
   207                     $hours = ((int) ($hours * 100) / 100);
   208                     if ($hours > 0) {
   209                         $hours = "+$hours";
   210                     }
   211 
   212                     $tzcode = str_replace('_', ' ', $data['timezone_id']);
   213                     $tzcode = htmlspecialchars($tzcode);
   214                     $formattedTimezone = "$hours, $shortname ($tzcode)";
   215                     $timezones[$data['timezone_id']] = $formattedTimezone;
   216                 }
   217             }
   218 
   219         } else { // DateTimeZone not available - use PEAR Date class
   220 
   221             require_once 'Date/TimeZone.php';
   222 
   223             $T = $GLOBALS['_DATE_TIMEZONE_DATA'];
   224 
   225             foreach ($T as $tzid => $tDetails) {
   226                 $tzcheck = explode('/', $tzid);
   227                 if (! in_array($tzcheck[0], $useonly)) {
   228                     continue;
   229                 }
   230                 if (!empty($tzcheck[1]) &&
   231                         (strpos($tzcheck[1], 'Riyadh') === 0)) {
   232                     // these time zones are based on solar time and not widely
   233                     // supported - skip
   234                     continue;
   235                 }
   236 
   237                 $tzcode = str_replace('_', ' ', $tzid);
   238                 $tzcode = htmlspecialchars($tzcode);
   239                 $hours = $tDetails['offset'] / (3600 * 1000);
   240                 $hours = ((int) ($hours * 100) / 100);
   241                 if ($hours > 0) {
   242                     $hours = "+$hours";
   243                 }
   244 
   245                 $formattedTimezone = "$hours, {$tDetails['shortname']} ($tzcode)";
   246                 $timezones[$tzid] = $formattedTimezone;
   247             }
   248 
   249         }
   250 
   251         uasort($timezones, array('TimeZoneConfig', '_sort_by_timezone'));
   252 
   253         return $timezones;
   254     }
   255 
   256     /**
   257     * Helper method: Sort timezone entries
   258     *
   259     * @param    string  $tz1    first timezone
   260     * @param    string  $tz2    second timezone
   261     * @return   int             0: equal, <0: first<second, >0: first>second
   262     * @static
   263     * @access   private
   264     *
   265     */
   266     function _sort_by_timezone($tz1, $tz2)
   267     {
   268         $p1 = explode(',', $tz1);
   269         $p2 = explode(',', $tz2);
   270 
   271         // compare offsets
   272         $o1 = $p1[0];
   273         $o2 = $p2[0];
   274         if ($o1 != $o2) {
   275             return ($o1 < $o2 ? -1 : 1);
   276         }
   277 
   278         // drop offset, pop timezone name, then add it to the end again
   279         array_shift($p1);
   280         $tz1 = trim(implode(',', $p1));
   281         $p1 = explode(' ', $tz1);
   282         $x1 = array_shift($p1);
   283         $p1[] = $x1;
   284         $tz1 = implode(' ', $p1);
   285 
   286         array_shift($p2);
   287         $tz2 = trim(implode(',', $p2));
   288         $p2 = explode(' ', $tz2);
   289         $x2 = array_shift($p2);
   290         $p2[] = $x2;
   291         $tz2 = implode(' ', $p2);
   292 
   293         return strcmp($tz1, $tz2);
   294     }
   295 
   296 }
   297 
   298 ?>