1<?php
2/**
3 @file       nobadbrowser/action.php
4 @brief      Warn users of bad browsers.
5 @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 @author     Luis Machuca Bezzaza <lambalicious [at] tuta [dot] io>
7**/
8// must be run within Dokuwiki
9if(!defined('DOKU_INC')) die();
10if(!defined('DW_LF')) define('DW_LF',"\n");
11
12if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
13define('THIS_PLUGIN', DOKU_PLUGIN.'nobadbrowser/');
14require_once(DOKU_PLUGIN.'action.php');
15require_once(DOKU_INC.'inc/confutils.php');
16require_once(DOKU_INC.'inc/infoutils.php'); // for notify facilities
17
18/**
19 * All DokuWiki plugins to extend the admin function
20 * need to inherit from this class
21 */
22class action_plugin_nobadbrowser extends DokuWiki_Action_Plugin {
23
24	// detected browser info
25	var $binfo = array();
26	// the plugin's data object
27	var $cnf= array();
28
29	function action_plugin_nobadbrowser () {
30		//global $ID;
31		//global $ACT;
32		global $bid;
33		$this->cnf= array();
34		$this->binfo= [];
35		if (!extension_loaded('browscap')) {
36			$this->binfo= $this->get_browser_local($_SERVER['HTTP_USER_AGENT']);
37			$this->binfo['browscap']= false;
38			msg(<<<EOF
39nobadbrowser notice: This PHP installation seems to lack ''browscap'' support. Results may be inconclusive.
40EOF
41, 2);
42		} else {
43			$this->binfo= get_browser(null, true);
44			$this->binfo['browscap']= true;
45		}
46		$this->binfo['_UA']= $_SERVER['HTTP_USER_AGENT'];
47		//msg(print_r($this->binfo, true), 1); // FOR DEBUG
48	}
49
50	/***
51	 * Register its handlers with the DokuWiki's event controller
52	 */
53	function register (Doku_Event_Handler $controller) {
54		global $ACT;
55		if ($ACT != 'show') return;
56		$controller->register_hook('TPL_CONTENT_DISPLAY','BEFORE', $this, 'warning',array());
57	}
58
59
60/*
61  rendering options (from getConf)
62  notify       -> use the DokuWiki notification message area
63  splash       -> use a JS+CSS splash screen (not available in this release)
64*/
65	function warning (Doku_Event $event, $param) {
66		global $ACT;
67		static $done= false;
68
69		if ($ACT!='show') {
70			return;
71		}
72		if ($this->getConf['debug']) {
73			$this->render_debug($event, $param);
74		}
75
76		if ($this->whybadbrowser()) {
77			$parameter= $this->cnf['parameter'];
78			$reason= $this->cnf['reason'];
79			$see= $this->cnf['see'];
80			$mens = <<<EOF
81You seem to be using a bad browser. \\\\
82You are at risk because __${parameter}__ is: __${reason}__.
83Visit [[${see}|nobadbrowser @ DokuWiki]] for more details.
84EOF;
85			$outp= p_render('xhtml', p_get_instructions($mens), $info);
86			msg(($outp), -1);
87		}
88    // end function
89    }
90
91
92/**
93 *******************************************************************
94 * Helper Functions
95 */
96
97
98	function whybadbrowser () {
99		if (preg_match('/\bIE/', $this->binfo['browser']) && intval($this->binfo['version'])< 10 ) {
100			$this->cnf= array(
101				'parameter' => 'Browser old age',
102				'reason' => $this->binfo['browser'] . " " . $this->binfo['version'] ,
103				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#internet_explorer'
104			);
105			return true;
106		}
107		if (preg_match('/\b(Chrome)/', $this->binfo['browser'])) {
108			$this->cnf= array(
109				'reason' => $this->binfo['browser'] ,
110				'parameter' => 'Browser',
111				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#google_chrome'
112			);
113			return true;
114		}
115		if (preg_match('/.*Google.*/', $this->binfo['renderingengine_maker']) || $this->binfo['renderingengine_name'] === 'Blink') {
116			$this->cnf= array(
117				'reason' => 'Chrome reskin' ,
118				'parameter' => 'Browser type',
119				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#google_chrome'
120			);
121			return true;
122		}
123		if (preg_match('/^Google.*/', $this->binfo['browser_maker'])) {
124			$this->cnf= array(
125				'reason' => $this->binfo['browser_maker'] ,
126				'parameter' => 'Browser creator',
127				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#google_chrome'
128			);
129			return true;
130		}
131		if (preg_match('/^Opera/', $this->binfo['browser']) && intval($this->binfo['version'])>12 ) {
132			$this->cnf= [
133				'reason' => $this->binfo['browser'] . " " . $this->binfo['version'],
134				'parameter' => 'Browser version is a Chrome reskin',
135				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#opera'
136			];
137			return true;
138		}
139		if (preg_match('/^Safari/', $this->binfo['browser']) || preg_match('/^Apple/', $this->binfo['browser_maker']) ) {
140			$this->cnf= [
141				'reason' => $this->binfo['browser_maker'] ,
142				'parameter' => 'Browser Ecosystem',
143				'see' => 'https://www.dokuwiki.org/plugin:nobadbrowser#apple'
144			];
145			return true;
146		}
147		return false;
148	}
149
150	/**
151	 * This function is an alternative to get_browser when not available.
152	 * 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 :
153	 * * browser
154	 * * version
155	 * * browser_maker
156	 * * renderingengine_name
157	 * * renderingengine_maker
158	 *
159	 * Other keys that can also be of interest:
160	 *
161	 * * renderingengine_version
162	 * * parent
163	 *
164	 * */
165	function get_browser_local ($user_agent, $return_array=true) {
166		$ret= [];
167		// Internet Explorer
168		if (strpos($user_agent, 'MSIE') !== false) {
169			$ret['browser']= 'IE';
170			$ret['browser_maker']= 'Microsoft Corporation';
171			if (preg_match ('#MSIE ([0-9\.]+);#', $user_agent, $browserversion) ) {
172				$ret['version']= $browserversion[1];
173				$ver= explode('.', $browserversion[1], 3);
174				list($ret['majorver'], $ret['minorver'])= $ver;
175				$ret['parent']= $ret['browser']. ' ' . $ret['majorver'];
176			}
177			$ret['renderingengine_name']= 'Trident';
178			$ret['renderingengine_maker']= 'Microsoft Corporation';
179			if (preg_match ('#Trident/([0-9\.]+)#', $user_agent, $rendererversion) ) {
180				$ret['renderingengine_version']= $rendererversion[1];
181			}
182		}
183		// Google Chrome and its various derivations
184		if (preg_match_all(
185		'#AppleWebKit/[0-9\.]+.*\(.*KHTML.*like.*Gecko.*\) Chrome/([0-9]+\.[0-9]+).+Safari/[0-9\.]+\b(.*)$#'
186		, $user_agent, $chrome_info) ) {
187			$ret['browser']= 'Chrome';
188			$ret['browser_maker']= 'Google Inc';
189			$ret['version']= $chrome_info[1][0];
190			$ret['parent']= 'Chrome';
191			$ret['variants']= $chrome_info[2];
192			$variants= trim($chrome_info[2]);
193			$variants= explode(' ', $variants);
194			//$ret['variant_match']= $chrome_info[2][0];
195			if (count($variants) > 0 && (isset($variants[0]) ) && ($variants[0] != '') ) {
196				//$ret['variant']= 1;
197				$variant= explode('/', $variants[0]);
198				$variantname= trim($variant[0]);
199				$variantmaker= $ret['browser_maker'];
200				if ($variantname=='Edg') { $variantname= 'Edge'; }
201				else if ($variantname=='OPR') { $variantname= 'Opera'; $variantmaker= 'Opera Software ASA'; }
202				$variantversion= explode('.', $variant[1],3);
203				$variantversion= $variantversion[0].'.'.$variantversion[1];
204				$ret['variant_found']= [ $variantname, $variantversion];
205				$ret['browser']= $variantname;
206				$ret['version']= $variantversion;
207				$ret['browser_maker']= $variantmaker;
208			}
209			//list($ret['majorver'], $ret['minorver'])= explode('.', $chrome_info[1],3);
210			$ret['renderingengine_name']= 'Blink';
211			$ret['renderingengine_maker']= 'Google Inc';
212			$ret['renderingengine_version']= '';
213		}
214		// Safari
215		if (preg_match_all(
216		'#AppleWebKit/[0-9\.]+.*\(.*KHTML.*like.*Gecko.*\) Version/([0-9]+\.[0-9]+).*Safari/([0-9]+\.[0-9]+).*#'
217		, $user_agent, $safari_info) ) {
218			$ret['browser']= 'Safari';
219			$ret['browser_maker']= 'Apple Inc';
220			$ret['version']= $safari_info[1][0];
221			$ret['renderingengine_name']= 'WebKit';
222			$ret['renderingengine_maker']= 'Apple Inc';
223			$ret['renderingengine_version']= '';
224		}
225		// Firefox and its variants
226		if (preg_match_all(
227		'#^Mozilla/[0-9\.]+.*Gecko/[0-9]+.+Firefox/([0-9]+\.[0-9]+).*$#'
228		, $user_agent, $firefox_info) ) {
229			$ret['browser']= 'Firefox';
230			$ret['browser_maker']= 'Mozilla Foundation';
231			$ret['version']= $firefox_info[1][0];
232			$rendererversion= $ret['version'];
233			$ret['renderingengine_name']= 'Gecko';
234			$ret['renderingengine_maker']= 'Mozilla Foundation';
235			$ret['renderingengine_version']= $rendererversion;
236		}
237		return $ret;
238	}
239
240	function render_debug (Doku_Event $event, $param) {
241		$arr= array(
242			'browser' => $this->binfo['browser'] ,
243			'browser_maker' => $this->binfo['browser_maker'] ,
244			);
245		$x = print_r($this->binfo, true);
246		$out= '<pre>'.  htmlspecialchars($x). '</pre>';
247		msg($out,-1);
248	}
249
250}
251