Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
95.65% |
22 / 23 |
|
75.00% |
3 / 4 |
CRAP | |
0.00% |
0 / 1 |
WMFBaseDomainExtractor | |
95.65% |
22 / 23 |
|
75.00% |
3 / 4 |
11 | |
0.00% |
0 / 1 |
getCookieDomain | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
4 | |||
matchBaseHostname | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
4 | |||
extractSubdomain | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
endsWith | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
2.06 |
1 | <?php |
2 | |
3 | namespace MobileFrontend; |
4 | |
5 | /** |
6 | * Utility class to find base domain for given host. |
7 | * |
8 | * This class contains a hardcoded list of all WMF hosts and WMF specific domain logic. As we never |
9 | * experienced any bug requests from users and we do not change domains too often there is no need |
10 | * to put that hosts list into settings. |
11 | * |
12 | * @see T148975 |
13 | */ |
14 | class WMFBaseDomainExtractor implements BaseDomainExtractorInterface { |
15 | /** |
16 | * @var string[] |
17 | */ |
18 | private $wmfWikiHosts = [ |
19 | 'wikipedia.org', |
20 | 'wikibooks.org', |
21 | 'wikiversity.org', |
22 | 'wikinews.org', |
23 | 'wiktionary.org', |
24 | 'wikisource.org', |
25 | 'wikiquote.org', |
26 | 'wikivoyage.org', |
27 | 'wikidata.org', |
28 | 'mediawiki.org', |
29 | // local vagrant instances |
30 | 'local.wmftest.net' |
31 | ]; |
32 | /** |
33 | * @var string[] |
34 | */ |
35 | private $wmfMultiDomainWikiHosts = [ |
36 | // commons, office, meta, outreach, wikimania, incubator, etc... |
37 | '.wikimedia.org', |
38 | // beta cluster |
39 | '.beta.wmflabs.org', |
40 | // all other labs |
41 | '.wmflabs.org' |
42 | ]; |
43 | |
44 | /** |
45 | * Although some browsers will accept cookies without the initial . in domain |
46 | * RFC 2109 requires it to be included. |
47 | * |
48 | * $server must be a valid URL (i.e. with the scheme included, http or https |
49 | * or protocol-relative e.g. //en.m.wikipedia.org'). NULL and empty strings |
50 | * can also be taken but will return NULL or empty string respectively. |
51 | * |
52 | * @inheritDoc |
53 | */ |
54 | public function getCookieDomain( $server ) { |
55 | // Per http://php.net/manual/en/function.parse-url.php, |
56 | // If the requested component doesn't exist within the given |
57 | // URL, NULL will be returned. So wfParseUrl() will return |
58 | // false as it calls parse_url() if a valid server URL is not |
59 | // given except it's an empty string. |
60 | $parsedUrl = wfParseUrl( $server ); |
61 | $host = $parsedUrl !== false ? $parsedUrl['host'] : null; |
62 | |
63 | $wikiHost = $this->matchBaseHostname( $host, $this->wmfWikiHosts ); |
64 | if ( $wikiHost !== false ) { |
65 | return '.' . $wikiHost; |
66 | } |
67 | |
68 | $multiWikiHost = $this->matchBaseHostname( $host, $this->wmfMultiDomainWikiHosts ); |
69 | if ( $multiWikiHost !== false ) { |
70 | return '.' . $this->extractSubdomain( $host, $multiWikiHost ); |
71 | } |
72 | return $host; |
73 | } |
74 | |
75 | /** |
76 | * Find out whether $hostname matches or is subdomain of any host from $hosts array |
77 | * |
78 | * @param string|null $hostname Visited host |
79 | * @param string[] $hosts Array of all wikimedia hosts |
80 | * @return bool|string Returns wikimedia host base domain, false when not found |
81 | */ |
82 | private function matchBaseHostname( $hostname, array $hosts ) { |
83 | if ( $hostname === null ) { |
84 | return false; |
85 | } |
86 | foreach ( $hosts as $wmfHost ) { |
87 | if ( $this->endsWith( $hostname, $wmfHost ) ) { |
88 | return $wmfHost; |
89 | } |
90 | } |
91 | return false; |
92 | } |
93 | |
94 | /** |
95 | * Parse $host and return $baseDomain with first subdomain |
96 | * ex: extractSubdomain('en.commons.wikimedia.org', '.wikimedia.org') => 'commons.wikimedia.org' |
97 | * |
98 | * This function assumes that $fullHostname is a subdomain of $baseDomain. Please |
99 | * do the endsWith() check first before calling this function |
100 | * |
101 | * @param string $fullHostname |
102 | * @param string $baseDomain |
103 | * @return string |
104 | */ |
105 | private function extractSubdomain( $fullHostname, $baseDomain ) { |
106 | $length = strlen( $baseDomain ); |
107 | |
108 | $subdomains = explode( '.', substr( $fullHostname, 0, -$length ) ); |
109 | $subdomain = array_pop( $subdomains ); |
110 | return $subdomain . $baseDomain; |
111 | } |
112 | |
113 | /** |
114 | * Check that $haystack ends with $needle. When $needle is |
115 | * empty, it should return false. |
116 | * |
117 | * @param string $haystack |
118 | * @param string $needle |
119 | * @return bool |
120 | */ |
121 | private function endsWith( $haystack, $needle ) { |
122 | $length = strlen( $needle ); |
123 | if ( $length === 0 ) { |
124 | return true; |
125 | } |
126 | return substr( $haystack, -$length ) === $needle; |
127 | } |
128 | } |