用PHP实现线上P四六级成绩单

闲来无事想做个东西耍,恰逢四六级即将出分,那便做一个生成假冒四六级的小玩意吧。
Demo:生成假四六级成绩单

准备图片

首先,我们当然是需要一个被处理过的成绩单的截图啦,用ps修改后,得到下面这个图。

PHP实现向图片写入文字

之后就该考虑如何采集修改者的信息并将其写到图片上了,恰好在B站看到了一个相关的视频:av(视频已失效),了解到php中imagettftext可以向图片写入字符串。
其语法为

1
imagettftext(底图,字号,旋转角度,X轴坐标,Y轴坐标,字体颜色,字体文件,要写入的字符串);

颜色必须使用RGB格式,否则会运行错误造成HTTP500.

因此上图即可通过下面实现,
新建一个php文档,取名CreatPic.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
<?php 
header("content-type: image/jpeg;");
//打开文件
$dst_path="bg.jpg";
$dst=imagecreatefromstring(file_get_contents($dst_path));

//定义样式
$color1 = imagecolorallocate($dst, 48, 131, 199); //蓝色,用于姓名、学校、年份
$color2 = imagecolorallocate($dst, 215, 30, 4); //红色,用于总分
$color3 = imagecolorallocate($dst, 124, 124, 124); //灰色,用于三科成绩

$font1='msyh.ttc';
$font2='msyhbd.ttc';

//定义文字
$year = "2018";
$name = "northword";
$school = "sxu";
//下几个参数同样

//向图片写入文字
imagettftext($dst,27,0,75,112,$color1,$font1,$year);
imagettftext($dst,19,0,310,225,$color1,$font1,$name);
imagettftext($dst,19,0,310,285,$color1,$font1,$school);
imagettftext($dst,25,0,310,500,$color2,$font2,$total);
imagettftext($dst,20,0,460,555,$color1,$font1,$score1);
imagettftext($dst,20,0,460,615,$color1,$font1,$score2);
imagettftext($dst,20,0,460,675,$color1,$font1,$score3);
//生成图片
imagejpeg($dst);
imagedestroy($dst);
?>

运行效果如下:

运行效果图

核心部分已经实现了,接下来我们实现采集用户信息并将其传送到php中。

HTML表单采集需要的信息

我们在这个PHP最后追加如下:

1
2
3
4
5
6
7
8
9
<form>
年份:<input type="text" name="year" placeholder="年份" value="2018"></br>
姓名:<input type="text" name="name" placeholder="姓名" ></br>
学校:<input type="text" name="school" placeholder="学校"></br>
听力:<input type="text" name="score1" placeholder="听力" id="score1" ></br>
阅读:<input type="text" name="score2" placeholder="阅读" id="score2" ></br>
写作和翻译<input type="text" name="score3" placeholder="写作和翻译:" id="score3"></br>
<input type="submit" value="确定">
</form>

这时候运行会得到一个表单,填写后会发现URL发生了变化,说明form写正确了。

1
http://www.northword.cn/cet-funny/1/index2.php?year=2018&name=1&school=0&score1=0&score2=0&score3=20

现在让php接受html传递的数据,把php“定义文字”部分的代码改更为:

1
2
3
4
5
6
7
8
9
$year=$_GET["year"];
$name=$_GET["name"];
$school=$_GET["school"];
$score1=$_GET["score1"]; //听力
$score2=$_GET["score2"]; //阅读
$score3=$_GET["score3"]; //写作翻译
$total=$_GET["score1"]+$_GET["score2"]+$_GET["score3"]; //总分
$grade=$_GET["grade"];
$session=$_GET["session"];

运行效果如下:
传值运行效果
到了这就已经基本完成目标需求了,接下来我们来完善一下细节。

其他细节

计算总分

我们发现在输入的时候“总分”是需要用户自行计算的,那能不能我们获取用户输入的三科成绩自动求和并显示在页面上呢?想到了监听文本框值的变化:oninput是监听文本框值变化,有变化触发onInput(event)事件,事件中通过id获取id为score1、score2、score3的元素的值,求和后赋给id为total的html元素。
给三科成绩的输入框添加Id和事件:

1
2
3
4
5
<input type="text" name="score1" id="score1" placeholder="听力" oninput="OnInput (event)" id="score1" ></br>
<input type="text" name="score2" id="score2" placeholder="阅读" oninput="OnInput (event)" id="score2" ></br>
<input type="text" name="score3" id="score3" placeholder="写作和翻译:" oninput="OnInput (event)" id="score3"></br>

当前总分:<a id="total"></a><br>

添加如下脚本,

1
2
3
4
5
6
<script type="text/javascript">
//当听力、阅读、写作的输入框值变化时计算总分并赋给id为total的元素
function OnInput (event) {
document.getElementById("total").innerHTML=(parseInt(document.getElementById("score1").value)+parseInt(document.getElementById("score2").value)+parseInt(document.getElementById("score3").value));
}
</script>

如此便解决了这个细节。

自适应页面

在手机端查看的时候不能自动缩放到合适的尺寸,搜索了一番,在里加上一行如下代码最简便,原理不知道。

1
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=yes">

选择等级的单选框

我们发现无法选择考试等级和场次,给表单中加个radio,并给php中加上相应的变量即可。
在这里需要注意的是label和radio之间可以用id连接,以便用户点击文字的时候也可以选上。
《from中单选点击文字即可选中选项的方法(radio与lable的连接)》

对正文本框

然后我们发现文本框对不齐,我们给他加一个表格以使它对齐。

js控制的传值

发现点击提交之后跳转到php图片那里无法再跳转回去,能不能不跳转实现传递数据呢,可以通过js。
《HTML form与php间传值的几种方法》

CSS控制图片显示隐藏

通过上面设置后发现在用户输入前图片也是被展示的,这样不好,我们应该让输入前没有图片,提交后再出现图片。

我们把结果页的全部放进一个div容器里,class="img-container",表单页放进一个<div class="form-container">里,给提交按钮添加事件使点击提交时隐藏form-container,显示img-container,这个可以通过更改div的css实现。

1
2
3
4
5
6
7
8
9
10
function showimg() {
//显示返回的图片
document.getElementById('div-img').style.display='block';
document.getElementById('div-from').style.display='none';
}
//返回重填按钮事件:隐藏图片,显示表单
function hiddenimg(){
document.getElementById('div-img').style.display='none';
document.getElementById('div-from').style.display='block';
}

如此基本完成了一个还算说得过去的东西。