Hitokoto一言API及微软Bing每日壁纸API的实现

一言网(Hitokoto.cn)创立于2016年,隶属于萌创Team,目前网站主要提供一句话服务。“动漫也好、小说也好、网络也好,不论在哪里,我们总会看到有那么一两个句子能穿透你的心。我们把这些句子汇聚起来,形成一言网络,以传递更多的感动。如果可以,我们希望我们没有停止服务的那一天。” 简单来说,一言指的就是一句话,可以是动漫中的台词,也可以是网络上的各种小段子。或是感动,或是开心,有或是单纯的回忆,与大家分享,这就是一言存在的目的。

Hitokoto一言API

下面简单介绍本站部署Hitokoto一言API的过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
//Ps:喜欢使用官方接口也可以前往官方的API介绍地址参考部署:https://hitokoto.cn/api
//获取句子文件的绝对路径
//如果你介意别人可能会拖走这个文本,可以将文件名自定义一下,或者通过配置文件权限,禁止Nginx拉取也行。
$path = dirname(__FILE__);
$file = file($path."/hitokoto.txt");

//随机读取一行
$arr = mt_rand( 0, count( $file ) - 1 );
$content = trim($file[$arr]);

//编码判断,用于输出相应的响应头部编码
if (isset($_GET['charset']) && !empty($_GET['charset'])) {
$charset = $_GET['charset'];
if (strcasecmp($charset,"gbk") == 0 ) {
$content = mb_convert_encoding($content,'gbk', 'utf-8');
}
} else {
$charset = 'utf-8';
}
header("Content-Type: text/html; charset=$charset");

//格式化判断,输出js或纯文本
if ($_GET['format'] === 'js') {
echo "function hitokoto(){document.write('" . $content ."');}";
} else {
echo $content;
}
/**以上代码保存为index.php,然后上传到网站根目录下的hitokoto文件夹(这个自己随机定义)即可。
*把hitokoto.txt上传至网站目录,并写入相应内容。
*尽管如此,倘若有高并发请求的业务需求,推荐使用MySQL来进行内容管理。
*/

现在,通过域名/路径就可以看到返回的结果了。[https://mydomain.com/hitokoto]
部署方法如下所示:

1
2
<script type="text/javascript" src="https://你的域名/hitokoto/?format=js&charset=utf-8"></script>
<div id="hitokoto"><script>hitokoto()</script></div>

微软Bing每日壁纸API

必应美图官方的 API 接口如下:

1
2
3
4
5
6
7
8
//国内版
https://cn.bing.com/HPImageArchive.aspx?idx=0&n=1
https://cn.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN
//国际版[From: https://stackoverflow.com/questions/10639914/is-there-a-way-to-get-bings-photo-of-the-day]
https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1
XML: https://www.bing.com/HPImageArchive.aspx?format=xml&idx=0&n=1&mkt=en-US
JSON: https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=en-US
RSS: https://www.bing.com/HPImageArchive.aspx?format=rss&idx=0&n=1&mkt=en-US

其中参数说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
参数名称                值含义

format(非必需) 返回数据格式,未定义则默认返回XML格式
•js(常使用,返回JSON格式)
•xml(返回XML格式)

idx(非必需) 请求图片截止天数
•0(今天)
•-1(截止到明天,预准备)
•1(截止至昨天,最多支持获取7天前的图片)

n(必需) 1-8返回请求数量,目前最多一次获取8张

mkt(非必需) 国家/地区代码
•zh-CN(中国)
•en-US(美国)

根据官方API返回的内容,对域名和url字段进行拼接即可得到图片地址。该.php文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
/**
Template Name: API-BingPicture
description: template for TOMORROW 星辰
https://www.tomorrow.wiki/archives/453
*/
if(file_exists("bingDaily.jpg"))
{
$time = time();

//文件修改时间和现在时间相差 24 小时以下的话,直接导向静态文件 jpg,否则重新生成 jpg
if($time - filemtime("bingDaily.jpg") < 24*60*60 )
{
header("Location:./bingDaily.jpg");
exit();
}
}

$str=file_get_contents('https://cn.bing.com/HPImageArchive.aspx?idx=0&n=1');
if (preg_match("/(.+?)<\/url>/ies", $str, $matches))
{
$imgurl='https://cn.bing.com'.$matches[1];
}
ob_end_clean();
ob_start();
header('Content-Type: image/JPEG');
@readfile($imgurl);
$temp = ob_get_contents();
@ob_flush();
$fp = fopen("bingDaily.jpg",'w');
fwrite($fp,$temp) or die('写文件错误');
header("Location:./bingDaily.jpg");
exit();
?>

最后,附上两条集成的API(对API进行外部资源引用注意Nginx的跨域配置问题):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//已拦截跨源请求:同源策略禁止读取位于 https://api.kixcs.com/hitokoto/?encode=json 的远程资源。
(原因:CORS 头缺少 'Access-Control-Allow-Origin')。
//.php文件中,开启跨域Ajax支持。
header('Access-Control-Allow-Origin:*');

//或者Nginx配置
location / {
# 允许 所有头部 所有域 所有方法
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Headers' '*';
add_header 'Access-Control-Allow-Methods' '*';
# OPTIONS 直接返回204
if ($request_method = 'OPTIONS') {
return 200;
}
}
1
2
https://api.kixcs.com/hitokoto/
https://api.kixcs.com/bing

备选方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
define('IN_HITOKOTO', TRUE);
header('Content-Type: text/html; charset=UTF-8');
//开启跨域Ajax支持
header('Access-Control-Allow-Origin:*');
//初始化资源文件
$array = file('./content.php');
//参数传递
$encode = $_GET['encode'];
$id = $_GET['id'];
//一言开始行数(0为验证行)
$id_min = 1;
//一言结束行数
$id_max = 3388;
//随机 - 判断数字
if (!$id == NULL && is_numeric($id))
{
//判断大小
if ($id >= $id_min && $id <= $id_max)
{
$number = $id;
}
else
{
$number = rand($id_min,$id_max);
}
}
else
{
$number = rand($id_min,$id_max);
}
$string = $array[$number];
//判断输出类型
if ($encode == 'javascript' || $encode == 'js')
{
echo 'function getHitokoto(){document.write("',trim($string),'");}';
}
else
{
echo trim($string);
}
1
2
3
4
5
6
7
//使用UTF-8-BOM编码(content.php),注意一言文本行数要与index.php中的$id_max匹配。
<?php if(!defined('IN_HITOKOTO')){echo "Access Denied.";exit();};?>
你们媒体千万要注意啊,不要“见着风,是得雨”啊。
接到这些消息,你媒体本身也要判断,明白意思吗?
假使这些完全……无中生有的东西,你再帮他说一遍,你等于……你也等于……你也有责任吧?
..........
..........

请求方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$id
Normal: Random ID
Option: $id_min ~ $id_max
Request URL: https://api.kixcs.com/hitokoto/?id=2
Request Method: GET
Respond:接到这些消息,你媒体本身也要判断,明白意思吗?
(The id of this sentence is 2.)

$encode
Normal: text
Option: javascript or js
Request URL: https://api.kixcs.com/hitokoto/?encode=js
Request Method: GET
Respond:function getHitokoto(){document.write("我没有说要钦定,没有任何这个意思。");}

前端页面中,使用如下代码进行调用:

1
2
<script type="text/javascript" src="https://api.kixcs.com/hitokoto/?encode=javascript"></script> 
<span class="getHitokoto"><script>getHitokoto()</script></span>

注意,倘若控制台出现:"Refused to execute script from because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled."类似错误,JS的MIME的type="text/javascript"配置正确,则有可能是CDN引发的问题。

1
https://github.com/rails/webpacker/issues/1651