1<?php 2/** 3 @file nobadbrowser/action.php 4 @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 5 @author Luis Machuca Bezzaza <lambalicious [at] tuta [dot] io> 6**/ 7// must be run within Dokuwiki 8if(!defined('DOKU_INC')) die(); 9if(!defined('DW_LF')) define('DW_LF',"\n"); 10 11if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 12define('THIS_PLUGIN', DOKU_PLUGIN.'nobadbrowser/'); 13require_once(DOKU_PLUGIN.'action.php'); 14require_once(DOKU_INC.'inc/confutils.php'); 15require_once(DOKU_INC.'inc/infoutils.php'); // for notify facilities 16 17/** 18 * All DokuWiki plugins to extend the admin function 19 * need to inherit from this class 20 */ 21class action_plugin_nobadbrowser extends DokuWiki_Action_Plugin { 22 23 // detected browser info 24 var $binfo = array(); 25 // the plugin's data object 26 var $cnf= array(); 27 28 function action_plugin_nobadbrowser () { 29 //global $ID; 30 //global $ACT; 31 global $bid; 32 $this->cnf= array(); 33 $this->binfo= []; 34 } 35 36 /*** 37 * Register its handlers with the DokuWiki's event controller 38 */ 39 function register (Doku_Event_Handler $controller) { 40 global $ACT; 41 if ($ACT != 'show') return; 42 $controller->register_hook('TPL_CONTENT_DISPLAY','BEFORE', $this, 'warning',array()); 43 } 44 45 46/* 47 rendering options (from getConf) 48 notify -> use the DokuWiki notification message area 49 splash -> use a JS+CSS splash screen (not available in this release) 50*/ 51 function warning (Doku_Event $event, $param) { 52 global $ACT; 53 static $done= false; 54 55 if ($ACT!='show') { 56 return; 57 } 58 59 $bc= extension_loaded('browscap'); 60 $with= $this->getConf('with_browscap'); 61 62 if ( $bc == false && $this->getConf('debug') == true ) { 63 msg(<<<EOF 64nobadbrowser notice: This PHP installation seems to lack ''browscap'' support. Results may be inconclusive. 65EOF 66, 2); 67 } 68 69 if ( $bc == true && $with == true ) { 70 $this->binfo= get_browser(null, true); 71 } else { 72 $this->binfo= $this->get_browser_local($_SERVER['HTTP_USER_AGENT']); 73 $this->binfo['browscap']= false; 74 } 75 $this->binfo['browscap']= $bc; 76 $this->binfo['with']= $with; 77 $this->binfo['_UA']= $_SERVER['HTTP_USER_AGENT']; 78 79 80 if ($this->getConf['debug'] ?? false) { 81 $this->render_debug($event, $param); 82 } 83 84 if ($this->whybadbrowser()) { 85 $parameter= $this->cnf['parameter']; 86 $reason= $this->cnf['reason']; 87 $see= $this->cnf['see']; 88 $mens = <<<EOF 89You seem to be using a bad browser. \\\\ 90You are at risk because __${parameter}__ is: __${reason}__. 91Visit [[${see}|nobadbrowser @ DokuWiki]] for more details. 92EOF; 93 $outp= p_render('xhtml', p_get_instructions($mens), $info); 94 msg(($outp), -1); 95 } 96 // end function 97 } 98 99 100/** 101 ******************************************************************* 102 * Helper Functions 103 */ 104 105 106 function whybadbrowser () { 107 108 // minimum and maximum acceptable versions, in format MAJOR*100+MINOR 109 $minmaxversions= [ 110 'Edge' => [null, null], 111 'Internet Explorer' => [800, 900], 112 'Opera' => [1000, 1264], 113 'Chrome' => [null, null], 114 'Firefox' => [3800, 15000], 115 'SeaMonkey' => [249, 300], 116 'PaleMoon' => [2500, 3000], 117 'Safari' => [null, null] 118 ]; 119 120 // Match Internet Explorer 121 if (preg_match('/\bIE/', $this->binfo['browser']) && intval($this->binfo['version'])< 10 ) { 122 $this->cnf= array( 123 'parameter' => 'Browser old age', 124 'reason' => $this->binfo['browser'] . " " . $this->binfo['version'] , 125 'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#internet_explorer' 126 ); 127 return true; 128 } 129 // ... or browsers made by Microsoft (incl. Edge) 130 if (preg_match('/^Microsoft.*/', $this->binfo['browser_maker'])) { 131 $this->cnf= array( 132 'reason' => $this->binfo['browser_maker'] , 133 'parameter' => 'Browser Ecosystem', 134 'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#internet_explorer' 135 ); 136 return true; 137 } 138 // Match Opera post-Presto 139 if (preg_match('/^Opera/', $this->binfo['browser']) && intval($this->binfo['version'])>12 ) { 140 $this->cnf= [ 141 'reason' => $this->binfo['browser'] . " " . $this->binfo['version'], 142 'parameter' => 'Browser is a Chrome reskin', 143 'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#opera' 144 ]; 145 return true; 146 } 147 // Match Google Chrome 148 if (preg_match('/\bChrome/', $this->binfo['browser'])) { 149 $this->cnf= array( 150 'reason' => $this->binfo['browser'] , 151 'parameter' => 'Browser', 152 'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#google_chrome' 153 ); 154 return true; 155 } 156 // ... or browsers made by Google (incl. Android WebView) 157 if (preg_match('/^Google.*/', $this->binfo['browser_maker'])) { 158 $this->cnf= array( 159 'reason' => $this->binfo['browser_maker'] , 160 'parameter' => 'Browser Ecosystem', 161 'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#google_chrome' 162 ); 163 return true; 164 } 165 // ...or Chrome reskins 166 if (preg_match('/\bChrome/', $this->binfo['parent']) ) { 167 $this->cnf= array( 168 'reason' => $this->binfo['parent'] , 169 'parameter' => 'Browser type', 170 'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#google_chrome' 171 ); 172 return true; 173 } 174 // ...or Chrome reskins "trying to pass" 175 if (preg_match('/.*Google Inc.*/', $this->binfo['renderingengine_maker']) ) { 176 $this->cnf= array( 177 'reason' => 'Chrome reskin' , 178 'parameter' => 'Browser type', 179 'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#google_chrome' 180 ); 181 return true; 182 } 183 // match browsers made by Apple 184 if (preg_match('/^Safari/', $this->binfo['browser']) 185 || preg_match('/^Apple/', $this->binfo['browser_maker']) ) { 186 $this->cnf= [ 187 'reason' => $this->binfo['browser_maker'] , 188 'parameter' => 'Browser Ecosystem', 189 'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#apple' 190 ]; 191 return true; 192 } 193 // match browsers made by Facebook, for GAFAM completeness 194 if (preg_match('/^Facebook/', $this->binfo['browser_maker']) ) { 195 $this->cnf= [ 196 'reason' => $this->binfo['browser_maker'] , 197 'parameter' => 'Browser Ecosystem', 198 'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#facebook' 199 ]; 200 return true; 201 } 202 // match browsers made by Amazon, for GAFAM completeness 203 if (preg_match('/^Amazon/', $this->binfo['browser_maker']) ) { 204 $this->cnf= [ 205 'reason' => $this->binfo['browser_maker'] , 206 'parameter' => 'Browser Ecosystem', 207 'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#amazon' 208 ]; 209 return true; 210 } 211 return false; 212 } 213 214 /** 215 * This function is an alternative to get_browser when not available. 216 * It does some parsing of the user agent string to provide acceptable, not necessarily accurate results, focused on returning five primary keys about the browser which are to concern for nobadbrowser : 217 * * browser 218 * * version 219 * * browser_maker 220 * * renderingengine_name 221 * * renderingengine_maker 222 * 223 * Other keys that can also be of interest: 224 * 225 * * renderingengine_version 226 * * parent 227 * 228 * */ 229 function get_browser_local ($user_agent, $return_array=true) { 230 $ret= [ 'browser' => 'generic', 'browser_maker' => 'generic', 'parent' => '', 'version' => '0' ]; 231 // Internet Explorer 232 if (strpos($user_agent, 'MSIE') !== false) { 233 $ret['browser']= 'IE'; 234 $ret['browser_maker']= 'Microsoft Corporation'; 235 if (preg_match ('#MSIE ([0-9\.]+);#', $user_agent, $browserversion) ) { 236 $ret['version']= $browserversion[1]; 237 $ver= explode('.', $browserversion[1], 3); 238 list($ret['majorver'], $ret['minorver'])= $ver; 239 $ret['parent']= $ret['browser']. ' ' . $ret['majorver']; 240 } 241 $ret['renderingengine_name']= 'Trident'; 242 $ret['renderingengine_maker']= 'Microsoft Corporation'; 243 if (preg_match ('#Trident/([0-9\.]+)#', $user_agent, $rendererversion) ) { 244 $ret['renderingengine_version']= $rendererversion[1]; 245 } 246 } 247 // Google Chrome and its various derivations 248 if (preg_match_all( 249 '#AppleWebKit/[0-9\.]+.*\(.*KHTML.*like.*Gecko.*\) Chrome/([0-9]+\.[0-9]+).+Safari/[0-9\.]+\b(.*)$#' 250 , $user_agent, $chrome_info) ) { 251 $ret['browser']= 'Chrome'; 252 $ret['browser_maker']= 'Google Inc'; 253 $ret['version']= $chrome_info[1][0]; 254 $ret['parent']= 'Chrome'; 255 $variants= $chrome_info[2]; 256 //msg( print_r($variants, true), 2); 257 if (count($variants) > 0 && (isset($variants[0]) ) && ($variants[0] != '') ) { 258 //$ret['variant']= 1; 259 $variant= explode('/', $variants[0]); 260 $variantname= trim($variant[0]); 261 $variantmaker= $ret['browser_maker']; 262 if (false) { 263 } else if ($variantname=='Edg') { 264 $variantname= 'Edge'; 265 } else if ($variantname=='OPR') { 266 $variantname= 'Opera'; $variantmaker= 'Opera Software ASA'; 267 } else if ($variantname=='uacq') { 268 $variantname= 'User Agent Switcher'; 269 } 270 $variantversion= explode('.', $variant[1],3); 271 $variantversion= $variantversion[0].'.'.$variantversion[1]; 272 $ret['variant_found']= [ $variantname, $variantversion]; 273 $ret['browser']= $variantname; 274 $ret['version']= $variantversion; 275 $ret['browser_maker']= $variantmaker; 276 } 277 //list($ret['majorver'], $ret['minorver'])= explode('.', $chrome_info[1],3); 278 $ret['renderingengine_name']= 'Blink'; 279 $ret['renderingengine_maker']= 'Google Inc'; 280 $ret['renderingengine_version']= ''; 281 } 282 // Safari 283 if (preg_match_all( 284 '#AppleWebKit/[0-9\.]+.*\(.*KHTML.*like.*Gecko.*\) Version/([0-9]+\.[0-9]+).*Safari/([0-9]+\.[0-9]+).*#' 285 , $user_agent, $safari_info) ) { 286 $ret['browser']= 'Safari'; 287 $ret['browser_maker']= 'Apple Inc'; 288 $ret['version']= $safari_info[1][0]; 289 $ret['renderingengine_name']= 'WebKit'; 290 $ret['renderingengine_maker']= 'Apple Inc'; 291 $ret['renderingengine_version']= ''; 292 } 293 // TODO: Facebook Browser 294 if (preg_match_all( 295 '#AppleWebKit/[0-9\.]+.*\(.*KHTML.*like.*Gecko.*\) Version/([0-9]+\.[0-9]+).*Safari/([0-9]+\.[0-9]+).*(FBAV|FBIOS).*#' 296 , $user_agent, $facebook_info) ) { 297 $ret['browser']= 'Facebook'; 298 $ret['browser_maker']= 'Facebook'; 299 $ret['version']= $facebook_info[1][0]; 300 $ret['renderingengine_name']= 'WebKit'; 301 $ret['renderingengine_maker']= 'Apple Inc'; 302 $ret['renderingengine_version']= ''; 303 } 304 // Firefox and its variants 305 if (preg_match_all( 306 '#^Mozilla/[0-9\.]+.*Gecko/[0-9]+.+Firefox/([0-9]+\.[0-9]+).*$#' 307 , $user_agent, $firefox_info) ) { 308 $ret['browser']= 'Firefox'; 309 $ret['browser_maker']= 'Mozilla Foundation'; 310 $ret['version']= $firefox_info[1][0]; 311 $rendererversion= $ret['version']; 312 $ret['renderingengine_name']= 'Gecko'; 313 $ret['renderingengine_maker']= 'Mozilla Foundation'; 314 $ret['renderingengine_version']= $rendererversion; 315 } 316 return $ret; 317 } 318 319 function render_debug (Doku_Event $event, $param) { 320 $x= print_r($this->binfo, true); 321 msg($x,3); 322 } 323 324} 325