闲来无事,网址收藏夹在图标上加一个网站图标.
参考: 网址收藏夹
主要流程:

  1. 获取链接域名
  2. 通过域名查找主站的<link rel="icon" >
  3. 如果没找到寻找主域名+favicon.ico
  4. 下载favicon图片到本地,第二次加载时只找本地图片.
  5. 如果域名不可访问,取域名的首字母生成icon图片

代码如下:

<?php
declare(strict_types=1);
define("ROOT_PATH", dirname(__FILE__, 2));
const ICON_PATH = ROOT_PATH.'/runtime/icons';
const FONT_PATH = ROOT_PATH.'/assets/font/';


/**
 * @param string $sourceUrl 远程路径
 * @param string $filename 本地路径
 * @param $retry 重试次数
 * @return string|null
 */
function downloadImg(string $sourceUrl, string $filename, $retry = 1){

    $userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36';
    $temp = $filename . '.tmp';

    $resource = fopen($temp, 'w');
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $sourceUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
    curl_setopt($ch, CURLOPT_TIMEOUT, 3);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_AUTOREFERER, true);
    curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
    curl_setopt($ch, CURLOPT_DNS_CACHE_TIMEOUT, 60 * 60 * 24);
    curl_setopt($ch, CURLOPT_FILE, $resource);
    $httpCode = null;
    while ($httpCode !== 200 && $retry > 0) {
        $retry--;
        curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    }
    $type = curl_getinfo($ch,CURLINFO_CONTENT_TYPE);

    $result = null;
    // 判断是否成功
    if ($httpCode == 200 && str_contains($type,"image") ) {
        $remoteSize = (float)curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD);
        $localSize = (float)filesize($temp);
        $abs = abs($localSize - $remoteSize);
        if ($abs < 10 && $abs >= 0) {
            $result = rename($temp, $filename) ? $filename : null;
        }
    }

    curl_close($ch);
    fclose($resource);
    @unlink($temp);
    return $result;
}

/**
 * 读取图片
 * @param $file
 * @return void
 */
function readImg($file){

    $info=getimagesize($file);
    @ob_clean();
    @ob_get_contents();
    @ob_flush();
    header('Content-Type: '.$info['mime']);
    readfile($file);
}


function getFavicon($host) {
    $ctx = stream_context_create([
        'http' => [
            'timeout' => 3
        ]
    ]);
    $scheme='https://';
    $preg=<<<REG
/<link[^>]*href="([^>|\"]*)"[\s]*rel="[^>|\"]*icon"[^>]*\/?>|<link[^>]*rel="[^>]*icon"[\s]*href="([^>|\"]*)"[^>]*\/?>/si
REG;
    $icon="";
    $url=$scheme.$host;
    $fp = @fopen( $url, 'r' ,false,$ctx);
    if(!$fp){
        $scheme='http://';
        $url=$scheme.$host;
        $fp = @fopen( $url, 'r' ,false,$ctx);
    }
    if(!$fp){
        return false;
    }

    while(!feof($fp)){
        $line= fgets($fp);
        preg_match($preg, $line, $match );
        if($match && ($match[1]||$match[2])){
            $icon=$match[1]?$match[1]:$match[2];
            break;
        }
        if(str_contains($line, "/head>")){
            break;
        };
    }

    if(!$icon){
        return false;
    }

    if(filter_var($icon,FILTER_VALIDATE_URL)){
        return $icon;
    }

    if(strpos($icon,'//')===0){
        $icon=str_replace("//",$scheme,$icon);
        return $icon;
    }

    return $scheme.$host.$icon;
}

/**
 *
 * @param string $host
 * @return
 */
function outFontIcon(string $host){

    $hosts=explode('.',$host);
    if(count($hosts)>2){
        $text=$hosts[1];
    }else{
        $text=$hosts[0];
    }
    $randText=md5($host);
    $bgRed=min(255,hexdec(substr($randText,0,2))+80);
    $bgGreen=min(255,hexdec(substr($randText,16,2))+80);
    $bgBlue=min(255,hexdec(substr($randText,-1,2))+80);
    $text=ucfirst(substr($text,0,1));
    $img = imagecreatetruecolor(128, 128);
    $textcolor=imagecolorallocate($img, 0, 0, 0);
    $bgColor=imagecolorallocate($img, $bgRed, $bgGreen, $bgBlue);

    $font=realpath(FONT_PATH.'siyuan.ttf');
//    imagecolortransparent($img,$bgColor);
    imagefill($img,0,0,$bgColor);
//    imagestring($img, 5, 0, 0, $text, $textcolor);
    imagettftext($img, 80, 0, 25, 100, $textcolor, $font, $text);
    @ob_clean();
    header('Content-type: image/png');
    imagepng($img);
    imagedestroy($img);
}

$url=$_GET['u'];
$isURL=filter_var($url,FILTER_VALIDATE_URL);
$host=$url;
if($isURL){
    $host= parse_url($url,PHP_URL_HOST);
}else{
    $host= parse_url('http://'.$url,PHP_URL_HOST);
}
//$host="hi-arkin.com";

if(!is_dir(ICON_PATH) || !is_writable(ICON_PATH)){
    mkdir(ICON_PATH,0755,true);
}

$iconFile=ICON_PATH.DIRECTORY_SEPARATOR.$host;

// 本地图片
if(file_exists($iconFile)){
    readImg($iconFile);
    die();
}

// ping
if(function_exists('fsockopen')) {
    $ping = @fsockopen($host, 80, $errno, $errstr, 0.5);
    if (!$ping) {
        outFontIcon($host);
        die();
    }
    fclose($ping);
}

// 获取官网图标
$icon = getFavicon($host);
if(!$icon){
    $icon="http://".$host.'/favicon.ico';
}

// 下载图标
$icon=downloadImg($icon,$iconFile);
if($icon){
    readImg($icon);
    die();
}

// 直接域名英文
outFontIcon($host);

原作者:阿金
本文地址:https://hi-arkin.com/archives/favicon-php.html

标签: php favicon

(本篇完)

评论