system/classes/timezoneconfig.class.php
author Dirk Haun <dirk@haun-online.de>
Sun, 20 Sep 2009 17:06:57 +0200
branchHEAD
changeset 7431 ecdf072e268e
parent 7430 a053d9023368
child 7432 3125f1336c8c
permissions -rw-r--r--
Keep track of the system time zone we set
     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     * Get the user's preferred timezone
    89     *
    90     * @return   string  name of the timezone
    91     * @static
    92     *
    93     */
    94     function getUserTimeZone()
    95     {
    96         global $_CONF, $_USER;
    97 
    98         // handle like the theme cookie, i.e. use if user is not logged in
    99         if (isset($_COOKIE[$_CONF['cookie_tzid']]) && empty($_USER['tzid'])) {
   100             $_USER['tzid'] = $_COOKIE[$_CONF['cookie_tzid']];
   101         }
   102 
   103         if (! empty($_USER['tzid'])) {
   104             $timezone = $_USER['tzid'];
   105         } elseif (! empty($_CONF['timezone'])) {
   106             $timezone = $_CONF['timezone'];
   107         } elseif (function_exists('date_default_timezone_get')) {
   108             $timezone = @date_default_timezone_get();
   109         } else {
   110             require_once 'Date/TimeZone.php';
   111 
   112             $tz_obj = Date_TimeZone::getDefault();
   113             $timezone = $tz_obj->id;
   114         }
   115 
   116         return $timezone;
   117     }
   118 
   119     /**
   120     * Provide a dropdown menu of the available timezones
   121     *
   122     * @return   string  HTML for the dropdown
   123     * @static
   124     *
   125     */
   126     function getTimeZoneDropDown($selected = '', $attributes = array())
   127     {
   128         $timezones = TimeZoneConfig::listAvailableTimeZones();
   129 
   130         $selection = '<select';
   131         foreach ($attributes as $name => $value) {
   132             $selection .= sprintf(' %s="%s"', $name, $value);
   133         }
   134         $selection .= '>' . LB;
   135 
   136         foreach ($timezones as $tzid => $tzdisplay) {
   137             $selection .= '<option value="' . $tzid . '"';
   138             if (!empty($selected) && ($selected == $tzid)) {
   139                 $selection .= ' selected="selected"';
   140             }
   141             $selection .= ">$tzdisplay</option>" . LB;
   142         }
   143         $selection .= '</select>';
   144 
   145         return $selection;
   146     }
   147 
   148     /**
   149     * Provide a list of available timezones
   150     *
   151     * @return   array   array of (timezone-short-name, timezone-long-name) pairs
   152     * @static
   153     *
   154     */
   155     function listAvailableTimeZones()
   156     {
   157         $timezones = array();
   158 
   159         // use only timezones that contain one of these
   160         $useonly = array('Africa', 'America', 'Antarctica', 'Arctic', 'Asia',
   161                          'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific',
   162                          'UTC');
   163 
   164         // check if we can use the DateTimeZone class
   165         $useDateTimeZone = false;
   166         if (class_exists('DateTimeZone') && class_exists('ReflectionClass')) {
   167             $rc = new ReflectionClass('DateTimeZone');
   168             if ($rc->hasMethod('listAbbreviations')) {
   169                 $useDateTimeZone = true;
   170             }
   171         }
   172 
   173         if ($useDateTimeZone) {
   174 
   175             $T = DateTimeZone::listAbbreviations();
   176             foreach ($T as $tzid => $entries) {
   177                 $shortname = strtoupper($tzid);
   178                 foreach ($entries as $data) {
   179                     $tzcheck = explode('/', $data['timezone_id']);
   180                     if (! in_array($tzcheck[0], $useonly)) {
   181                         continue;
   182                     }
   183 
   184                     $hours = $data['offset'] / 3600;
   185                     $hours = ((int) ($hours * 100) / 100);
   186                     if ($hours > 0) {
   187                         $hours = "+$hours";
   188                     }
   189 
   190                     $tzcode = str_replace('_', ' ', $data['timezone_id']);
   191                     $tzcode = htmlspecialchars($tzcode);
   192                     $formattedTimezone = "$hours, $shortname ($tzcode)";
   193                     $timezones[$data['timezone_id']] = $formattedTimezone;
   194                 }
   195             }
   196 
   197         } else { // DateTimeZone not available - use PEAR Date class
   198 
   199             require_once 'Date/TimeZone.php';
   200 
   201             $T = $GLOBALS['_DATE_TIMEZONE_DATA'];
   202 
   203             foreach ($T as $tzid => $tDetails) {
   204                 $tzcheck = explode('/', $tzid);
   205                 if (! in_array($tzcheck[0], $useonly)) {
   206                     continue;
   207                 }
   208                 if (!empty($tzcheck[1]) &&
   209                         (strpos($tzcheck[1], 'Riyadh') === 0)) {
   210                     // these time zones are based on solar time and not widely
   211                     // supported - skip
   212                     continue;
   213                 }
   214 
   215                 $tzcode = str_replace('_', ' ', $tzid);
   216                 $tzcode = htmlspecialchars($tzcode);
   217                 $hours = $tDetails['offset'] / (3600 * 1000);
   218                 $hours = ((int) ($hours * 100) / 100);
   219                 if ($hours > 0) {
   220                     $hours = "+$hours";
   221                 }
   222 
   223                 $formattedTimezone = "$hours, {$tDetails['shortname']} ($tzcode)";
   224                 $timezones[$tzid] = $formattedTimezone;
   225             }
   226 
   227         }
   228 
   229         uasort($timezones, array('TimeZoneConfig', '_sort_by_timezone'));
   230 
   231         return $timezones;
   232     }
   233 
   234     /**
   235     * Helper method: Sort timezone entries
   236     *
   237     * @param    string  $tz1    first timezone
   238     * @param    string  $tz2    second timezone
   239     * @return   int             0: equal, <0: first<second, >0: first>second
   240     * @static
   241     * @access   private
   242     *
   243     */
   244     function _sort_by_timezone($tz1, $tz2)
   245     {
   246         $p1 = explode(',', $tz1);
   247         $p2 = explode(',', $tz2);
   248 
   249         // compare offsets
   250         $o1 = $p1[0];
   251         $o2 = $p2[0];
   252         if ($o1 != $o2) {
   253             return ($o1 < $o2 ? -1 : 1);
   254         }
   255 
   256         // drop offset, pop timezone name, then add it to the end again
   257         array_shift($p1);
   258         $tz1 = trim(implode(',', $p1));
   259         $p1 = explode(' ', $tz1);
   260         $x1 = array_shift($p1);
   261         $p1[] = $x1;
   262         $tz1 = implode(' ', $p1);
   263 
   264         array_shift($p2);
   265         $tz2 = trim(implode(',', $p2));
   266         $p2 = explode(' ', $tz2);
   267         $x2 = array_shift($p2);
   268         $p2[] = $x2;
   269         $tz2 = implode(' ', $p2);
   270 
   271         return strcmp($tz1, $tz2);
   272     }
   273 
   274 }
   275 
   276 ?>