HTTPS-Fehler im Link Indication Plugin

Ich setze bereits seit einer Weile das Link Indication Plugin ein, das externe Links mit einem Icon ergänzt, sodass man sie besser erkennen kann. Seitdem jedoch meine und immer mehr externe Seiten HTTPS statt HTTP verwenden, ist mir aufgefallen, dass die Icons nicht mehr angezeigt wurden.

Nun habe ich mir einfach mal den Quelltext des Plugins angesehen, um dem Problem auf die Schliche zu kommen. Und tatsächlich: ein winziger Bug ist der Auslöser des ganzen Problems. Diesen findet man in der Methode "GetDomainnameForUri()", die in der Version 4.4 wie folgt aussieht:

1
2
3
4
5
6
7
8
9
10
11
12
        /**
         * Retrieve the domain name from the URI. We consider sub domains as well.
         */
   
        function GetDomainnameFromUri($uri){
            $exp1 = '/^(http|https|ftp)?(:\/\/)?(www.)?([^\/]+)/i';
                preg_match($exp1, $uri, $matches);
                if (isset($matches[4])) {
                return $matches[4];
            } else {
                        return '';
                }
        }

Hier wird die URL anhand eines regulären Ausdrucks zerteilt. Das Problem ist der erste Teil des Ausdrucks ("(http|https|ftp)?"), der besagt, dass ein Treffer vorhanden ist, sobald entweder "http", "https" oder "ftp" gefunden wird. Leider liefert dieser Ausdruck sofort ein Ergebnis zurück, sobald es "http" gesehen hat, sodass das mittlere "https" nie betrachtet wird.

Um mir das genauer anzusehen, habe ich mir mal einen Testfall geschrieben:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
  function GetDomainnameFromUri($uri){
    $exp1 = '/^(http|https|ftp)?(:\/\/)?(www.)?([^\/]+)/i';
    preg_match($exp1, $uri, $matches);
    print_r($matches);
  }

  GetDomainnameFromUri("/example");
  GetDomainnameFromUri("example.com");
  GetDomainnameFromUri("www.example.com");
  GetDomainnameFromUri("example.com/example");
  GetDomainnameFromUri("www.example.com/example");
  GetDomainnameFromUri("http://example.com");
  GetDomainnameFromUri("http://www.example.com");
  GetDomainnameFromUri("http://example.com/example");
  GetDomainnameFromUri("http://www.example.com/example");
  GetDomainnameFromUri("https://example.com");
  GetDomainnameFromUri("https://www.example.com");
  GetDomainnameFromUri("https://example.com/example");
  GetDomainnameFromUri("https://www.example.com/example");
?>

Hier die zugehörigen Ergebnisse:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
Array
(
)
Array
(
    [0] => example.com
    [1] =>
    [2] =>
    [3] =>
    [4] => example.com
)
Array
(
    [0] => www.example.com
    [1] =>
    [2] =>
    [3] => www.
    [4] => example.com
)
Array
(
    [0] => example.com
    [1] =>
    [2] =>
    [3] =>
    [4] => example.com
)
Array
(
    [0] => www.example.com
    [1] =>
    [2] =>
    [3] => www.
    [4] => example.com
)
Array
(
    [0] => http://example.com
    [1] => http
    [2] => ://
    [3] =>
    [4] => example.com
)
Array
(
    [0] => http://www.example.com
    [1] => http
    [2] => ://
    [3] => www.
    [4] => example.com
)
Array
(
    [0] => http://example.com
    [1] => http
    [2] => ://
    [3] =>
    [4] => example.com
)
Array
(
    [0] => http://www.example.com
    [1] => http
    [2] => ://
    [3] => www.
    [4] => example.com
)
Array
(
    [0] => https:
    [1] => http
    [2] =>
    [3] =>
    [4] => s:
)
Array
(
    [0] => https:
    [1] => http
    [2] =>
    [3] =>
    [4] => s:
)
Array
(
    [0] => https:
    [1] => http
    [2] =>
    [3] =>
    [4] => s:
)
Array
(
    [0] => https:
    [1] => http
    [2] =>
    [3] =>
    [4] => s:
)

Wie man sieht, wird durch den ersten Ausdruck ("(http|https|ftp)?") das "http" herausgetrennt, die nächsten beiden Ausdrücke ("(:\/\/)?" und "(www.)?") liefern leere Ergebnisse und erst der letzte Ausdruck ("([^\/]+)") fängt den Rest ab - allerdings nur bis zum ersten Slash. Dementsprechend heißen alle HTTPS-URLs nach dem Parsen nur noch "s:".

In dem Plugin konfiguriert man auch die Adresse seiner eigenen Website. Diese Konfiguration wird mit der gleichen Funktion bearbeitet. Wenn nun also die eigene Seite eine HTTPS-Adresse enthält und gleichzeitig ein externer Link eine HTTPS-Adresse enthält, so führen diese beiden unterschiedlichen Adressen zum selben Ergebnis "s:" in der Funktion "GetDomainnameFromUri()".

Ein weiteres Problem in dieser Funktion dürfte eher wenige Adressen treffen: Der dritte Ausdruck ("(www.)?") hat nämlich ein Problem - den Punkt. Bei regulären Ausdrücken steht der Punkt nicht einfach nur für das Zeichen ".", sondern für alle Zeichen. Daher muss er, wenn das Zeichen "." gemeint ist, escaped werden ("\.").

Nehmen wir mal ein Beispiel, wo dieser Bug zu Problem führt: Wenn ich beispielsweise die URL der Supportseite der IBM hernehme, so lautet diese "http://www.ibm.com/support/entry/portal/de/de". Wenn man diese jedoch besucht, wird man auf "http://www-947.ibm.com/support/entry/portal/support" weitergeleitet. Der Ausdruck ("(www.)?") erkennt nun jedoch "www-" und schneidet es weg. Übrig bleibt dann die nicht existente Domain "947.ibm.com":

1
2
3
4
5
6
7
8
Array
(
    [0] => http://www-947.ibm.com
    [1] => http
    [2] => ://
    [3] => www-
    [4] => 947.ibm.com
)

Weiterhin kann die jetzige Funktion weder mit Authentisierungen, noch mit Portnummern umgehen. Diese werden einfach der Domain zugerechnet. Um das alles zu beheben, muss man den Ausdruck ein wenig abändern. Die neue Variante kann dann mit wesentlich mehr Fällen umgehen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
  function GetDomainnameFromUri($uri){
    $exp1 = '/^(([^:]+:\/\/)|(\/\/))?(([^:]+):([^@]+)@)?([^:\/\?\#]+)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/i';
    preg_match($exp1, $uri, $matches);
    print_r($matches);
  }

  GetDomainnameFromUri("/example");
  GetDomainnameFromUri("example.com");
  GetDomainnameFromUri("www.example.com");
  GetDomainnameFromUri("example.com/example");
  GetDomainnameFromUri("www.example.com/example");
  GetDomainnameFromUri("http://example.com");
  GetDomainnameFromUri("http://www.example.com");
  GetDomainnameFromUri("http://example.com/example");
  GetDomainnameFromUri("http://www.example.com/example");
  GetDomainnameFromUri("https://example.com");
  GetDomainnameFromUri("https://www.example.com");
  GetDomainnameFromUri("https://example.com/example");
  GetDomainnameFromUri("https://www.example.com/example");

  GetDomainnameFromUri("//example.com");
  GetDomainnameFromUri("user:password@example.com");
  GetDomainnameFromUri("example.com:80");
  GetDomainnameFromUri("example.com/example?example=example");
  GetDomainnameFromUri("example.com/example#example");
?>

Hier dazu der entsprechende Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
Array
(
)
Array
(
    [0] => example.com
    [1] =>
    [2] =>
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => example.com
)
Array
(
    [0] => www.example.com
    [1] =>
    [2] =>
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => www.example.com
)
Array
(
    [0] => example.com/example
    [1] =>
    [2] =>
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => example.com
    [8] =>
    [9] =>
    [10] => /example
)
Array
(
    [0] => www.example.com/example
    [1] =>
    [2] =>
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => www.example.com
    [8] =>
    [9] =>
    [10] => /example
)
Array
(
    [0] => http://example.com
    [1] => http://
    [2] => http://
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => example.com
)
Array
(
    [0] => http://www.example.com
    [1] => http://
    [2] => http://
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => www.example.com
)
Array
(
    [0] => http://example.com/example
    [1] => http://
    [2] => http://
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => example.com
    [8] =>
    [9] =>
    [10] => /example
)
Array
(
    [0] => http://www.example.com/example
    [1] => http://
    [2] => http://
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => www.example.com
    [8] =>
    [9] =>
    [10] => /example
)
Array
(
    [0] => https://example.com
    [1] => https://
    [2] => https://
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => example.com
)
Array
(
    [0] => https://www.example.com
    [1] => https://
    [2] => https://
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => www.example.com
)
Array
(
    [0] => https://example.com/example
    [1] => https://
    [2] => https://
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => example.com
    [8] =>
    [9] =>
    [10] => /example
)
Array
(
    [0] => https://www.example.com/example
    [1] => https://
    [2] => https://
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => www.example.com
    [8] =>
    [9] =>
    [10] => /example
)
Array
(
    [0] => //example.com
    [1] => //
    [2] =>
    [3] => //
    [4] =>
    [5] =>
    [6] =>
    [7] => example.com
)
Array
(
    [0] => user:password@example.com
    [1] =>
    [2] =>
    [3] =>
    [4] => user:password@
    [5] => user
    [6] => password
    [7] => example.com
)
Array
(
    [0] => example.com:80
    [1] =>
    [2] =>
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => example.com
    [8] => :80
    [9] => 80
)
Array
(
    [0] => example.com/example?example=example
    [1] =>
    [2] =>
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => example.com
    [8] =>
    [9] =>
    [10] => /example
    [11] => ?example=example
    [12] => example=example
)
Array
(
    [0] => example.com/example#example
   [1] =>
    [2] =>
    [3] =>
    [4] =>
    [5] =>
    [6] =>
    [7] => example.com
    [8] =>
    [9] =>
    [10] => /example
    [11] =>
    [12] =>
    [13] => #example
   [14] => example
)

Die eigentliche Methode sollte also nach Möglichkeit so aussen:

1
2
3
4
5
6
7
8
9
10
11
12
        /**
         * Retrieve the domain name from the URI. We consider sub domains as well.
         */
   
        function GetDomainnameFromUri($uri){
            $exp1 = '/^(([^:]+:\/\/)|(\/\/))?(([^:]+):([^@]+)@)?([^:\/\?\#]+)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/i';
            preg_match($exp1, $uri, $matches);
            if (isset($matches[7])) {
                return $matches[7];
            } else {
                return '';
            }
        }

Ich habe diese neue Version nun bei mir im Einsatz und sie funktioniert so, wie die alte es von Anfang an hätte tun sollen. 🙂

Linkindikatorgrüße, Kenny

Schreibe einen Kommentar

Um Ihnen beim weiteren Kommentieren auf dieser Webseite die erneute Eingabe Ihrer Daten zu ersparen, wird beim Absenden Ihres Kommentars ein Cookie an Ihren Browser gesendet und von diesem gespeichert. Mit dem Absenden eines Kommentars auf dieser Webseite stimmen Sie der Speicherung und Übertragung dieses Cookies explizit zu.

Pflichtfelder sind mit * markiert.