diff --git a/lib/classes/useragent.php b/lib/classes/useragent.php index a2c4dbafb44..2817f1ae31d 100644 --- a/lib/classes/useragent.php +++ b/lib/classes/useragent.php @@ -808,6 +808,25 @@ class core_useragent { return false; } + /** + * Checks if the user agent is MS Word. + * Not perfect, as older versions of Word use standard IE6/7 user agents without any identifying traits. + * + * @return bool true if user agent could be identified as MS Word. + */ + public static function is_msword() { + $useragent = self::get_user_agent_string(); + if (!preg_match('/(\bWord\b|ms-office|MSOffice|Microsoft Office)/i', $useragent)) { + return false; + } else if (strpos($useragent, 'Outlook') !== false) { + return false; + } else if (strpos($useragent, 'Meridio') !== false) { + return false; + } + // It's Office, not Outlook and not Meridio - so it's probably Word, but we can't really be sure in most cases. + return true; + } + /** * Check if the user agent matches a given brand. * diff --git a/lib/tests/useragent_test.php b/lib/tests/useragent_test.php index 530f1d90061..770012d3d97 100644 --- a/lib/tests/useragent_test.php +++ b/lib/tests/useragent_test.php @@ -49,6 +49,9 @@ class core_useragent_testcase extends basic_testcase { '7.0' => array( 'Windows XP SP2' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)' ), + '7.0b' => array( + 'Windows XP' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Meridio for Excel 5.0.251; Meridio for PowerPoint 5.0.251; Meridio for Word 5.0.251; Meridio Protocol; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)' + ), '8.0' => array( 'Windows Vista' => 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648)' ), @@ -156,6 +159,22 @@ class core_useragent_testcase extends basic_testcase { 'Windows XP' => 'Opera/9.0 (Windows NT 5.1; U; en)', 'Debian Linux' => 'Opera/9.01 (X11; Linux i686; U; en)' ) + ), + 'MS Word' => array( + '2010' => array( + 'Windows 7' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; ms-office)', + 'Mac OS X' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X) Word/14.38.0' + ) + ), + 'MS Outlook' => array( + '2010' => array( + 'Windows 7' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; Microsoft Outlook 14.0.7113; ms-office; MSOffice 14)' + ) + ), + 'Meridio' => array( + '5.0.251' => array( + 'Windows XP' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Meridio for Excel 5.0.251; Meridio for PowerPoint 5.0.251; Meridio for Word 5.0.251; Meridio Protocol; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)' + ) ) ); @@ -183,6 +202,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertFalse(core_useragent::check_chrome_version()); $this->assertFalse(core_useragent::is_safari_ios()); $this->assertFalse(core_useragent::check_safari_ios_version()); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['Safari iOS']['528']['iPhone']); $this->assertTrue(core_useragent::is_safari_ios()); @@ -195,6 +215,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertFalse(core_useragent::check_safari_version('500')); $this->assertFalse(core_useragent::is_chrome()); $this->assertFalse(core_useragent::check_chrome_version()); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['WebKit Android']['530']['Nexus']); $this->assertTrue(core_useragent::is_webkit()); @@ -205,6 +226,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertFalse(core_useragent::check_safari_version()); $this->assertFalse(core_useragent::is_chrome()); $this->assertFalse(core_useragent::check_chrome_version()); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['WebKit Android']['537']['Samsung GT-9505']); $this->assertTrue(core_useragent::is_webkit()); @@ -234,12 +256,14 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_chrome_version(8)); $this->assertFalse(core_useragent::check_chrome_version(10)); $this->assertFalse(core_useragent::check_safari_version('1')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['Opera']['9.0']['Windows XP']); $this->assertTrue(core_useragent::is_opera()); $this->assertTrue(core_useragent::check_opera_version()); $this->assertTrue(core_useragent::check_opera_version('8.0')); $this->assertFalse(core_useragent::check_opera_version('10.0')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['MSIE']['6.0']['Windows XP SP2']); $this->assertTrue(core_useragent::is_ie()); @@ -247,6 +271,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_ie_version('5.0')); $this->assertFalse(core_useragent::check_ie_compatibility_view()); $this->assertFalse(core_useragent::check_ie_version('7.0')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['MSIE']['5.0']['Windows 98']); $this->assertFalse(core_useragent::is_ie()); @@ -255,6 +280,23 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_ie_version('5.0')); $this->assertFalse(core_useragent::check_ie_compatibility_view()); $this->assertFalse(core_useragent::check_ie_version('7.0')); + $this->assertFalse(core_useragent::is_msword()); + + core_useragent::instance(true, $this->user_agents['MSIE']['7.0']['Windows XP SP2']); + $this->assertTrue(core_useragent::is_ie()); + $this->assertTrue(core_useragent::check_ie_version()); + $this->assertTrue(core_useragent::check_ie_version('7.0')); + $this->assertFalse(core_useragent::check_ie_compatibility_view()); + $this->assertFalse(core_useragent::check_ie_version('8.0')); + $this->assertFalse(core_useragent::is_msword()); + + core_useragent::instance(true, $this->user_agents['MSIE']['7.0b']['Windows XP']); + $this->assertTrue(core_useragent::is_ie()); + $this->assertTrue(core_useragent::check_ie_version()); + $this->assertTrue(core_useragent::check_ie_version('7.0')); + $this->assertFalse(core_useragent::check_ie_compatibility_view()); + $this->assertFalse(core_useragent::check_ie_version('8.0')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['MSIE']['9.0']['Windows 7']); $this->assertTrue(core_useragent::is_ie()); @@ -264,6 +306,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_ie_version('9.0')); $this->assertFalse(core_useragent::check_ie_compatibility_view()); $this->assertFalse(core_useragent::check_ie_version('10')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['MSIE']['9.0i']['Windows 7']); $this->assertTrue(core_useragent::is_ie()); @@ -273,6 +316,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_ie_version('9.0')); $this->assertTrue(core_useragent::check_ie_compatibility_view()); $this->assertFalse(core_useragent::check_ie_version('10')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['MSIE']['10.0']['Windows 8']); $this->assertTrue(core_useragent::is_ie()); @@ -283,6 +327,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_ie_version('10')); $this->assertFalse(core_useragent::check_ie_compatibility_view()); $this->assertFalse(core_useragent::check_ie_version('11')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['MSIE']['10.0i']['Windows 8']); $this->assertTrue(core_useragent::is_ie()); @@ -293,6 +338,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_ie_version('10')); $this->assertTrue(core_useragent::check_ie_compatibility_view()); $this->assertFalse(core_useragent::check_ie_version('11')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['MSIE']['11.0']['Windows 8.1']); $this->assertTrue(core_useragent::is_ie()); @@ -304,6 +350,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_ie_version('11')); $this->assertFalse(core_useragent::check_ie_compatibility_view()); $this->assertFalse(core_useragent::check_ie_version('12')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['MSIE']['11.0i']['Windows 8.1']); $this->assertTrue(core_useragent::is_ie()); @@ -315,6 +362,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_ie_version('11')); $this->assertTrue(core_useragent::check_ie_compatibility_view()); $this->assertFalse(core_useragent::check_ie_version('12')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['Firefox']['2.0']['Windows XP']); $this->assertTrue(core_useragent::is_firefox()); @@ -325,6 +373,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_gecko_version(20030516)); $this->assertTrue(core_useragent::check_gecko_version(20051106)); $this->assertTrue(core_useragent::check_gecko_version(2006010100)); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['Firefox']['1.0.6']['Windows XP']); $this->assertTrue(core_useragent::is_firefox()); @@ -336,6 +385,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertFalse(core_useragent::check_firefox_version('1.5')); $this->assertFalse(core_useragent::check_firefox_version('3.0')); $this->assertFalse(core_useragent::check_gecko_version('2')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['Firefox']['2.0']['Windows XP']); $this->assertTrue(core_useragent::is_firefox()); @@ -347,6 +397,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_gecko_version(20051106)); $this->assertTrue(core_useragent::check_gecko_version(2006010100)); $this->assertFalse(core_useragent::check_firefox_version('3.0')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['Firefox']['3.6']['Linux']); $this->assertTrue(core_useragent::is_firefox()); @@ -360,6 +411,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_gecko_version(2006010100)); $this->assertFalse(core_useragent::check_firefox_version('4')); $this->assertFalse(core_useragent::check_firefox_version('10')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['Firefox']['3.6']['Linux']); $this->assertTrue(core_useragent::is_firefox()); @@ -375,6 +427,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertFalse(core_useragent::check_firefox_version('10')); $this->assertFalse(core_useragent::check_firefox_version('18')); $this->assertFalse(core_useragent::check_gecko_version('4')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['Firefox']['15.0a2']['Windows']); $this->assertTrue(core_useragent::is_firefox()); @@ -392,6 +445,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_firefox_version('15')); $this->assertFalse(core_useragent::check_firefox_version('18')); $this->assertFalse(core_useragent::check_gecko_version('18')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['Firefox']['18.0']['Mac OS X']); $this->assertTrue(core_useragent::is_firefox()); @@ -411,6 +465,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_firefox_version('18')); $this->assertFalse(core_useragent::check_firefox_version('19')); $this->assertFalse(core_useragent::check_gecko_version('19')); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['SeaMonkey']['2.0']['Windows']); $this->assertTrue(core_useragent::check_gecko_version('2')); @@ -421,6 +476,7 @@ class core_useragent_testcase extends basic_testcase { $this->assertFalse(core_useragent::check_gecko_version('4.0')); $this->assertFalse(core_useragent::is_firefox()); $this->assertFalse(core_useragent::check_firefox_version()); + $this->assertFalse(core_useragent::is_msword()); core_useragent::instance(true, $this->user_agents['SeaMonkey']['2.1']['Linux']); $this->assertTrue(core_useragent::check_gecko_version('2')); @@ -434,7 +490,22 @@ class core_useragent_testcase extends basic_testcase { $this->assertTrue(core_useragent::check_firefox_version(4.0)); $this->assertFalse(core_useragent::check_firefox_version(5)); $this->assertFalse(core_useragent::check_gecko_version('18.0')); + $this->assertFalse(core_useragent::is_msword()); + // We're not really interested in what MS Word gets identified as beyond MS Word itself. + core_useragent::instance(true, $this->user_agents['MS Word']['2010']['Windows 7']); + $this->assertTrue(core_useragent::is_msword()); + + core_useragent::instance(true, $this->user_agents['MS Word']['2010']['Mac OS X']); + $this->assertTrue(core_useragent::is_msword()); + + // Outlook should not be considered to be MS Word. + core_useragent::instance(true, $this->user_agents['MS Outlook']['2010']['Windows 7']); + $this->assertFalse(core_useragent::is_msword()); + + // Meridio should not be considered to be MS Word. + core_useragent::instance(true, $this->user_agents['Meridio']['5.0.251']['Windows XP']); + $this->assertFalse(core_useragent::is_msword()); } /** @@ -442,8 +513,6 @@ class core_useragent_testcase extends basic_testcase { * works as expected. */ public function test_supports_svg() { - $this->assertTrue(core_useragent::supports_svg()); - // MSIE 5.0 is not considered a browser at all: known false positive. core_useragent::instance(true, $this->user_agents['MSIE']['5.0']['Windows 98']); $this->assertTrue(core_useragent::supports_svg()); diff --git a/lib/weblib.php b/lib/weblib.php index c843fa2e2b3..8fb28a643a0 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -2551,6 +2551,16 @@ function redirect($url, $message='', $delay=-1) { break; } + if (core_useragent::is_msword()) { + // Clicking a URL from MS Word sends a request to the server without cookies. If that + // causes a redirect Word will open a browser pointing the new URL. If not, the URL that + // was clicked is opened. Because the request from Word is without cookies, it almost + // always results in a redirect to the login page, even if the user is logged in in their + // browser. This is not what we want, so prevent the redirect for requests from Word. + $debugdisableredirect = true; + break; + } + if (empty($CFG->debugdisplay) or empty($CFG->debug)) { // No errors should be displayed. break;