You've built a bookmark manager, a link directory, or a dashboard that displays other websites. You want each site's favicon to make the list look polished — but blindly hitting /favicon.ico for every URL is fragile. Many sites ship SVG icons, use custom paths, or rely on conditional <link> tags instead of the default root file.
This tutorial walks through a PHP get favicon from URL workflow: parse the HTML for <link rel="icon"> declarations, fall back to the legacy /favicon.ico endpoint, validate the response, and save the binary locally.
Prerequisites
You need PHP 7.4 or newer with two extensions enabled:
curl — for fetching remote pages and following redirects
dom — for parsing HTML and extracting <link> tags
Both ship with the official PHP Docker image and most Linux distributions. Run php -m to confirm they're listed before you start coding.
Step 1: Fetch the Page HTML
Start with a basic cURL request. The User-Agent header matters more than it looks — some sites return a stripped-down HTML to non-browser clients, which can omit favicon <link> tags entirely.
Always cap redirects and timeouts. A runaway 30-second cURL request is a fast way to fill your PHP-FPM worker pool.
Step 2: Parse the HTML for rel="icon" Tags
The HTML spec defines rel="icon" as the way to declare a favicon (see the WHATWG link relation reference). Browsers may pick any matching <link>, so we scan every occurrence and prefer the first one with a usable href.
<?php
function findIconUrl(string $baseUrl, string $html): ?string {
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML($html);
libxml_clear_errors();
$xpath = new DOMXPath($dom);
$links = $xpath->query('//link[@rel="icon" or @rel="shortcut icon"]');
foreach ($links as $link) {
$href = $link->getAttribute('href');
if ($href === '') continue;
return resolveUrl($baseUrl, $href);
}
return null;
}
?>
Notice we include shortcut icon as well — it's an old Microsoft IE relic, but a surprising number of legacy sites still declare their favicon that way.
Step 3: Resolve Relative URLs
Favicon hrefs are often relative paths like /static/icon.png or icons/favicon.svg. Use parse_url plus a small helper to turn them into absolute URLs before downloading.
If the HTML contains no <link rel="icon"> tags, every browser still requests /favicon.ico automatically. Hit that endpoint as a fallback so you don't return blank icons for old-school sites.
Now download the icon, verify it actually returned an image, and save it to disk. Always re-fetch with cURL rather than reusing the HTML response — the favicon URL may live on a different domain or CDN with different caching rules.
HTML error pages masquerading as icons. A misconfigured server can return a 200 status with an HTML body when the favicon is missing. Always check the content-type header and discard anything that doesn't start with image/.
CDN rate limits. Hitting a third-party CDN from your server repeatedly can get your IP throttled or banned. Cache successful downloads to disk and respect a polite fetch interval (a few seconds per host is usually safe).
SSL verification disabled. Setting CURLOPT_SSL_VERIFYPEER to false is tempting during debugging but exposes your users to MITM attacks. Keep it on in production.
Encoding edge cases. DOMDocument falls back to ISO-8859-1 when the HTML lacks a charset meta tag, which can garble href values on UTF-8 sites. Prepend a <meta charset='UTF-8'> block or switch to a UTF-8-aware parser like HTML5DomDocument.
Same-origin policy does not apply server-side. PHP can fetch any public favicon without CORS checks — those rules only apply to your front-end JavaScript.
When to Switch to a Dedicated Tool
A hand-rolled PHP function is fine for a few thousand URLs. Once you need multi-format output (ICO, PNG, SVG, Apple Touch), dark-mode awareness, maskable manifest icons, or reliable coverage of sites with quirky <link> structures, the cURL plumbing becomes a maintenance burden. A tool like Mzu favicondl handles the parsing, fallback, normalization, and packaging across every browser and device, so you can drop the boilerplate and focus on your product.
You can also compare this manual approach with the popular public favicon API endpoints to see which trade-off fits your stack better — manual fetching gives you full control, while APIs save time at the cost of an external dependency.
また、この手作業のアプローチと、よく利用されている公開 favicon API エンドポイント を比較し、どちらのトレードオフがご自身のスタックに合っているか検討するのも良いでしょう。手動フェッチは完全な制御を得られる一方で、API は外部依存というコストを払う代わりに時間を節約できます。
북마크 매니저, 링크 디렉터리, 또는 다른 웹사이트를 표시하는 대시보드를 만들어 보신 적 있을 겁니다. 목록을 깔끔하게 보이도록 각 사이트의 favicon을 표시하고 싶지만, 모든 URL에 대해 무작정 /favicon.ico를 요청하는 방법은 안정적이지 않습니다. 많은 사이트가 SVG 아이콘을 사용하거나, 사용자 지정 경로를 쓰거나, 기본 루트 파일 대신 조건부 <link> 태그에 의존하기 때문입니다.
이 튜토리얼에서는 HTML에서 <link rel="icon"> 선언을 파싱하고, 기존 /favicon.ico 엔드포인트로 폴백(fallback)한 뒤, 응답을 검증하여 바이너리를 저장하는 PHP get favicon from URL 워크플로를 단계별로 살펴봅니다.
사전 준비 사항
PHP 7.4 이상과 다음 두 가지 확장이 활성화되어 있어야 합니다.
curl — 원격 페이지를 가져오고 리디렉션을 처리하기 위해 필요
dom — HTML을 파싱하고 <link> 태그를 추출하기 위해 필요
두 확장은 공식 PHP Docker 이미지와 대부분의 Linux 배포판에 기본 포함되어 있습니다. 코딩을 시작하기 전에 php -m 명령으로 두 확장이 목록에 표시되는지 확인해 주세요.
1단계: 페이지 HTML 가져오기
기본 cURL 요청부터 시작합니다. User-Agent 헤더는 생각보다 중요합니다. 일부 사이트는 브라우저가 아닌 클라이언트에 대해서는 단순화된 HTML을 반환하며, 이 경우 favicon <link> 태그가 아예 누락될 수 있습니다.
리디렉션과 타임아웃에는 항상 상한을 두세요. 30초짜리 cURL 요청이 제어 없이 이어지면 PHP-FPM 워커 풀이 금방 가득 차게 됩니다.
2단계: rel="icon" 태그를 위해 HTML 파싱하기
HTML 명세는 favicon을 선언하는 방법으로 rel="icon"을 정의하고 있습니다(WHATWG 링크 관계 참조 참고). 브라우저는 일치하는 <link> 중 어느 것이든 선택할 수 있으므로, 우리는 모든 항목을 스캔하고 사용 가능한 href를 가진 첫 번째 항목을 우선 사용합니다.
<?php
function findIconUrl(string $baseUrl, string $html): ?string {
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML($html);
libxml_clear_errors();
$xpath = new DOMXPath($dom);
$links = $xpath->query('//link[@rel="icon" or @rel="shortcut icon"]');
foreach ($links as $link) {
$href = $link->getAttribute('href');
if ($href === '') continue;
return resolveUrl($baseUrl, $href);
}
return null;
}
?>
여기서 shortcut icon 항목도 함께 포함했습니다. 이는 구 Microsoft IE의 잔재이지만, 의외로 많은 레거시 사이트가 아직도 이 방식으로 favicon을 선언하고 있습니다.
Step 3: 상대 URL 해석하기
Favicon의 href는 /static/icon.png나 icons/favicon.svg처럼 상대 경로인 경우가 많습니다. 다운로드 전에 parse_url과 간단한 helper 함수를 함께 사용해 절대 URL로 변환합니다.
HTML 오류 페이지가 아이콘으로 위장하는 경우. 서버 설정이 잘못되면 favicon이 없을 때 HTML 본문과 함께 200 상태를 반환할 수 있습니다. 항상 content-type 헤더를 확인하고 image/으로 시작하지 않는 응답은 버려야 합니다.
CDN 요청 제한. 서버에서 타사 CDN을 반복적으로 호출하면 IP가 제한되거나 차단될 수 있습니다. 성공한 다운로드는 디스크에 캐시하고, 정중한 요청 간격(호스트당 몇 초 정도면 보통 안전)을 유지하세요.
SSL 검증 비활성화. 디버깅 중에 CURLOPT_SSL_VERIFYPEER를 false로 설정하고 싶어질 수 있지만, 사용자를 MITM 공격에 노출시킵니다. 운영 환경에서는 검증 옵션을 그대로 켜두세요.
인코딩 엣지 케이스. HTML에 charset meta 태그가 없을 때 DOMDocument는 ISO-8859-1로 폴백하기 때문에, UTF-8 사이트에서는 href 값을 왜곡할 수 있습니다. <meta charset='UTF-8'> 블록을 앞에 붙이거나 HTML5DomDocument처럼 UTF-8을 인식하는 파서로 전환하세요.
Same-origin 정책은 서버 측에는 적용되지 않습니다. PHP는 CORS 검사 없이도 모든 공개 favicon을 가져올 수 있습니다. 이 규칙은 프런트엔드 JavaScript에만 적용됩니다.
전용 도구로 전환할 시점
수천 개 정도의 URL이라면 직접 작성한 PHP 함수로도 충분합니다. 하지만 ICO, PNG, SVG, Apple Touch 아이콘 같은 멀티 포맷 출력, 다크 모드 인식, maskable manifest 아이콘, 혹은 특이한 <link> 구조를 가진 사이트까지 안정적으로 대응해야 할 때가 되면, cURL 코드는 유지보수 부담이 됩니다. Mzu favicondl 같은 도구는 모든 브라우저와 디바이스에 걸친 파싱, 폴백, 정규화, 패키징을 처리해 주므로 보일러플레이트를 걷어내고 제품 개발에 집중할 수 있습니다.
이 수동 방식을 인기 있는 공개 favicon API 엔드포인트와 비교해 보면, 어떤 트레이드오프가 자신의 스택에 더 맞는지 판단할 수 있습니다. 수동 페칭은 완전한 제어권을 주는 반면, API는 외부 종속성을 감수하는 대신 시간을 절약해 줍니다.
Has construido un gestor de marcadores, un directorio de enlaces o un panel que muestra otros sitios web. Quieres que el favicon de cada sitio haga que la lista se vea pulida — pero lanzar a ciegas una petición a /favicon.ico por cada URL es frágil. Muchos sitios publican iconos SVG, usan rutas personalizadas o dependen de etiquetas <link> condicionales en lugar del archivo raíz por defecto.
Este tutorial te guía paso a paso por un flujo de PHP para obtener el favicon a partir de una URL: analizar el HTML en busca de declaraciones <link rel="icon">, recurrir al endpoint heredado /favicon.ico como fallback, validar la respuesta y guardar el binario en local.
Requisitos previos
Necesitas PHP 7.4 o superior con dos extensiones habilitadas:
curl — para obtener páginas remotas y seguir redirecciones
dom — para analizar el HTML y extraer las etiquetas <link>
Ambas vienen incluidas en la imagen oficial de PHP para Docker y en la mayoría de distribuciones de Linux. Ejecuta php -m para confirmar que aparecen listadas antes de empezar a programar.
Paso 1: Obtener el HTML de la página
Empieza con una petición cURL básica. La cabecera User-Agent importa más de lo que parece — algunos sitios devuelven un HTML simplificado a clientes que no son navegadores, lo que puede omitir por completo las etiquetas <link> del favicon.
Limita siempre las redirecciones y los timeouts. Una petición cURL descontrolada de 30 segundos es la forma más rápida de saturar tu pool de workers de PHP-FPM.
Paso 2: Analizar el HTML en busca de etiquetas rel="icon"
La especificación de HTML define rel="icon" como la forma de declarar un favicon (consulta la referencia de relaciones de enlace del WHATWG). Los navegadores pueden elegir cualquier <link> que coincida, así que recorremos todas las ocurrencias y preferimos la primera que tenga un href utilizable.
<?php
function findIconUrl(string $baseUrl, string $html): ?string {
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML($html);
libxml_clear_errors();
$xpath = new DOMXPath($dom);
$links = $xpath->query('//link[@rel="icon" or @rel="shortcut icon"]');
foreach ($links as $link) {
$href = $link->getAttribute('href');
if ($href === '') continue;
return resolveUrl($baseUrl, $href);
}
return null;
}
?>
Fíjate que incluimos también shortcut icon: es una reliquia de Microsoft IE, pero sorprendentemente muchos sitios legacy todavía declaran su favicon de esa forma.
Paso 3: Resolver URLs relativas
Los href del favicon suelen ser rutas relativas como /static/icon.png o icons/favicon.svg. Usa parse_url junto con un pequeño helper para convertirlas en URLs absolutas antes de descargarlas.
Si el HTML no contiene etiquetas <link rel="icon">, todos los navegadores siguen solicitando /favicon.ico automáticamente. Accede a ese endpoint como fallback para no devolver iconos en blanco en sitios antiguos.
Ahora descarga el icono, verifica que realmente devolvió una imagen y guárdalo en disco. Vuelve a solicitarlo siempre con cURL en lugar de reutilizar la respuesta HTML: la URL del favicon puede estar en un dominio o CDN diferente con reglas de caché distintas.
Páginas de error HTML haciéndose pasar por iconos. Un servidor mal configurado puede devolver un estado 200 con un cuerpo HTML cuando falta el favicon. Comprueba siempre la cabecera content-type y descarta cualquier cosa que no empiece por image/.
Límites de tasa del CDN. Si realizas muchas peticiones a un CDN de terceros desde tu servidor, pueden limitarte o banearte la IP. Guarda en disco las descargas exitosas y respeta un intervalo de fetch educado (unos pocos segundos por host suele ser seguro).
Verificación SSL deshabilitada. Poner CURLOPT_SSL_VERIFYPEER a false es tentador durante la depuración, pero expone a tus usuarios a ataques MITM. Mantenlo activado en producción.
Casos límite de codificación. DOMDocument recurre a ISO-8859-1 cuando el HTML carece de una meta tag de charset, lo que puede estropear los valores de href en sitios UTF-8. Para evitarlo, antepón un bloque <meta charset='UTF-8'> o cambia a un parser con soporte UTF-8 como HTML5DomDocument.
La política de mismo origen no se aplica en el lado del servidor. PHP puede obtener cualquier favicon público sin comprobaciones CORS: esas reglas solo aplican al JavaScript de tu front-end.
Cuándo pasar a una herramienta dedicada
Una función PHP hecha a mano es suficiente para unos pocos miles de URLs. Cuando necesitas salida multi-formato (ICO, PNG, SVG, Apple Touch), soporte de modo oscuro, iconos maskable para manifest o cobertura fiable de sitios con estructuras de <link> peculiares, el cableado de cURL se convierte en una carga de mantenimiento. Una herramienta como Mzu favicondl se encarga del parsing, el fallback, la normalización y el empaquetado en cada navegador y dispositivo, para que puedas olvidarte del boilerplate y centrarte en tu producto.
También puedes comparar este enfoque manual con los populares endpoints públicos de API de favicon para ver qué trade-off encaja mejor con tu stack: el fetching manual te da control total, mientras que las APIs ahorran tiempo a costa de una dependencia externa.
Skip the cURL Plumbing
Mzu favicondl parses favicon links, downloads every format, and packages them for all browsers in one click.