0x00

好长时间没水文章了呢
今天再来糊弄一篇(
众所周知,必应每天的背景图片都不一样

bing-bg
bing-bg

如何获取这个背景图片来做其它用途呢(如网站头图)
application
application

0x01

要整到这个图片,首先要获得它的url或uri
分析一下页面元素

bing-bguri
bing-bguri

首页这里有个uri,这里就是它的背景uri了
世界上最好的编程语言写个api,我们就能用辣
开始写代码之前,我们先看看这个uri有什么特征:
symbols
symbols

w=1920 h=1080,也就是说这个uri还可以让图片变大变小
找到这个之后,我们就能开始整活了

$width=$_GET['w'];
$height=$_GET['h'];

先通过get参数获取用户需要的长宽,不多b

$cachedir=__DIR__."/cache/";
$cachetoday=$cachedir.date('Ymd').'-'.$width.'-'.$height.'.jpg';
//if cache file exists
if(file_exists($cachetoday)){
    goto readcache;
}else{
    goto onlinefetch;
}

为了节省服务器流量以及提高加载速度,我们可以缓存已经下载下来的图片文件。为了区分,缓存文件以日期和分辨率标识。比如今天有人请求了一个1920*1080的图片,它的缓存文件名就是20201008-1920-1080.jpg。
若明天有人再次请求,缓存文件名就变成了20201009-1920-1080.jpg,而本地并没有这样的缓存,if语句便会执行onlinefetch清空缓存并重新生成缓存文件。
__DIR__会返回当前php脚本的路径,不多b。

readcache:
showImg($cachetoday);
//terminate the current script 2 avoid fetching image online
exit();
// function showImg(string $img):void
function showImg($img){
    $info = getimagesize($img);
    $imgExt = image_type_to_extension($info[2], false);
    $fun = "imagecreatefrom{$imgExt}";
    $imgInfo = $fun($img);
    $mime = image_type_to_mime_type(exif_imagetype($img));
    header('Content-Type:'.$mime);
    $quality = 100;
    if($imgExt == 'png') $quality = 9;
    $getImgInfo = "image{$imgExt}";
    $getImgInfo($imgInfo, null, $quality);
    imagedestroy($imgInfo);
}

这里定义了一个showImg函数。因为api需要直接返回图片而不能是下载文件,因此需要php安装exif扩展,并使用里面的功能指定Content-Type的返回头。

return-image-directly
return-image-directly

这里我使用php标记功能而不是定义一个新函数,原因就是我喜欢这样(
它和函数的区别就是:程序调用完函数后,脚本运行位置会返回调用处

function 1(){
echo '1';
}
function 2(){
echo '2';
}
1();

//程序输出:
// 1
//即调用完1函数后运行位置返回调用处,从调用处往下执行

而php标记则是直接把脚本运行位置跳转到一个地方

goto 1;
1:
echo '1';
2:
echo '2';
//程序输出:
// 1
// 2
// 若标记处代码运行完毕未作其它操作,脚本会接着往下执行

因此我们运行完readcache后要使用exit()来退出脚本,以免往下执行刷新当日缓存。

onlinefetch:
//clear local cache
cleancache($cachedir);
// function cleancache(string $cachepath):void
function cleancache($cachepath){
    $dirarray=scandir($cachepath);
    foreach($dirarray as $filename){
        if(is_dir($cachepath.$filename)==false)
        unlink($cachepath.$filename);
    }
} 

过了一天,所有的缓存文件都已过时,我们需要遍历缓存目录把它们全部删除。
需要注意的是,scandir()返回的结果除了当前目录,还有.和..(指向当前目录和上级目录),我们需要用is_dir()把它们排除掉,否则unlink()会返回E_WARNING级的错误,影响返回数据。

//get bing html
$bingcode=file_get_contents('https://cn.bing.com/');
//get bing bgimg uri
$bing_bguri=getSubStr($bingcode,'<div id="bgImgProgLoad" data-ultra-definition-src="','" data-explicit-bing-load=');
function getSubStr($str, $leftStr, $rightStr)
{
    $left = strpos($str, $leftStr);
    $right = strpos($str, $rightStr,$left);
    if($left < 0 or $right < $left) return '';
    return substr($str, $left + strlen($leftStr), $right-$left-strlen($leftStr));
}

这里定义了getSubStr函数,用于取出一个字符串中间的文本。其中,$str是包含所需文本的字符串(即bing前端代码),$leftStr是它左边的文本(用于标记),$rightStr是它右边的文本。
bing这个背景图片标签非常的有特点,随便一看就能找出来,把它们传进getSubStr即可获取图片uri

//process
if($width!=''){
    $bing_bguri=str_replace('w=1920','w='.$width,$bing_bguri);
}
if($height!=''){
    $bing_bguri=str_replace('h=1080','h='.$height,$bing_bguri);
}
$bing_bgurl='https://cn.bing.com'.$bing_bguri;

这里就利用之前的get参数并替换uri里面的长、宽数值来获取指定大小的图片
然后和bing主域名拼接在一起形成完整url

//fetch image
$bingbg=file_get_contents($bing_bgurl);
file_put_contents($cachetoday,$bingbg);
//display
showImg($cachetoday);

然后获取图片并存入缓存,接着把图片展示给用户
这个api就算完成了,全部代码:

/*
 *GetBingDailyBackgroundImage(DailyBimg)
 *Author: LtD0gE
 */
// function getSubStr(string str,string leftStr,string rightStr):string
function getSubStr($str, $leftStr, $rightStr)
{
    $left = strpos($str, $leftStr);
    $right = strpos($str, $rightStr,$left);
    if($left < 0 or $right < $left) return '';
    return substr($str, $left + strlen($leftStr), $right-$left-strlen($leftStr));
}
// function showImg(string img):void
function showImg($img){
    $info = getimagesize($img);
    $imgExt = image_type_to_extension($info[2], false);
    $fun = "imagecreatefrom{$imgExt}";
    $imgInfo = $fun($img);
    $mime = image_type_to_mime_type(exif_imagetype($img));
    header('Content-Type:'.$mime);
    $quality = 100;
    if($imgExt == 'png') $quality = 9;
    $getImgInfo = "image{$imgExt}";
    $getImgInfo($imgInfo, null, $quality);
    imagedestroy($imgInfo);
}
// function cleancache(string cachepath):void
function cleancache($cachepath){
    $dirarray=scandir($cachepath);
    foreach($dirarray as $filename){
        if(is_dir($cachepath.$filename)==false)
        unlink($cachepath.$filename);
    }
} 
$width=$_GET['w'];
$height=$_GET['h'];
$cachedir=__DIR__."/cache/";
$cachetoday=$cachedir.date('Ymd').'-'.$width.'-'.$height.'.jpg';
//if cache file exists
if(file_exists($cachetoday)){
    goto readcache;
}else{
    goto onlinefetch;
}
readcache:
showImg($cachetoday);
//terminate the current script 2 avoid fetching image online
exit();
onlinefetch:
//clear local cache
cleancache($cachedir);
//get bing html
$bingcode=file_get_contents('https://cn.bing.com/');
//get bing bgimg uri
$bing_bguri=getSubStr($bingcode,'<div id="bgImgProgLoad" data-ultra-definition-src="','" data-explicit-bing-load=');
//process
if($width!=''){
    $bing_bguri=str_replace('w=1920','w='.$width,$bing_bguri);
}
if($height!=''){
    $bing_bguri=str_replace('h=1080','h='.$height,$bing_bguri);
}
$bing_bgurl='https://cn.bing.com'.$bing_bguri;
//fetch image
$bingbg=file_get_contents($bing_bgurl);
file_put_contents($cachetoday,$bingbg);
//display
showImg($cachetoday);
//exit but effects nothing :)
exit();
示例地址:https://source.littledoge.top/api/dailybimg.php?w=长&h=宽

此API已停止服务。
也可把get参数去掉,默认获取1920*1080图片

0x02

咕咕咕