/style/contrib/mobile.php
PHP | 677 lines | 426 code | 64 blank | 187 comment | 93 complexity | f77f633e295733fb5dca1eee160ce196 MD5 | raw file
- <?php
- /**
- * phpBB Mobile style mod for phpBB 3.0
- *
- * Created by Vjacheslav Trushkin (Arty) for use with one of mobile phpBB styles.
- * See detect_mobile.xml for mod installation instructions.
- * Check http://www.phpbbmobile.com/ for latest version.
- *
- * @version 3.4
- * @license http://opensource.org/licenses/gpl-license.php GNU Public License
- */
- if (!defined('IN_PHPBB'))
- {
- exit;
- }
- /**
- * Mobile style class
- */
- class phpbb_mobile
- {
- /**
- * Mobile style path.
- * Change it to correct string to make script locate mobile style faster.
- * Alternatively you can define 'MOBILE_STYLE_PATH' in includes/constants.php or config.php
- *
- * @var string|bool
- */
- public static $mobile_style_path = '';
- /**
- * Mobile style ID, if style is installed.
- * Change it to correct string to make script locate mobile style faster.
- * Alternatively you can define 'MOBILE_STYLE_ID' in includes/constants.php or config.php
- *
- * If mobile style path is set, this variable will be ignored
- *
- * @var int
- */
- public static $mobile_style_id = 0;
- /**
- * True if mobile style should be used for search engines
- *
- * @var bool
- */
- public static $mobile_seo = true;
-
- /**
- * True if link to switch to mobile style should be shown for desktop browsers
- *
- * @var bool
- */
- public static $always_show_link = true;
- /**
- * @var bool
- */
- protected static $mobile_mode = false;
- protected static $mobile_var = 'mobile';
- protected static $cookie_var = false;
- protected static $is_bot = false;
- protected static $is_desktop = false;
- protected static $passed_mobile_path = false;
- /**
- * Start mobile style setup
- *
- * @param bool|string $style_path Path to mobile style, saved to $passed_mobile_path
- */
- public static function setup($style_path = false)
- {
- global $user;
-
- self::set_cookie_var();
- self::override_template();
- self::$is_bot = empty($user->data['is_bot']) ? false : $user->data['is_bot'];
-
- // Check mode only if it wasn't checked already
- if (self::$mobile_mode === false)
- {
- if (is_string($style_path) && strlen($style_path))
- {
- self::$passed_mobile_path = $style_path;
- }
- elseif (is_int($style_path) && $style_path > 0)
- {
- self::$mobile_style_id = $style_path;
- }
- self::$mobile_mode = self::get_mode();
- }
- if (self::is_desktop_mode(self::$mobile_mode))
- {
- // Force desktop style
- return;
- }
- if (!self::is_mobile_mode(self::$mobile_mode))
- {
- // Detect browser
- $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
- if (!self::is_mobile_browser($user_agent))
- {
- self::$is_desktop = true;
- return;
- }
- }
- // Locate mobile style
- $path = self::locate_mobile_style();
- if ($path === false)
- {
- // Mobile style was not found
- self::set_cookie('404', false);
- self::$mobile_mode = '404';
- return;
- }
- // Set mobile style data
- self::set_mobile_style();
- }
-
- /**
- * Set mobile style
- */
- protected static function set_mobile_style()
- {
- global $user, $template;
-
- // Define MOBILE_STYLE if it is not defined yet
- if (!defined('MOBILE_STYLE'))
- {
- define('MOBILE_STYLE', true);
- }
-
- // Change user->theme data
- $user->theme = array_merge($user->theme, self::user_theme_data());
- $template->orig_tpl_inherits_id = $user->theme['template_inherits_id'];
- // Reset imageset
- $user->img_array = array();
-
- // Set template
- $template->set_template();
- }
-
- /**
- * Override global $template variable
- */
- protected static function override_template()
- {
- if (defined('ADMIN_START'))
- {
- return;
- }
- global $template;
- if (is_a($template, 'mobile_template'))
- {
- return;
- }
- $tpl = new mobile_template();
- $tpl->clone_properties($template);
- $template = $tpl;
- }
-
- /**
- * @return array Data for $user->theme
- */
- protected static function user_theme_data()
- {
- return array(
- 'style_id' => self::$mobile_style_id,
- 'template_storedb' => 0,
- 'template_path' => self::$mobile_style_path,
- 'template_id' => 0,
- 'bbcode_bitfield' => 'lNg=',
- 'template_inherits_id' => 1,
- 'template_inherit_path' => 'prosilver',
- 'theme_path' => self::$mobile_style_path,
- 'theme_name' => self::$mobile_style_path,
- 'theme_storedb' => 0,
- 'theme_id' => 0,
- 'imageset_path' => self::$mobile_style_path,
- 'imageset_id' => 0,
- 'imageset_name' => self::$mobile_style_path,
- );
- }
- /**
- * Set cookie variable name
- */
- protected static function set_cookie_var()
- {
- if (self::$cookie_var !== false)
- {
- return;
- }
- global $config;
- self::$cookie_var = (isset($config['cookie_name']) ? $config['cookie_name'] . '_' : '') . self::$mobile_var;
- }
-
- /**
- * Set cookie value
- *
- * param string $value Cookie value
- * param bool $long If true, cookie will be set for full duration. If false, cookie will be set for browser session duration
- */
- protected static function set_cookie($value, $long = true)
- {
- global $config;
- $cookietime = ($long && empty($_SERVER['HTTP_DNT'])) ? time() + (($config['max_autologin_time']) ? 86400 * (int) $config['max_autologin_time'] : 31536000) : 0;
- $name_data = rawurlencode(self::$cookie_var) . '=' . rawurlencode($value);
- $expire = ($cookietime) ? gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime) : '';
- $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain'];
- header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false);
- }
-
- /**
- * Check if mode triggers mobile style
- *
- * @param string $mode Browser mode
- *
- * @return bool
- */
- protected static function is_mobile_mode($mode)
- {
- return ($mode == 'mobile');
- }
-
- /**
- * Check if mode triggers desktop style
- *
- * @param string $mode Browser mode
- *
- * @return bool
- */
- protected static function is_desktop_mode($mode)
- {
- return ($mode == 'desktop' || $mode == '404');
- }
-
- /*
- * Get browser mode from cookie and $_GET data
- *
- * @return string|false Mobile style mode, false if default
- */
- protected static function get_mode()
- {
- $value = request_var(self::$mobile_var, '');
- switch ($value)
- {
- case 'reset':
- // Reset to default mode
- self::set_cookie('', false);
- return false;
- case 'on':
- // Mobile device detected by JavaScript
- $value = 'mobile';
- self::set_cookie($value, false);
- return $value;
- case 'off':
- // Desktop detected by JavaScript
- $value = 'desktop';
- self::set_cookie($value, false);
- return $value;
- case '404': // Mobile style detected, but not found
- case 'desktop': // Force desktop style
- case 'mobile': // Force mobile style
- self::set_cookie($value, $value != '404');
- return $value;
- }
-
- if (isset($_COOKIE[self::$cookie_var]))
- {
- switch ($_COOKIE[self::$cookie_var])
- {
- case 'mobile': // Force mobile style
- case 'desktop': // Force desktop style
- $value = $_COOKIE[self::$cookie_var];
- return $value;
- }
- }
- else
- {
- self::set_cookie('');
- }
- return false;
- }
-
- /**
- * Return path to styles directory
- *
- * @param bool $include_style_path If true, result will include mobile style path
- *
- * @return string Path to 'styles' or to 'styles/' + mobile style path
- */
- protected static function styles_path($include_style_path = false)
- {
- global $phpbb_root_path;
- return $phpbb_root_path . 'styles' . ($include_style_path ? '/' . self::$mobile_style_path : '');
- }
- /**
- * Check user agent string for mobile browser id.
- *
- * @param string $user_agent User agent string
- *
- * @return bool True if mobile browser
- */
- public static function is_mobile_browser($user_agent)
- {
- if (self::$mobile_seo && self::$is_bot)
- {
- return true;
- }
- if ((strpos($user_agent, 'Mobile') === false && // Generic mobile browser string, most browsers have it.
- strpos($user_agent, 'SymbianOS') === false && // Nokia device running Symbian OS.
- strpos($user_agent, 'Opera M') === false && // Opera Mini or Opera Mobile.
- strpos($user_agent, 'Android') === false && // Android devices that don't have 'Mobile' in UA string.
- stripos($user_agent, 'HTC_') === false && // HTC devices that don't have 'Mobile' nor 'Android' in UA string. Case insensitive.
- strpos($user_agent, 'Fennec/') === false && // Firefox mobile
- strpos($user_agent, 'Kindle') === false && // Kindle Fire tablet
- strpos($user_agent, 'BlackBerry') === false) || // BlackBerry
- strpos($user_agent, 'iPad') !== false) // iPad should be excluded
- {
- // Not a mobile browser
- return false;
- }
- // Mobile browser
- return true;
- }
-
- /**
- * Check if mobile style exists
- *
- * @param string $path Directory name of mobile style
- *
- * @return bool True if mobile style exists
- */
- protected static function check_style_path($path)
- {
- // Locate and read style.cfg
- $style_cfg = self::styles_path() . '/' . $path . '/style.cfg';
- if (!file_exists($style_cfg))
- {
- return false;
- }
- $style_cfg_data = @file_get_contents($style_cfg);
- if ($style_cfg_data === false || strpos($style_cfg_data, 'mobile') === false)
- {
- return false;
- }
-
- // Check style.cfg for "mobile = 1"
- foreach (explode("\n", $style_cfg_data) as $row)
- {
- $list = explode('=', $row);
- if (count($list) == 2 && trim($list[0]) == 'mobile' && trim($list[1]) == '1')
- {
- return true;
- }
- }
- return false;
- }
- /**
- * Check if mobile style exists
- *
- * @param int $id Style id
- *
- * @return string|bool Path to style if mobile style exists, false on error
- */
- protected static function check_style_id($id)
- {
- global $db;
- $id = (int) $id;
- $sql = 'SELECT t.template_path
- FROM ' . STYLES_TABLE . ' s, ' . STYLES_TEMPLATE_TABLE . " t
- WHERE s.style_id = $id
- AND t.template_id = s.template_id";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
- if ($row === false || !self::check_style_path($row['template_path']))
- {
- return false;
- }
- return $row['template_path'];
- }
- /**
- * Locate mobile style
- *
- * @param bool $check_db If true and mobile style id is set, script will check phpbb_styles table for mobile style
- * @param bool $check_dirs If true, script will search for mobile style in styles directory
- *
- * @return string|bool Mobile style path
- */
- public static function locate_mobile_style($check_db = true, $check_dirs = true)
- {
- // Locate by style path
- if (defined('MOBILE_STYLE_PATH') && self::check_style_path(MOBILE_STYLE_PATH))
- {
- self::$mobile_style_path = MOBILE_STYLE_PATH;
- return self::$mobile_style_path;
- }
- if (!empty(self::$mobile_style_path) && self::check_style_path(self::$mobile_style_path))
- {
- return self::$mobile_style_path;
- }
- // Locate by style id
- if ($check_db && defined('MOBILE_STYLE_ID') && ($path = self::check_style_id(MOBILE_STYLE_ID)) !== false)
- {
- self::$mobile_style_path = $path;
- return $path;
- }
- if ($check_db && self::$mobile_style_id && (!defined('MOBILE_STYLE_ID') || MOBILE_STYLE_ID != self::$mobile_style_id) && ($path = self::check_style_id(self::$mobile_style_id)) !== false)
- {
- self::$mobile_style_path = $path;
- return $path;
- }
- // Default style path, passed in session.php
- if (!empty(self::$passed_mobile_path) && self::check_style_path(self::$passed_mobile_path))
- {
- self::$mobile_style_path = self::$passed_mobile_path;
- return self::$mobile_style_path;
- }
- // Search styles directory
- if (!$check_dirs)
- {
- return false;
- }
- $styles_dir = self::styles_path();
- $iterator = new DirectoryIterator($styles_dir);
- foreach ($iterator as $fileinfo)
- {
- if ($fileinfo->isDir() && self::check_style_path($fileinfo->getFilename()))
- {
- self::$mobile_style_path = $fileinfo->getFilename();
- return self::$mobile_style_path;
- }
- }
- return false;
- }
-
- /**
- * Create HTML code for mobile style link
- *
- * @param template $template Template class instance
- * @param string $mode Mode to add to URL
- * @param string $lang Language variable for link text
- *
- * @return string HTML code for link
- */
- protected static function create_link($template, $mode, $lang)
- {
- global $user;
- $text = '';
- $lang_key = 'MOBILE_STYLE_' . strtoupper($lang);
- switch ($lang)
- {
- case 'switch_full':
- $text = isset($user->lang[$lang_key]) ? $user->lang[$lang_key] : 'Switch to full style';
- break;
- case 'switch_mobile':
- $text = isset($user->lang[$lang_key]) ? $user->lang[$lang_key] : 'Switch to mobile style';
- break;
- case 'not_found':
- $text = isset($user->lang[$lang_key]) ? $user->lang[$lang_key] : 'Error locating mobile style files';
- break;
-
- default:
- return '';
- }
- $link = $template->_rootref['U_INDEX'];
- if (!empty($template->_rootref['U_VIEW_TOPIC']))
- {
- $link = $template->_rootref['U_VIEW_TOPIC'];
- }
- elseif (!empty($template->_tpldata['navlinks']) && isset($template->_tpldata['navlinks'][count($template->_tpldata['navlinks']) - 1]['U_VIEW_FORUM']))
- {
- $link = $template->_tpldata['navlinks'][count($template->_tpldata['navlinks']) - 1]['U_VIEW_FORUM'];
- }
- $link .= (strpos($link, '?') === false ? '?' : '&') . self::$mobile_var . '=' . $mode;
- return '<a href="' . $link . '">' . $text . '</a>';
- }
-
- /**
- * Add data to overall_footer.html
- *
- * @param mobile_template $template Template class instance
- *
- * @return string Empty string
- */
- public static function template_footer($template)
- {
- if (defined('MOBILE_STYLE') && self::$is_bot)
- {
- return '';
- }
- $link = '';
- switch (self::$mobile_mode)
- {
- case '404':
- $link = self::create_link($template, 'mobile', 'not_found');
- break;
-
- case 'mobile':
- $link = self::create_link($template, 'desktop', 'switch_full');
- break;
-
- case 'desktop':
- $link = self::create_link($template, 'mobile', 'switch_mobile');
- break;
-
- case '':
- if (!defined('MOBILE_STYLE') && (self::$always_show_link || !self::$is_desktop))
- {
- // Detected desktop style
- $link = self::create_link($template, 'mobile', 'switch_mobile');
- }
- elseif (defined('MOBILE_STYLE'))
- {
- // Detected mobile style
- $link = self::create_link($template, 'desktop', 'switch_full');
- }
- break;
- }
- if (strlen($link))
- {
- echo '<div class="mobile-style-switch mobile-style-switch-footer" style="padding: 5px; text-align: center;">' . $link . '</div>';
- }
- return '';
- }
- /**
- * Add data to overall_header.html
- *
- * @param mobile_template $template Template class instance
- *
- * @return string HTML code to echo after overall_header.html
- */
- public static function template_header($template)
- {
- if (defined('MOBILE_STYLE') && self::$is_bot)
- {
- return '';
- }
- $link = '';
- switch (self::$mobile_mode)
- {
- case 'mobile':
- if (isset($_GET[self::$mobile_var]))
- {
- // Show link below header only if style was just switched
- $link = self::create_link($template, 'desktop', 'switch_full');
- }
- break;
-
- case 'desktop':
- if (isset($_GET[self::$mobile_var]))
- {
- // Show link below header only if style was just switched
- $link = self::create_link($template, 'mobile', 'switch_mobile');
- }
- break;
-
- case '':
- self::include_js($template);
- if (defined('MOBILE_STYLE') && !isset($_COOKIE[self::$cookie_var]))
- {
- // Detected mobile style
- $link = self::create_link($template, 'desktop', 'switch_full');
- }
- break;
- }
- if (strlen($link))
- {
- return '<div class="mobile-style-switch mobile-style-switch-header" style="padding: 5px; text-align: center;">' . $link . '</div>';
- }
- return '';
- }
-
- /**
- * Attempt to include detect.js from mobile style
- *
- * @param mobile_template $template Template class instance
- */
- protected static function include_js($template)
- {
- if (defined('MOBILE_STYLE') && self::$is_bot)
- {
- return;
- }
- if (count($_POST) || isset($_GET[self::$mobile_var]))
- {
- // Do not redirect on forms or when URL has mode
- return;
- }
-
- // Locate mobile style
- if (self::locate_mobile_style(false, false) === false)
- {
- return;
- }
-
- $script = self::styles_path(true) . '/template/detect.js';
- if (!@file_exists($script))
- {
- return;
- }
- $template->_rootref['META'] = (isset($template->_rootref['META']) ? $template->_rootref['META'] : '') . '<script type="text/javascript"> var phpBBMobileStyle = ' . (defined('MOBILE_STYLE') ? 'true' : 'false') . ', phpBBMobileVar = \'' . addslashes(self::$mobile_var) . '\'; </script><script type="text/javascript" src="' . htmlspecialchars($script) . '?t=' . @filemtime($script) . '"></script>';
- }
- }
- /**
- * Extend template class to override _tpl_include()
- */
- class mobile_template extends template
- {
- /**
- * Override _tpl_include function
- */
- function _tpl_include($filename, $include = true)
- {
- if ($include)
- {
- $to_echo = '';
- if ($filename == 'overall_footer.html')
- {
- $to_echo = phpbb_mobile::template_footer($this);
- }
- if ($filename == 'overall_header.html')
- {
- $to_echo = phpbb_mobile::template_header($this);
- }
- }
- parent::_tpl_include($filename, $include);
- if ($include)
- {
- echo $to_echo;
- }
- }
-
- /**
- * Clone template class properties
- *
- * @param template $template Template class instance to copy from
- */
- public function clone_properties($template)
- {
- foreach (array_keys(get_class_vars(get_class($this))) as $var)
- {
- $this->$var = $template->$var;
- }
- }
- }