A Laravel package that can be used for fetching favicons from websites

Overview

Favicon Fetcher

Latest Version on Packagist Build Status Total Downloads PHP from Packagist GitHub license

Table of Contents

Overview

A Laravel package that can be used for fetching favicons from websites.

Installation

Requirements

The package has been developed and tested to work with the following minimum requirements:

  • PHP 8.0
  • Laravel 8.0

Install the Package

You can install the package via Composer:

composer require ashallendesign/favicon-fetcher

Publish the Config

You can then publish the package's config file by using the following command:

php artisan vendor:publish --provider="AshAllenDesign\FaviconFetcher\FaviconFetcherProvider"

Usage

Fetching Favicons

Now that you have the package installed, you can start fetching the favicons from different websites.

Using the fetch Method

To fetch a favicon from a website, you can use the fetch method which will return an instance of AshAllenDesign\FaviconFetcher\Favicon:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$favicon = Favicon::fetch('https://ashallendesign.co.uk');

Using the fetchOr Method

If you'd like to provide a default value to be used if a favicon cannot be found, you can use the fetchOr method.

For example, if you wanted to use a default icon (https://example.com/favicon.ico) if a favicon could not be found, your code could look something like this:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$favicon = Favicon::fetchOr('https://ashallendesign.co.uk', 'https://example.com/favicon.ico');

This method also accepts a Closure as the second argument if you'd prefer to run some custom logic. The url field passed as the first argument to the fetchOr method is available to use in the closure. For example, to use a closure, your code could look something like this:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$favicon = Favicon::fetchOr('https://ashallendesign.co.uk', function ($url) {
    // Run extra logic here...

    return 'https://example.com/favicon.ico';
});

Exceptions

By default, if a favicon can't be found for a URL, the fetch method will return null. However, if you'd prefer an exception to be thrown, you can use the throw method available on the Favicon facade. This means that if a favicon can't be found, an AshAllenDesign\FaviconFetcher\Exceptions\FaviconNotFoundException will be thrown.

To enable exceptions to be thrown, your code could look something like this:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$favicon = Favicon::throw()->fetch('https://ashallendesign.co.uk');

Drivers

Favicon Fetcher provides the functionality to use different drivers for retrieving favicons from websites.

Available Drivers

By default, Favicon Fetcher ships with 4 drivers out-the-box: http, google-shared-stuff, favicon-kit, unavatar.

The http driver fetches favicons by attempting to parse "icon" and "shortcut icon" link elements from the returned HTML of a webpage. If it can't find one, it will attempt to guess the URL of the favicon based on common defaults.

The google-shared-stuff driver fetches favicons using the Google Shared Stuff API.

The favicon-kit driver fetches favicons using the Favicon Kit API.

The unavatar driver fetches favicons using the Unavatar API.

How to Choose a Driver

It's important to remember that the google-shared-stuff, favicon-kit, and unavatar drivers interact with third-party APIs to retrieve the favicons. So, this means that some data will be shared to external services.

However, the http driver does not use any external services and directly queries the website that you are trying to fetch the favicon for. Due to the fact that this package is new, it is likely that the http driver may not be 100% accurate when trying to fetch favicons from websites. So, theoretically, the http driver should provide you with better privacy, but may not be as accurate as the other drivers.

Choosing a Driver

You can select which driver to use by default by changing the default field in the favicon-fetcher config file after you've published it. The package originally ships with the http driver enabled as the default driver.

For example, if you wanted to change your default driver to favicon-kit, you could update your favicon-fetcher config like so:

return [

    // ...
        
    'default' => 'favicon-kit',
            
    // ...

]

If you'd like to set the driver on-the-fly, you can do so by using the driver method on the Favicon facade. For example, if you wanted to use the google-shared-stuff driver, you could do so like this:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$favicon = Favicon::driver('google-shared-stuff')->fetch('https://ashallendesign.co.uk');

Fallback Drivers

There may be times when a particular driver cannot find a favicon for a website. If this happens, you can fall back and attempt to find it again using a different driver.

For example, if we wanted to try and fetch the favicon using the http driver and then fall back to the google-shared-stuff driver if we can't find it, your code could look something like this:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$favicon = Favicon::withFallback('google-shared-stuff')->fetch('https://ashallendesign.co.uk');

Adding Your Own Driver

There might be times when you want to provide your own custom logic for fetching favicons. To do this, you can build your driver and register it with the package for using.

First, you'll need to create your own class and make sure that it implements the AshAllenDesign\FaviconFetcher\Contracts\Fetcher interface. For example, your class could like this:

use AshAllenDesign\FaviconFetcher\Contracts\Fetcher;
use AshAllenDesign\FaviconFetcher\Favicon;

class MyCustomDriver implements Fetcher
{
    public function fetch(string $url): ?Favicon
    {
        // Add logic here that attempts to fetch a favicon...
    }

    public function fetchOr(string $url, mixed $default): mixed
    {
        // Add logic here that attempts to fetch a favicon or return a default...
    }
}

After you've created your new driver, you'll be able to register it with the package using the extend method available through the Favicon facade. You may want to do this in a service provider so that it is set up and available in the rest of your application.

You can register your custom driver like so:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

Favicon::extend('my-custom-driver', new MyCustomDriver());

Now that you've registered your custom driver, you'll be able to use it for fetching favicons like so:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$favicon = Favicon::driver('my-custom-driver')->fetch('https://ashallendesign.co.uk');

Storing Favicons

After fetching favicons, you might want to store them in your filesystem so that you don't need to fetch them again in the future. Favicon Fetcher provides two methods that you can use for storing the favicons: store and storeAs.

Using store

If you use the store method, a filename will automatically be generated for the favicon before storing. The method's first parameter accepts a string and is the directory that the favicon will be stored in. You can store a favicon using your default filesystem disk like so:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$faviconPath = Favicon::fetch('https://ashallendesign.co.uk')->store('favicons');

// $faviconPath is now equal to: "/favicons/abc-123.ico"

If you'd like to use a different storage disk, you can pass it as an optional second argument to the store method. For example, to store the favicon on S3, your code use the following:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$faviconPath = Favicon::fetch('https://ashallendesign.co.uk')->store('favicons', 's3');

// $faviconPath is now equal to: "/favicons/abc-123.ico"

Using storeAs

If you use the storeAs method, you will be able to define the filename that the file will be stored as. The method's first parameter accepts a string and is the directory that the favicon will be stored in. The second parameter specifies the favicon filename (excluding the file extension). You can store a favicon using your default filesystem disk like so:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$faviconPath = Favicon::fetch('https://ashallendesign.co.uk')->storeAs('favicons', 'ashallendesign');

// $faviconPath is now equal to: "/favicons/ashallendesign.ico"

If you'd like to use a different storage disk, you can pass it as an optional third argument to the storeAs method. For example, to store the favicon on S3, your code use the following:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$faviconPath = Favicon::fetch('https://ashallendesign.co.uk')->storeAs('favicons', 'ashallendesign', 's3');

// $faviconPath is now equal to: "/favicons/ashallendesign.ico"

Caching Favicons

As well as being able to store favicons, the package also allows you to cache the favicon URLs. This can be extremely useful if you don't want to store a local copy of the file and want to use the external version of the favicon that the website uses.

As a basic example, if you have a page displaying 50 websites and their favicons, we would need to find the favicon's URL on each page load. As can imagine, this would drastically increase the page load time. So, by retrieving the URLs from the cache, it would majorly improve up the page speed.

To cache a favicon, you can use the cache method available on the Favicon class. The first parameter accepts a Carbon\CarbonInterface as the cache lifetime. For example, to cache the favicon URL of https://ashallendesign.co.uk for 1 day, your code might look something like:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$faviconPath = Favicon::fetch('https://ashallendesign.co.uk')->cache(now()->addDay());

By default, the package will always try and resolve the favicon from the cache before attempting to retrieve a fresh version. However, if you want to disable the cache and always retrieve a fresh version, you can use the useCache method like so:

use AshAllenDesign\FaviconFetcher\Facades\Favicon;

$faviconPath = Favicon::useCache(false)->fetch('https://ashallendesign.co.uk');

The package uses favicon-fetcher as a prefix for all the cache keys. If you'd like to change this, you can do so by changing the cache.prefix field in the favicon-fethcher config file. For example, to change the prefix to my-awesome-prefix, you could update your config file like so:

return [

    // ...
        
    'cache' => [
        'prefix' => 'my-awesome-prefix',
    ]
            
    // ...

]

Testing

To run the package's unit tests, run the following command:

composer test

To run Larastan for the package, run the following command:

composer larastan

Security

If you find any security related issues, please contact me directly at [email protected] to report it.

Contribution

If you wish to make any changes or improvements to the package, feel free to make a pull request.

To contribute to this package, please use the following guidelines before submitting your pull request:

  • Write tests for any new functions that are added. If you are updating existing code, make sure that the existing tests pass and write more if needed.
  • Follow PSR-12 coding standards.
  • Make all pull requests to the master branch.

Changelog

Check the CHANGELOG to get more information about the latest changes.

Credits

License

The MIT License (MIT). Please see License File for more information.

Comments
  • Allow element attributes in single quotes

    Allow element attributes in single quotes

    This fix tries to fetch favicon when icon href is using single quotes instead of double.

    Example: <link href='https://www.1a.lv/assets/themes/1a/favicon-c97bcf2fe300f089a14f027f6302d7d1bf0767561b811612e375f48dccdff6d0.ico' rel='shortcut icon' type='image/x-icon'>

    opened by marispro 6
  • Wrong file extension when storing the favicon.

    Wrong file extension when storing the favicon.

    Hi thanks for this nice package, but I think there is a problem. When storing the favicon in the storage I got this result :

    $favicon = Favicon::fetch('https://headlessui.com')->store('favicons', 'public');
    // 6f886546-edc2-4041-9a5c-8803f236ac25.com
    
    $favicon = Favicon::fetch('https://vuejs.org')->store('favicons', 'public');
    // favicons/bf4d32f3-fd86-4696-9a01-482d810da7f9.org
    
    $favicon = Favicon::fetch('https://remote.io')->store('favicons', 'public');
    // favicons/d0e9c6d4-2cd5-4abd-ac53-2fcad9ff817a.io
    

    The file extension follows the URL domain. that's should not be the case, it should be .png or other image formats.

    opened by misbahansori 5
  • Call to a member function cache() on null

    Call to a member function cache() on null

    Hello,

    If I run the following code which looks like it should work:

    use AshAllenDesign\FaviconFetcher\Facades\Favicon;
    Favicon::fetch("https://example.com/")->cache(now()->addWeek())->getFaviconUrl();
    

    It will crash with:

    [Error] Call to a member function cache() on null
    
    opened by gjsman 5
  • HttpDriver findLinkElement method

    HttpDriver findLinkElement method

    Hello,

    currently findLinkElement() function pattern is $pattern = '/<link.*rel="(icon|shortcut icon)"[^>]*>/i';

    however this does not work in all cases, because it might assume that this is favicon link:

    when we remove dot and asterisk (.*), then it works much better. However, I can not test all possible cases. $pattern = '/<link rel="(icon|shortcut icon)"[^>]*>/i';

    Any ideas why this pattern is how it is?

    opened by marispro 5
  • How to handle cURL error 6: Could not resolve host

    How to handle cURL error 6: Could not resolve host

    Hi! First of all, thanks for this great package.

    I'm building service which handles 500k+ domains and there are many domains that are not available. When this happens, we will get cURL error for "Could not resolve host".

    Any suggestions how to handle this error so that we will get favicon as null?

    Thanks!

    opened by markoman78 2
  • Remove incorrect mime type and extension

    Remove incorrect mime type and extension

    When I originally added this list, I used a list from a Stack Overflow post. It looks like I accidentally left a text/calendar mime type in there accidentally.

    This PR removes the incorrect mime type 🙂

    opened by ash-jc-allen 0
  • Fix HTTP driver bug if multiple link elements are on the same line

    Fix HTTP driver bug if multiple link elements are on the same line

    This PR fixes a bug in the HTTP driver that was using the wrong <link> tag while parsing the HTML.

    This bug happened if there were multiple <link> tags on the same line in the HTML. The preg_match function was grabbing the entire line and then we were returning the first link in the matches. So, this would return whichever link element was the first on the line.

    Now, the code will explode the line and loop through the links to find the "icon" or "shortcut icon" element.

    opened by ash-jc-allen 0
Releases(v1.2.1)
  • v1.2.1(Nov 8, 2022)

    What's Changed

    • Fixed bug that prevented a favicon URL from being detected using the HttpDriver if the favicon URL was using single quotes (instead of double quotes) by @marispro in https://github.com/ash-jc-allen/favicon-fetcher/pull/20

    New Contributors

    • @marispro made their first contribution in https://github.com/ash-jc-allen/favicon-fetcher/pull/20

    Full Changelog: https://github.com/ash-jc-allen/favicon-fetcher/compare/v1.2.0...v1.2.1

    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Oct 17, 2022)

    What's Changed

    • Added support for PHP 8.2 by @ash-jc-allen in https://github.com/ash-jc-allen/favicon-fetcher/pull/21

    Full Changelog: https://github.com/ash-jc-allen/favicon-fetcher/compare/v1.1.3...v1.2.0

    Source code(tar.gz)
    Source code(zip)
  • v1.1.3(Sep 3, 2022)

    What's Changed

    • Remove incorrect mime type and extension by @ash-jc-allen in https://github.com/ash-jc-allen/favicon-fetcher/pull/19

    Full Changelog: https://github.com/ash-jc-allen/favicon-fetcher/compare/v1.1.2...v1.1.3

    Source code(tar.gz)
    Source code(zip)
  • v1.1.2(Jul 23, 2022)

    What's Changed

    • Fixed bug that was using the wrong file extension when storing favicons by @ash-jc-allen in https://github.com/ash-jc-allen/favicon-fetcher/pull/17

    Full Changelog: https://github.com/ash-jc-allen/favicon-fetcher/compare/v1.1.1...v1.1.2

    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(May 10, 2022)

    What's Changed

    • Fixed bug that was returning the incorrect favicon URL in the HttpDriver if multiple <link> elements existed on the same line in the webpage's HTML. (#13)

    Full Changelog: https://github.com/ash-jc-allen/favicon-fetcher/compare/v1.1.0...v1.1.1

    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Apr 27, 2022)

    What's Changed

    • Added an Unavatar driver by @ash-jc-allen in https://github.com/ash-jc-allen/favicon-fetcher/pull/8

    Full Changelog: https://github.com/ash-jc-allen/favicon-fetcher/compare/v1.0.0...v1.1.0

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Apr 26, 2022)

Owner
Ash Allen
Laravel Web Developer Preston, United Kingdom
Ash Allen
A wiki to ease developers' work by providing a user authentication librariesthat can be used as middleware within a web application to authenticate

A wiki to ease developers' work by providing a user authentication librariesthat can be used as middleware within a web application to authenticate (their application user) requests.

Zuri Training 6 Aug 8, 2022
Phantom Analyzer scans websites for spy pixels. It runs via Laravel Vapor using Browsershot.

Phantom Analyzer Phantom Analyzer was a tool we launched during Halloween 2020. It's a much simpler version of Blacklight by The Markup and we had so

Fathom Analytics 105 Dec 18, 2022
Admidio is a free open source user management system for websites of organizations and groups

Admidio is a free open source user management system for websites of organizations and groups. The system has a flexible role model so that it’s possible to reflect the structure and permissions of your organization.

Admidio 214 Jan 1, 2023
Create Portfolio websites

Porfolio This repo contains a portfolio that showcases examples of your work along with the usual resume information about your work experience. To vi

Manasi Patil 2 Mar 6, 2022
RSS-Bridge is a PHP project capable of generating RSS and Atom feeds for websites that don't have one

RSS-Bridge is a PHP project capable of generating RSS and Atom feeds for websites that don't have one. It can be used on webservers or as a stand-alone application in CLI mode.

RSS Bridge Community 5.5k Dec 30, 2022
Open Source Voucher Management System is a web application for manage voucher. used PHP with Laravel Framework and use MySQL for Database.

Voucher Management System is a web application for manage voucher. You can create and manage your voucher. Voucher Management System is used PHP with Laravel Framework and use MySQL for Database.

Artha Nugraha Jonar 34 Sep 17, 2022
A Zabbix 5.4 module to group items under Monitoring -> Latest data per Tag as it used to be with Application grouping in previous versions of Zabbix

zabbix-module-latest-data Written according to Zabbix official documentation https://www.zabbix.com/documentation/current/manual/modules A Zabbix 5.4

BGmot 18 Dec 6, 2022
A learning management system (LMS) is a software application or web-based technology used to plan, implement and assess a specific learning process.

vidyaprabodhan-gov-php-project A learning management system (LMS) is a software application or web-based technology used to plan, implement and assess

Narayan Pote 1 Dec 23, 2021
This prj we have two NODEMCU ( ESP8266) and two RFID_RC522 and some rfid tags we used ARDUINO IDE on NODEMCU and running server with XAMPP

This prj we have two NODEMCU ( ESP8266) and two RFID_RC522 and some rfid tags we used ARDUINO IDE on NODEMCU and running server with XAMPP

Mohammadamir Soltanzadeh 2 Mar 29, 2022
DomainMOD is an open source application written in PHP & MySQL used to manage your domains and other internet assets in a central location

DomainMOD is an open source application written in PHP & MySQL used to manage your domains and other internet assets in a central location. DomainMOD also includes a Data Warehouse framework that allows you to import your web server data so that you can view, export, and report on your live data.

DomainMOD 349 Jan 8, 2023
WebFit was initially thought for the subject of Systems Analysis and Design, and consists of a site that is used by customers of a fictitious gym

WebFit - Um site para academia Sobre o site O WebFit foi pensado inicialmente para a matéria de Análise e Projeto de Sistemas, e consiste em um site q

Gianluca Notari Magnabosco 2 Sep 12, 2022
Class used for health analysis results. It returns BMI, BMR, TDEE, Pollock 7 sinfolds stats (body fat, body density, lean mass, fat mass)

php-health Class used for health analysis results. It returns BMI, BMR, TDEE, Polock 7 sinfolds stats (body fat, body density, lean mass, fat mass) Th

Vinicius Marques de Souza 2 Oct 5, 2022
A great looking and easy-to-use photo-management-system you can run on your server, to manage and share photos.

Lychee A great looking and easy-to-use photo-management-system. Since the 1st of April 2018 this project has moved to it's own Organisation (https://g

Tobias Reich 6.2k Jan 5, 2023
Server manager is a open source project made for people so that they can add the servers to one single place irrespective of their provider and manage it through one location.

Server Manager Are you sick of having to log into hundreads of different website just to access your server? Well we got you, Server manager is a open

null 8 Aug 9, 2022
This is a Task Manager system for managing your task. You can categorize your tasks and upload music to the project And a whole host of other features

taskManager Login and register Each user can have their own task Categorize tasks by creating folders Edit and Delete Folders Search for Tasks Show nu

masoudharooni 11 May 22, 2022
Build a health check report that can be verified with Oh Dear

Create a health check report to be verified by Oh Dear Using this package you can build up the JSON that Oh Dear expects for the health check. Install

Oh Dear 5 Oct 6, 2022
A blog website where you can create/edit/delete blogs.

A blog website where you can create/edit/delete blogs. All the data will be caught from the DB, but here's the catch: I'm doing this project in Laravel 8.

null 1 Dec 8, 2021
User input collection of recipes that can be filtered to meet certain criteria or to return a random recipe.

How to use: Install xampp: https://www.apachefriends.org/index.html and PHP Unzip the repo in the C:/xampp/htdocs directory Run xampp and turn on the

kristiyan 1 Jan 27, 2022