【PHP】一步一步实现验证码

背景

验证码就是把一串随机产品的数字动态生成一幅图片,再加上干扰元素。此时用户可以通过肉眼能识别里面的数字或者字符,但是可以屏蔽机器的自动识别。

很多地方需要用到验证码,因为Web网站经常会遇到身份欺骗的攻击,攻击者通过在客户端脚本写入代码,写请求消耗远远大于读请求。大量写请求的情况,会严重耗费系统的资源。所以说验证码主要是防止有人利用机器人进行自动批量注册等行为。

笔者看过了http://www.imooc.com/learn/115
的视频教程以后非常有感触,想把实现验证码的步骤一步一步的记录下来。同时最后的时候他封装成类,可以在之后的工作中进行反复的利用。

其实验证码的代码已经研究了很多次了,但是大部分网上找到的教程都是一次性给出所有的代码,这样阅读的时候很难把握住笔者的开发思路,本教程希望一步一步的截图上代码,帮助新人理清思路。

验证码的核心技术

首先需要对实现验证码的步骤进行分解。主要可以分为如下几步:

  • 生成验证码底图
  • 生成随机字符,然后和底图合并
  • 当用户输入的时候,和原内容进行对比校验。
Paste_Image.png

接下来我们分不同的章节介绍如何实现每一个步骤。

环境

项目 内容
操作系统 windows
环境 xamp

需要启动Apache,验证方法是在浏览器框里输入127.0.0.1
如果出现如下的图片,则启动成功。


Paste_Image.png

实现验证码底图

首先是通过PHP实现100×30px大小的图片。
主要使用的函数方法:resource imagecreatetruecolor(int $width, int $height)
在D:\xampp\htdocs下建立project文件夹。新建captcha.php
输入:

<?php $image = imagecreatetruecolor(100,30);//生成资源 $bgcolor = imagecolorallocate($image , 255,255,255);//#ffffff,为一幅图像分配颜色 imagefill($image , 0 , 0 , $bgcolor);//左上角,区域填充 header("content-type:image/png"); imagepng($image); imagedestroy($image); ?>
在浏览器输入框输入http://127.0.0.1/project/captcha.php

Paste_Image.png

结果是一片大白。

下面解释一下里面涉及到的函数:

项目 内容
imagecreatetruecolor 生成空白的画布
imagecolorallocate 分配颜色
imagefill 填充颜色
header 发送HTTP头
imagepng 以png格式进行导出
imagedestory 输出结束的时候记得回收资源

为了表明各函数用法,特将PHP手册中的详细用法摘录如下:

  • imagecreatetruecolor — 新建一个真彩色图像
    resource imagecreatetruecolor ( int $width , int $height )
  • imagecolorallocate — 为一幅图像分配颜色
    int imagecolorallocate ( resource $image , int $red , int $green , int $blue )
    第一次对 imagecolorallocate() 的调用会给基于调色板的图像填充背景色,即用 imagecreate() 建立的图像。
    其他red,green,blue对应RGB值
  • imagefill — 区域填充
    bool imagefill ( resource $image , int $x , int $y , int $color )
    imagefill() 在 image 图像的坐标 x,y(图像左上角为 0, 0)处用 color 颜色执行区域填充(即与 x, y 点颜色相同且相邻的点都会被填充)。
  • header — 发送原生 HTTP 头
    void header ( string $string [, bool $replace = true [, int $http_response_code ]] )
    请注意 header() 必须在任何实际输出之前调用
  • imagepng — 以 PNG 格式将图像输出到浏览器或文件
    bool imagepng ( resource $image [, string $filename ] )
  • imagedestroy — 销毁图片资源
    bool imagedestroy ( resource $image )

注意事项:

  • 依赖于GD扩展,输出图片前必须提前输出图片header信息
  • 默认输出为黑色背景。

实现数字验证码

在上一章里面我们已经新建了一张画布,相当于把整个框架搭起来了,本章的主要目的是在上面加上随机的数字。
给图片加上数字,主要使用imagestring()方法。

imagestring — Draw a string horizontally
bool imagestring ( resource $image , int $font , int $x , int $y , string $string , int $color )

  • font:表示字体,
  • x,y:表示位置

从上面这个函数的参数可以看出,我们需要给出生成随机验证码数字的字体,位置,内容和颜色。
字体是死的,可以直接规定大小。

因为要生成4个随机数字,可以使用一个for循环for ($i = 0 ; $i < 4 ; $i++)

下面讨论怎么获得位置信息:
可以把长度100分成4份,所以每个数字的位置是($i * 100 / 4 ),然后加上随机的offset,可以得到
$x = ($i * 100 / 4 ) + rand (5,10);

内容通过:$fontContent = rand (0,9);获得。

最后是怎么获得随机的颜色:
对于imagecolorallocate()这个函数而言,只需要获得随机的RGB值,就可以实现随机的颜色了。为了更加醒目,我们限定随机RGB值的范围为0~120,因为是深色区间。

$fontColor = imagecolorallocate($image , rand(0,120) , rand(0,120), rand(0,120));//0~120是深色区间。

下面加上生成随机数字的代码段,在imagefill()那行下面加入:
<?php $image = imagecreatetruecolor(100,30);//生成资源 $bgcolor = imagecolorallocate($image , 255,255,255);//#ffffff,为一幅图像分配颜色 imagefill($image , 0 , 0 , $bgcolor);//左上角,区域填充 // 生成随机数字 for ($i = 0 ; $i < 4 ; $i++){ $fontSize = 6; $fontColor = imagecolorallocate($image , rand(0,120) , rand(0,120), rand(0,120));//0~120是深色区间。 $fontContent = rand (0,9); // 坐标 $x = ($i * 100 / 4 ) + rand (5,10);//总宽度100,放4个数字。 $y = rand (5 , 10); imagestring ($image,$fontSize,$x,$y,$fontContent,$fontColor); } header("content-type:image/png"); imagepng($image); imagedestroy($image); ?>

在地址栏里面输入127.0.0.1/project/captcha.php

Paste_Image.png

可以看出生成了4个随机的数字。

增加干扰元素

为了防止被机器轻易的读出来,可以增加干扰的元素。
先增加干扰的小点,用到函数
bool imagesetpixel(resource $image , int $x , int $y , int $color)

首先看点的位置怎么得到。
既然是随机生成用来干扰的点,那么可以在整个画布随机的跑,所以x = rand (1 , 99); y = rand (1 , 29)
而点的颜色注意要比字的浅,所以在50~200中选。

上代码,增加200个点。

<?php $image = imagecreatetruecolor(100,30);//生成资源 $bgcolor = imagecolorallocate($image , 255,255,255);//#ffffff,为一幅图像分配颜色 imagefill($image , 0 , 0 , $bgcolor);//左上角,区域填充 for ($i = 0 ; $i < 4 ; $i++){ $fontSize = 6; $fontColor = imagecolorallocate($image , rand(0,120) , rand(0,120), rand(0,120));//0~120是深色区间。 $fontContent = rand (0,9); // 坐标 $x = ($i * 100 / 4 ) + rand (5,10);//总宽度100,放4个数字。 $y = rand (5 , 10); imagestring ($image,$fontSize,$x,$y,$fontContent,$fontColor); } for ($i = 0 ; $i < 200 ; $i++){ $pointColor = imagecolorallocate ($image , rand (50,200),rand(50,200),rand(50,200));//颜色要比数字的浅。 imagesetpixel ($image , rand (1,99),rand(1,29),$pointColor);//生成的点不要超过画布。 } header("content-type:image/png"); imagepng($image); imagedestroy($image); ?>
依旧看看效果:

Paste_Image.png

再加点随机的线:
使用方法:bool imageline (resource $image , int $x1 , int $y1 , int $x2 , int $y2 , int $color)
手册上的解释是:
Draws a line between the two given points.
也就是说在给出的两点间画线。

注意随机线的颜色比随机点的颜色要更浅,所以在80~220里面选。
下面给出加随机线的代码:
// 生成干扰线 for ( $i = 0 ; $i < 3 ; $i++){ $lineColor = imagecolorallocate($image , rand (80,220),rand(80,220),rand(80,220)); imageline($image , rand (1,99),rand(1,29),rand(1,99),rand(1,29),$lineColor); }
结果如图:

Paste_Image.png

生成随机的字母和数字

之前生成的内容只有随机的数字,还是容易被机器识别出来,所谓道高一尺魔高一丈,对手在加码,我们也得加码撒。下面我们在随机的内容里面加上字母,这样组合更多,可以更好的屏蔽那些机器人。

首先我们把可能用到的字母和数字放到变量$data里面去,注意可以把容易混淆的字母和数字去掉,比如l和数字1容易混,所以直接干掉。

然后每次随机的从字符串里面抽一个出来,使用substr函数。
string substr ( string $string , int $start [, int $length ] )
从$string里$start位置抽出$length长的字符。

这样对原有的代码进行简单的修改就可以了。

<?php $image = imagecreatetruecolor(100,30);//生成资源 $bgcolor = imagecolorallocate($image , 255,255,255);//#ffffff,为一幅图像分配颜色 imagefill($image , 0 , 0 , $bgcolor);//左上角,区域填充 // 生成随机数字 for ($i = 0 ; $i < 4 ; $i++){ $fontSize = 6; $fontColor = imagecolorallocate($image , rand(0,120) , rand(0,120), rand(0,120));//0~120是深色区间。 // $fontContent = rand (0,9); $data = "abcdefghijkmnopqrstuvwxyz23456789"; // 生成随机的字母和数字,从$data字符串里面,任意一个位置,取一个字母 $fontContent = substr($data , rand(0,strlen($data)), 1); // 坐标 $x = ($i * 100 / 4 ) + rand (5,10);//总宽度100,放4个数字。 $y = rand (5 , 10); imagestring ($image,$fontSize,$x,$y,$fontContent,$fontColor); } for ($i = 0 ; $i < 200 ; $i++){ $pointColor = imagecolorallocate ($image , rand (50,200),rand(50,200),rand(50,200));//颜色要比数字的浅。 imagesetpixel ($image , rand (1,99),rand(1,29),$pointColor);//生成的点不要超过画布。 } // 生成干扰线 for ( $i = 0 ; $i < 3 ; $i++){ $lineColor = imagecolorallocate($image , rand (80,220),rand(80,220),rand(80,220)); imageline($image , rand (1,99),rand(1,29),rand(1,99),rand(1,29),$lineColor); } header("content-type:image/png"); imagepng($image); imagedestroy($image); ?>
效果如图

Paste_Image.png

通过session存储验证信息

session是存储的服务器端的信息,可以把生成的内容保存在服务器端的$_SESSION["authcode"]字段里面。当前端的用户输入相应的验证字符后,和$_SESSION["authcode"]进行对比,如果相同,自然证明输入正确、

需要在代码的最顶部加上session_start()

现在要考虑如何保存保存验证码的信息,先定义一个$captch_code 的空字符串,每生成一的随机的数字或者字符,都拼接到上面去。

其实在真实的开发环境下,我们都是用服务器的集群来保存session的,也就是说有可能第一次请求的时候建立的session保存在A服务器上,但是下次需要来拿数据的时候会被分配到B服务器上,所以校验会失败。在多服务器的情况下,我们需要考虑集中管理session,比如使用memcache来保存session信息。

<?php session_start(); $image = imagecreatetruecolor(100,30);//生成资源 $bgcolor = imagecolorallocate($image , 255,255,255);//#ffffff,为一幅图像分配颜色 imagefill($image , 0 , 0 , $bgcolor);//左上角,区域填充 // 生成随机数字 $captch_code = ""; for ($i = 0 ; $i < 4 ; $i++){ $fontSize = 6; $fontColor = imagecolorallocate($image , rand(0,120) , rand(0,120), rand(0,120));//0~120是深色区间。 // $fontContent = rand (0,9); $data = "abcdefghijkmnopqrstuvwxyz23456789"; // 生成随机的字母和数字,从$data字符串里面,任意一个位置,取一个字母 $fontContent = substr($data , rand(0,strlen($data)), 1); $captch_code .= $fontContent; // 坐标 $x = ($i * 100 / 4 ) + rand (5,10);//总宽度100,放4个数字。 $y = rand (5 , 10); imagestring ($image,$fontSize,$x,$y,$fontContent,$fontColor); } // 将循环生成的随机数字保存在$_SESSION里面 $_SESSION['authcode'] = $captch_code; for ($i = 0 ; $i < 200 ; $i++){ $pointColor = imagecolorallocate ($image , rand (50,200),rand(50,200),rand(50,200));//颜色要比数字的浅。 imagesetpixel ($image , rand (1,99),rand(1,29),$pointColor);//生成的点不要超过画布。 } // 生成干扰线 for ( $i = 0 ; $i < 3 ; $i++){ $lineColor = imagecolorallocate($image , rand (80,220),rand(80,220),rand(80,220)); imageline($image , rand (1,99),rand(1,29),rand(1,99),rand(1,29),$lineColor); } header("content-type:image/png"); imagepng($image); imagedestroy($image); ?>

验证码通过表单进行提交

在project文件夹里面新建form.php
输入
<pre>
<?php?>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>确认验证码</title>
</head>
</pre>
<body> <form action="./form.php" method="post"> <p>验证图片:![](./captcha.php)</p> <p>请输入图片中的内容:<input type="text" name="authcode" value=""/></p> <p><input type="submit" value="提交" style="padding:6px 20px;"/></p> </form> </body> </html>

表单提交的内容都会存到$_REQUEST['authcode']里面,所以需要加上验证表单提交和$_SESSION[‘authcode’]是否相同的代码。
<pre>
<?php
if (isset($_REQUEST['authcode'])){
session_start();
if($_REQUEST['authcode'] == $_SESSION['authcode']){
echo '<font color="#0000CC">输入正确</font>';
}else{
echo '<font color = "#CC0000"><b>输入错误</b></font>';
}
exit();
}
?>
</pre>

此时在地址栏输入127.0.0.1/project/form.php,然后填入验证码字符

Paste_Image.png

点击提交按钮。

Paste_Image.png

但是如果是输入全大写的字母,会输出“输入错误”的标志。

因为我们在判断的时候是把原始输入和服务器保存的进行比较,所以自然需要完全一致才行。
可以把用户的输入全部转换为小写
<pre>
<?php
if (isset($_REQUEST['authcode'])){
session_start();
if(strtolower(trim($_REQUEST['authcode'])) == $_SESSION['authcode']){
echo '<font color="#0000CC">输入正确</font>';
}else{
echo '<font color = "#CC0000"><b>输入错误</b></font>';
}
exit();
}
?>
</pre>

动态验证

之前的代码存在一个问题,如果出来的验证码图片用户不能完全分辨得出,就没有办法了。在生活中,一般的验证码图片旁边都会有“看不清?”这样的提示,点击的话,会刷新验证码。
可以通过三个步骤进行:

  • 增加可点击的“换一个”文案
  • 用JS选择器选取图片
  • 用js修改验证码图片地址
    首先增加文案
    <pre>
    <a href="javascript:void(0)">换一个?</a>
    </pre>
    为了方便选取图片,给img加上id属性,使用document.getElementById('captch_img')获得图片,然后用新的图片对他进行赋值,注意可以加上一段随机数字。
    <pre>
    <?php
    if (isset($_REQUEST['authcode'])){
    session_start();
    if(strtolower(trim($_REQUEST['authcode'])) == $_SESSION['authcode']){
    echo '<font color="#0000CC">输入正确</font>';
    }else{
    echo '<font color = "#CC0000"><b>输入错误</b></font>';
    }
    exit();
    }
    ?>
    <!doctype html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>确认验证码</title>
    </head>
    <body>
    <form action="./form.php" method="post">
    <p>验证图片:<img id="captcha_img" border="1" src="./captcha.php?r=<?php echo rand();?>" width="100" heigh="30">
    <a href="javascript:void(0)" onclick="document.getElementById('captcha_img').src='./captcha.php?r='+Math.random()">换一个?</a>
    </p>
    <p>请输入图片中的内容:<input type="text" name="authcode" value=""/></p>
    <p><input type="submit" value="提交" style="padding:6px 20px;"/></p>
    </form>
    </body>
    </html>
    </pre>

至此验证码的功能基本都实现了,下面主要进行类的封装,以后可以多次的复用。

验证码类的封装

首先考虑通用的验证码类里面有那些元素:

<pre>
class Vcode {
private $width; //验证码图片的宽度
private $height; //验证码图片的高度
private $codeNum; //验证码字符的个数
private $disturbColorNum; //干扰元素数量
private $checkCode; //验证码字符
private $image; //验证码资源
}
</pre>

然后写构造方法,主要用来实例化验证码对象,并为一些成员属性初使化 。
在写构造方法之前,我们新定义一个内部私有方法createCheckCode(),随机生成用户指定个数的字符串,去掉了容易混淆的字符oOLlz和数字012
<pre>
private function createCheckCode(){
$data="3456789abcdefghijkmnpqrstuvwxy";
for($i=0; $i<$this->codeNum; $i++) {
// $char = $code{rand(0,strlen($code)-1)};
$fontContent = substr($data , rand(0,strlen($data)), 1);
$captch_code .= $fontContent;
}
return $captch_code;
}
</pre>

然后开始写构造函数:
<pre>
/**
* 构造方法用来实例化验证码对象,并为一些成员属性初使化
* @param int $width 设置验证码图片的宽度,默认宽度值为80像素
* @param int $height 设置验证码图片的高度,默认高度值为20像素
* @param int $codeNum 设置验证码中字母和数字的个数,默认个数为4个
/
function __construct($width=80, $height=20, $codeNum=4) {
$this->width = $width;
$this->height = $height;
$this->codeNum = $codeNum;
$number = floor($height
$width/15);
//如果验证码字符过多,则需要减少干扰点的数量
if($number > 240-$codeNum)
$this->disturbColorNum = 240-$codeNum;
else
$this->disturbColorNum = $number;
$this->checkCode = $this->createCheckCode();
}
</pre>

我们之前讲过输出图像有几个步骤,首先新建画布,然后生成干扰点,再加上随机的字符,最后输出。可以把每个步骤包装成一个方法,然后在outImg()里面统一调用。

  • 新建画布
    <pre>
    /* 内部使用的私有方法,用来创建图像资源,并初使化背影 */
    private function getCreateImage(){
    $this->image = imagecreatetruecolor($this->width,$this->height);

          $backColor = imagecolorallocate($this->image, rand(225,255),rand(225,255),rand(225,255)); 
          
          @imagefill($this->image, 0, 0, $backColor); 
          
      }
    

</pre>

  • 设置干扰元素
    <pre>
    /* 内部使用的私有方法,设置干扰像素,向图像中输出不同颜色的点 */
    private function setDisturbColor() {
    // 画随机点
    for($i=0; $i <= $this->disturbColorNum; $i++) {
    $color = imagecolorallocate($this->image, rand(50,200), rand(50,200), rand(50,200));
    imagesetpixel($this->image,rand(1,$this->width-2),rand(1,$this->height-2),$color);
    }
    // 画随机线
    for($i=0; $i<10; $i++){
    $color=imagecolorallocate($this->image,rand(80,220),rand(80,220),rand(80,220));
    imageline($this->image,rand(-10,$this->width),rand(-10,$this->height),rand(30,300),rand(20,200),55,44,$color);
    }
    }
    </pre>

  • 在图片上写字

<pre>
/* 内部使用的私有方法,随机颜色、随机摆放、随机字符串向图像中输出 /
private function outputText() {
for ($i=0; $i<=$this->codeNum; $i++) {
$fontcolor = imagecolorallocate($this->image, rand(0,128), rand(0,128), rand(0,128));
$fontSize = rand(3,5);
$x = floor($this->width/$this->codeNum)
$i+3;
$y = rand(0,$this->height-imagefontheight($fontSize));
imagechar($this->image, $fontSize, $x, $y, $this->checkCode{$i}, $fontcolor);
}
}
</pre>

  • 输出图像,

<pre>
/* 内部使用的私有方法,自动检测GD支持的图像类型,并输出图像 */
private function outputImage(){
if(imagetypes() & IMG_GIF){
header("Content-type: image/gif");
imagegif($this->image);
}elseif(imagetypes() & IMG_JPG){
header("Content-type: image/jpeg");
imagejpeg($this->image, "", 0.5);
}elseif(imagetypes() & IMG_PNG){
header("Content-type: image/png");
imagepng($this->image);
}elseif(imagetypes() & IMG_WBMP){
header("Content-type: image/vnd.wap.wbmp");
imagewbmp($this->image);
}else{
die("PHP不支持图像创建!");
}
}
</pre>

  • 使用outImg()函数统一起来

<pre>
/* 内部使用的私有方法,用于输出图像 */
private function outImg(){
$this->getCreateImage();
$this->setDisturbColor();
$this->outputText();
$this->outputImage();
}
</pre>

  • 向服务器SESSION中保存验证码
    <pre>
    /**
    * 用于输出验证码图片,也向服务器的SESSION中保存了验证码,使用echo 输出对象即可
    /
    function __toString(){
    /
    加到session中, 存储下标为code */
    $_SESSION["code"] = strtoupper($this->checkCode);
    $this->outImg();
    return '';
    }
    </pre>

  • 析构函数

<pre>
/* 析构方法,在对象结束之前自动销毁图像资源释放内存 */
function __destruct(){
imagedestroy($this->image);
}
</pre>

至此验证码类已经完成,只要直接输出对象,就可以向浏览器中输出图片,可以在表单中使用。

在提交验证码到服务器的时候,已经转为了大写,需要在验证的时候把浏览器提交的也转换为大写。

应用验证码类

新建imgcode.php文件,使用session_start()开启回话控制,同时创建类的对象。
此时如果使用echo输出,同时会自动将验证码字符串保存在服务器中。

<pre>
<?php
/**
file:imgcode.php
用于请求时,通过验证码类的对象向客户端输出图片
*/
session_start(); //开启SESSION,会使用$_SESSION["code"]在服务器中保存验证码

require_once('captch.class.php');    //包含验证码所在的类文件
echo new Vcode();                   //创建验证码对象,并直接被输出自动调用魔术__toString()方法

</pre>

构造表单,应用验证码

在form.php中,包含输入表单和匹配验证码两部分。

<pre>
<?php
/** form.php 用于输出用户操作表单和验证用户的输入 /
session_start(); //开启SESSION
if(isset($_POST['submit'])){ //判断用户提交后执行
/
判断用户在表单中输入的字符串和验证码图片中的字符串是否相同 /
if(strtoupper(trim($_POST["code"])) == $_SESSION['code']){ //如果验证码输出成功
echo '验证码输入成功
'; //输出成功的提示信息
}else{ //如果验证码输入失败
echo '<font color="red">验证码输入错误!!</font>
'; //输出失败的输入信息
}
}
?>
<html>
<head>
<title>Image</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<script>
/
定义一个JavaScript函数,当单击验证码时被调用,将重新请求并获取一个新的图片 /
function newgdcode(obj,url) {
/
后面传递一个随机参数,否则在IE7和火狐下,不刷新图片 */
obj.src = url+ '?nowtime=' + new Date().getTime();
}
</script>
</head>
<body> ![](imgcode.php) <form method="POST" action="form.php"> <input type="text" size="4" name="code" /> <input type="submit" name="submit" value="提交"> </form> </body> </html>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容