通过 PHP 自动获取 favicon.ico 网站的图标
做了一个网址导航:导航 - 四六导航
在补充网站的时候遇到一个很麻烦的事情,我需要手动获取各个网站的 ico 图标,没有图标的话,导航还是挺不好看的。于是我百度了一下,找到一个通过 php 解决的方案。
解决方案
在网站 function
里,我增加了 ico
的功能文件夹,然后新建了一个 index-php
,把下面的代码放在了 index.php
中:
<?php
/**
* php 获取网站 favicon 图标
*/
$url = getParam('url'); //获取传过来的链接参数
$type = getParam('type'); //获取传过来的链接参数
if(empty($url)){die('?url=https://www.baidu.com and &type=1 get base64');}
if(substr($url, 0, 4) != 'http'){$url = 'http://'.$url;}
if(empty($type)){header('Content-type: image/x-icon');}//输出的是图标格式
$content=geticon($url,$type);
if(empty($content)){
$content=threeapi($url);
if($content && !empty($type))$content=base64EncodeImage($content);
}
if(empty($content)){echo default_ico($type);return;}
echo $content;return;
function getcachedir(){
$dir = './cache';
if (!is_dir($dir)) mkdir($dir,0777,true) or die('创建缓存目录失败!');
return $dir;
}
function geticon($url,$type=0){
if(empty($url))return '';
if(isUrl($url) != '1'){return default_ico($type);}$http = '';
if(substr($url, 0, 5) == 'https'){$http = 'https://'; } //如果是 https 头,传到后面取图标时加上。防止出现 302 重定向
$arr = url_parse($url);$domain = $arr['host']; //分解目标域名
$fav =$arr['fav']; //图标保存的路径和名称
//调用缓存文件
if (file_exists($fav)){ //有缓存就直接输出缓存
$file = file_get_contents($fav);
if($file) return $type?base64EncodeImage($file):$file;
}
$check1=getFav($http.$domain."/favicon.ico");if($check1) {cachefile($url,$check1); return $type?base64EncodeImage($check1):$check1;}//第一次尝试 根目录
$curl = get_url_content($url);//尝试读取内容并匹配 ico 文件
$file = $curl['exec'];preg_match('|href\s*=\s*[\"\']([^<>]*?)\.ico[\"\'\?]|i',$file,$a); //正则匹配
if(!empty($a[1])){
$file2=$a[1] .='.ico';
if(!substr($file2,0,4)=='http'){//相对路径
if(substr($file2, 0, 1) == '/'){$file2 = substr($file2, 1);}
if(substr($file2, 0, 3) == '../'){$file2 = substr($a[1], 3);}
if(substr($a[1], 0, 2) == './'){$file2 = substr($file2, 2);}
$file2 = $http.$domain.'/'.$file2;//手动加上链接再试一次
}
$check2=getFav($file2);if($check2) {cachefile($url,$check2);return $type?base64EncodeImage($check2):$check2;}//第二次尝试
}return '';
}
function url_parse($url){
$arr = parse_url($url);$dir = getcachedir();
$arr['fav']=$dir."/".$arr['host'].".ico";
return $arr;
}
function cachefile($url,$content){
if(empty($url) || empty($content))return false;
$arr = url_parse($url);
file_put_contents($arr['fav'],$content);
}
function threeapi($url,$type=0){
$urls=array(
'http://api.byi.pw/favicon/?url='.$url,
'http://cdn.website.h.qhimg.com/index.php?domain='.$url,
);
if(!empty($urls[$type])){
$check1=getFav($urls[$type]);
if($check1) {cachefile($url,$check1);return $check1;}else return threeapi($urls[($type+1)]);
}return false;
}
/**
* 获取 favion 图标
*/
function getFav($url){
$curl = get_url_content($url);
$file = $curl['exec']; //获取到的文件
$zt = $curl['getinfo']; //状态
if($file && $zt['http_code'] == '200'){return $file;} //有文件,并且返回状态为 200
return false;
}
function default_ico($type=0){
$file = "null.ico";
$data = file_get_contents($file);
return $type?base64EncodeImage($data):$data;
}
/**
* 获取 GET 或 POST 过来的参数
* @param $key 键值
* @param $default 默认值
* @return 获取到的内容(没有则为默认值)
*/
function getParam($key,$default=''){
return trim($key && is_string($key) ? (isset($_POST[$key]) ? $_POST[$key] : (isset($_GET[$key]) ? $_GET[$key] : $default)) : $default);
}
//将图片转化成 base 编码
function base64EncodeImage ($image_data,$mime='image/png') {
$base64_image = 'data:' . $mime . ';base64,' . chunk_split(base64_encode($image_data));
return $base64_image;
}
/**
* curl 获取数据
* @param $bbb 目标 url 地址
* @return ['exec'] 获取的内容
* @return ['getinfo'] 返回的状态码
*/
function get_url_content($bbb) {
$ch = curl_init();
$timeout = 5000; //超时时间
curl_setopt ($ch, CURLOPT_URL, $bbb);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT_MS, $timeout);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // https 请求 不验证证书和 hosts
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt ($ch, CURLOPT_ENCODING, 'gzip'); //取消 gzip 压缩(代表:网易邮箱)
$file_info['exec']= curl_exec($ch);
$file_info['getinfo'] = curl_getinfo($ch); //判断状态 有的情况下无法正确判断 ico 是否存在
curl_close($ch);
return $file_info;
}
/**
* 判断字符串是否为域名
* @param $s 目标 url 地址
* @return
*/
function isUrl($s) {
return preg_match('/^http展开?:\/\/'.
'(([0-9]{1,3}\.){3}[0-9]{1,3}'. // IP形式的URL- 199.194.52.184
'|'. // 允许IP和DOMAIN(域名)
'([0-9a-z_!~*\'()-]+\.)*'. // 三级域验证- www.
'([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\.'. // 二级域验证
'[a-z]{2,6})'. // 顶级域验证.com or .museum
'(:[0-9]{1,4})?'. // 端口- :80
'((\/\?)|'. // 如果含有文件对文件部分进行校验
'(\/[0-9a-zA-Z_!~\*\'\(\)\.;\?:@&=\+\$,%#-\/]*)?)$/',
$s) == 1;
}
?>
使用方法也很简单
直接调用
域名 + /?url=目标网址
例如: https://blog.46cbm.top/function/favicon/?url=blog.46cbm.top
返回 base64 编码的图片信息
域名 + /?url=目标网址
&type=1
例如: https://blog.46cbm.top/function/favicon/?url=blog.46cbm.top&type=1
总结
虽然作为图标,部分的 ico 的清晰度不太好,但是至少强迫症的我,至少暂时没有了心头刺。
文章目录
打赏: 微信
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。