Skip to content

Commit 4aa5a86

Browse files
committed
Fixed favicons not loading
1 parent 4e63810 commit 4aa5a86

File tree

1 file changed

+137
-65
lines changed

1 file changed

+137
-65
lines changed

resources/views/components/favicon.blade.php

Lines changed: 137 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,159 @@
1-
<?php use App\Models\Link; ?>
2-
31
<?php
4-
function getFavIcon($id) {
5-
$link = Link::find($id);
6-
$url = $link->link;
7-
8-
$html = false;
9-
$context = stream_context_create();
10-
11-
// Set timeout to 3 seconds
12-
stream_context_set_option($context, 'http', 'timeout', 3);
13-
14-
// Set custom User-Agent header
15-
$userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36';
16-
stream_context_set_option($context, 'http', 'header', "User-Agent: $userAgent\r\n");
17-
18-
// Attempt to fetch HTML content with timeout
19-
if (function_exists('curl_version')) {
20-
$curlHandle = curl_init($url);
21-
curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true);
22-
curl_setopt($curlHandle, CURLOPT_TIMEOUT, 3);
23-
curl_setopt($curlHandle, CURLOPT_USERAGENT, $userAgent);
24-
$html = curl_exec($curlHandle);
25-
curl_close($curlHandle);
26-
} else {
27-
$html = @file_get_contents($url, false, $context);
2+
use App\Models\Link;
3+
4+
function getFaviconURL($url)
5+
{
6+
$ch = curl_init($url);
7+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
8+
curl_setopt($ch, CURLOPT_HEADER, true);
9+
curl_setopt($ch, CURLOPT_NOBODY, true);
10+
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36');
11+
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
12+
$response = curl_exec($ch);
13+
14+
// Check if cURL request was successful
15+
if ($response === false) {
16+
return null;
2817
}
2918
30-
31-
$dom = new DOMDocument();
32-
if ($html !== false) {
19+
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
20+
curl_close($ch);
21+
22+
// Check if the URL is redirected
23+
if ($httpCode == 301 || $httpCode == 302) {
24+
$redirectUrl = getRedirectUrlFromHeaders($response);
25+
if ($redirectUrl) {
26+
return getFaviconURL($redirectUrl); // Recursively call getFavicon with the redirected URL
27+
}
28+
}
29+
30+
// Try extracting favicon using DOMDocument
3331
try {
34-
@$dom->loadHTML($html);
35-
} catch (Throwable $e) {}
36-
}
32+
$dom = new DOMDocument();
33+
$dom->strictErrorChecking = false;
34+
@$dom->loadHTMLFile($url);
35+
if ($dom) {
36+
$domxml = simplexml_import_dom($dom);
37+
// Check for the historical rel="shortcut icon"
38+
if ($domxml->xpath('//link[@rel="shortcut icon"]')) {
39+
$path = $domxml->xpath('//link[@rel="shortcut icon"]');
40+
$faviconURL = getAbsoluteUrl($url, $path[0]['href']);
41+
return $faviconURL;
42+
}
43+
// Check for the HTML5 rel="icon"
44+
elseif ($domxml->xpath('//link[@rel="icon"]')) {
45+
$path = $domxml->xpath('//link[@rel="icon"]');
46+
$faviconURL = getAbsoluteUrl($url, $path[0]['href']);
47+
return $faviconURL;
48+
}
49+
}
50+
} catch (Exception $e) {
51+
// Silently fail and continue to the next method
52+
}
3753
54+
// Check directly for favicon.ico or favicon.png
55+
$parse = parse_url($url);
56+
$favicon_headers = @get_headers("http://" . $parse['host'] . "/favicon.ico");
57+
if ($favicon_headers && $favicon_headers[0] != 'HTTP/1.1 404 Not Found') {
58+
$faviconURL = "http://" . $parse['host'] . "/favicon.ico";
59+
return $faviconURL;
60+
}
3861
39-
$xpath = new DOMXPath($dom);
62+
$favicon_headers = @get_headers("http://" . $parse['host'] . "/favicon.png");
63+
if ($favicon_headers && $favicon_headers[0] != 'HTTP/1.1 404 Not Found') {
64+
$faviconURL = "http://" . $parse['host'] . "/favicon.png";
65+
return $faviconURL;
66+
}
4067
41-
$faviconUrl = '';
68+
// Fallback to regex extraction
69+
$faviconURL = extractFaviconUrlWithRegex($response);
70+
if ($faviconURL) {
71+
$faviconURL = getAbsoluteUrl($url, $faviconURL);
72+
}
73+
return $faviconURL;
74+
}
4275
43-
// Search for <link> tags with rel="icon" or rel="shortcut icon"
44-
$linkTags = $xpath->query("//link[contains(@rel, 'icon') or contains(@rel, 'shortcut icon')]");
45-
foreach ($linkTags as $tag) {
46-
$faviconUrl = $tag->getAttribute('href');
47-
if (strpos($faviconUrl, 'http') !== 0) {
48-
$faviconUrl = $url . '/' . ltrim($faviconUrl, '/');
49-
}
50-
break; // Stop after the first matching <link> tag
76+
function getRedirectUrlFromHeaders($headers)
77+
{
78+
if (preg_match('/^Location:\s+(.*)$/mi', $headers, $matches)) {
79+
return trim($matches[1]);
80+
}
81+
return null;
82+
}
83+
84+
function extractFaviconUrlWithRegex($html)
85+
{
86+
// Check for the historical rel="shortcut icon"
87+
if (preg_match('/<link[^>]+rel=["\']shortcut icon["\'][^>]+href=["\']([^"\']+)["\']/', $html, $matches)) {
88+
$faviconURL = $matches[1];
89+
return $faviconURL;
5190
}
5291
53-
$fallbackFavicon = 'assets/linkstack/icons/website.svg';
92+
// Check for the HTML5 rel="icon"
93+
if (preg_match('/<link[^>]+rel=["\']icon["\'][^>]+href=["\']([^"\']+)["\']/', $html, $matches)) {
94+
$faviconURL = $matches[1];
95+
return $faviconURL;
96+
}
97+
98+
return null;
99+
}
54100
55-
if (empty($faviconUrl)) {
56-
$faviconUrl = $fallbackFavicon;
101+
function getAbsoluteUrl($baseUrl, $relativeUrl)
102+
{
103+
$parsedUrl = parse_url($baseUrl);
104+
$scheme = isset($parsedUrl['scheme']) ? $parsedUrl['scheme'] : 'http';
105+
$host = isset($parsedUrl['host']) ? $parsedUrl['host'] : '';
106+
$path = isset($parsedUrl['path']) ? $parsedUrl['path'] : '';
107+
$basePath = "$scheme://$host$path";
108+
109+
if (strpos($relativeUrl, 'http') === 0) {
110+
return $relativeUrl; // Already an absolute URL
111+
} elseif (strpos($relativeUrl, '/') === 0) {
112+
return "$scheme://$host$relativeUrl"; // Root-relative URL
113+
} else {
114+
return "$basePath/$relativeUrl"; // Path-relative URL
57115
}
116+
}
117+
118+
function getFavIcon($id)
119+
{
120+
try{
121+
122+
$link = Link::find($id);
123+
$page = $link->link;
58124
59-
$extension = pathinfo($faviconUrl, PATHINFO_EXTENSION);
60-
$filename = $id . "." . $extension;
61-
$filepath = base_path("assets/favicon/icons") . "/" . $filename;
125+
$url = getFaviconURL($page);
126+
127+
$fileExtension = pathinfo($url, PATHINFO_EXTENSION);
128+
$filename = $id . '.' . $fileExtension;
129+
$filepath = base_path('assets/favicon/icons') . '/' . $filename;
62130
63131
if (!file_exists($filepath)) {
64-
if ($faviconUrl !== $fallbackFavicon) {
65-
if (function_exists('curl_version')) {
66-
$curlHandle = curl_init($faviconUrl);
67-
curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true);
68-
curl_setopt($curlHandle, CURLOPT_TIMEOUT, 3);
69-
curl_setopt($curlHandle, CURLOPT_USERAGENT, $userAgent);
70-
$faviconData = curl_exec($curlHandle);
71-
curl_close($curlHandle);
72-
73-
if ($faviconData !== false) {
74-
file_put_contents($filepath, $faviconData);
75-
}
76-
} else {
77-
file_put_contents($filepath, file_get_contents($faviconUrl, false, $context));
132+
if (function_exists('curl_version')) {
133+
$curlHandle = curl_init($url);
134+
curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, true);
135+
curl_setopt($curlHandle, CURLOPT_TIMEOUT, 3);
136+
$faviconData = curl_exec($curlHandle);
137+
curl_close($curlHandle);
138+
139+
if ($faviconData !== false) {
140+
file_put_contents($filepath, $faviconData);
78141
}
79142
} else {
80-
copy($fallbackFavicon, $filepath);
143+
file_put_contents($filepath, file_get_contents($url));
81144
}
82145
}
83146
84-
return $filename;
147+
return url('assets/favicon/icons/' . $id . '.' . $fileExtension);
148+
149+
}catch(Exception $e){
150+
// Handle the exception by copying the default SVG favicon
151+
$defaultIcon = base_path('assets/linkstack/icons/website.svg');
152+
$filename = $id . '.svg';
153+
$filepath = base_path('assets/favicon/icons') . '/' . $filename;
154+
copy($defaultIcon, $filepath);
155+
156+
return url('assets/favicon/icons/' . $filename);
157+
}
85158
}
86159
?>
87-

0 commit comments

Comments
 (0)