纯音乐:千年等一回

陶笛吹奏

yii框架
用yii开发个人网站之搭建前后台-上
用yii开发个人网站之搭建前后台-中
用yii开发个人网站之搭建前后台-下
Yii2的一些插件使用

用yii开发个人网站之搭建前后台-上

在开始枯燥的教程之前,先来一个轻松的游戏,但是呢,这个游戏是用html和php代码构成的。如下图,是一张国际象棋棋盘图片,图片由黑白两种颜色相互交错构成。我们的游戏规则就是:用少量的html和php代码解析出这种黑白相间的效果。

代码怎么写呢?你是不是觉得毫无头绪?其实很多事情都是有规律、有技巧的。我们一步一步来。

1.首先,用html代码里面的table标签解析出4个格子全部都是黑色的效果。代码如下:

<style type="text/css">
td{width:100px;height:100px;background:black;}
</style>

<table border=1 align='center'>
    <tr>
        <td></td>
        <td></td>
    </tr>


    <tr>
        <td></td>
        <td></td>
    </tr>
</table>

效果如下图:

2.我们怎么把这4个格子变成黑白交错呢?难道要一个格子一个格子来写?当然不是,这是最笨的方法。在公布答案之前,先动动你的脑子,你是否发现了某种规律?

其实规律很简单:一个是行和列,一个是单(奇数)与双(偶数)。揭晓答案吧!代码如下:

echo '这是王玉坛在php培训班学习期间,最爱的小玩意,没事无聊时就玩玩这个。';
echo '<table border=1 style="margin:0 auto;">';
for($a=1;$a<=6;$a++){
    echo '<tr>';
    for($b=1;$b<=6;$b++){
        if( ($a%2==0 && $b%2!=0) || ($a%2!=0 && $b%2==0) ){//如果行数是偶数并且列数是奇数,或者反之
            echo '<td style="background:pink;width:100px;height:100px;text-align:center;">'.$a.'行'.$b.'列'.'</td>';
        }else{
            echo '<td style="background:white;width:100px;height:100px;text-align:center;">'.$a.'行'.$b.'列'.'</td>';
        }
    }
    echo '</tr>';
}
echo '</table>';

效果图如下:

我们从上面的代码可以看出,变量$a代表行数,变量$b代表列数,只要把上面的粉红色(pink)改成黑色,把行数和列数改成你想要的数值就可以了,国际象棋图谱就搞定了!

通过上面的小游戏,你是不是不再觉得编程一定是很枯燥的东西呢?其实编程真的是非常枯燥的,但是它里面也有乐趣,就好比我们的人生或工作,我相信大部份人的人生、大部份人的工作都是枯燥乏味的、不断重复的。

好了,游戏结束,言归正传,看下面。


下面的教程可参考看云手册 https://www.kancloud.cn/curder/yii

一、下载yii2框架文件夹,搭建yii2最基本的前后台,拥有一个初步的完整项目。可参考在线视频教程https://v.youku.com/v_show/id_XODY4NDQ5NzA0.html

你可以不用精通PHP的yii框架2.0版本,但你必须学会它的基本知识,你才可以在你的电脑(我们称为本地,以区别于线上)开发一个完整的个人网站,完成后再把代码和数据库上传到服务器或虚拟主机上,服务器虽然要贵一点,但是我还是推荐用服务器,比虚拟主机好处多多。

1.在你的电脑浏览器输入www.yiichina.com进入yii的官网,点击“下载”,点击高级版本(Yii2的高级应用程序模板)即可自动下载,等待下载完成即可。因为我一直没用基本版本,所以对它不了解,这里以高级版本为例。如果你了解composer的话,可以用它来下载,具体的composer指令可以在yii的官网www.yiichina.com/download里找到。

首先要安装composer(自行百度怎么安装),安装composer成功后,按照官方的方法在命令行工具里切换到环境根目录下,输入php composer.phar create-projectyiisoft/yii2-app-advancedadvanced,如果提示报错,就不用php,直接输入composer create-projectyiisoft/yii2-app-advancedadvanced即可,接下来要做的就是有点漫长的等待,这个过程中间是没有任何提示的,请不要把命令行工具中途关掉。

2.把下载好的文件夹放到你电脑的环境根目录下(不要跟我说你不懂什么叫“环境”,那你就是门外汉了),解压,重命名为你觉得合适的名字。如果是个人网站,我建议你以你的姓名来命名,或者命名为project1(项目1的意思),千万别用中文来命名。把advanced文件夹里的全部文件剪切到项目根目录下,删掉advanced空文件夹。

3.现在的项目目录如下图:其中backend目录代表后台,frontend代表前台,common代表公共,vendor代表扩展,console代表控制台……

4.现在frontend的web和config目录下、backend的web和config目录下、common的config目录下、console的config目录下都没有配置文件,需要点击根目录下的init.bat文件完成项目的初始化,在弹出的命令界面里操作,在本地就选development,线上就选production,输入代表它们的数字,按回车键,输入yes按回车就行了。这样,frontend和backend的web和config下,以及common和console的config目录下就会自动生成对应的配置文件了。

5.配置本地站点域名:点击phpstudy的“其他选项菜单”,点击“站点域名管理”进入域名管理列表界面,“网站域名”填你喜欢的命名,例如我这里是“www.project1.com” 。“网站目录”可以点击“打开”按钮或者直接填,网站域名www.project1.com指向我这部电脑里面的E:\www\project1\frontend\web,代表我在我这部电脑(本地)的浏览器输入www.project1.com,这部电脑会先根据自己的hosts文件访问设定好的IP,因为我设置了IP是127.0.0.1,它就会自动访问本地,而不是去访问线上的IP,这时候,phpstudy的apache服务器会根据设定好的网站域名(本地域名,就是假的域名)去匹配本地电脑里的目录文件,找到E:\www\project1\frontend\web下的index.php(因为index.php文件是默认的入口文件,所以网站目录只需要输入E:\www\project1\frontend\web,不需要再加上它下面的index.php)。别的框架都是一个网站只有一个域名,把域名直接指向根目录,打开这个域名(网址)就是网站前台了,在域名后面接上/admin就是网站后台的地址了。但是yii比较特别,一个项目可以用两个域名,前台一个域名,后台一个域名,分别指向frontend文件夹下的web文件夹和backend文件夹下的web文件夹。还有关键的一步:在hosts文件里配置本地域名,如下图,www.project1.com代表网站前台,admin.project1.com代表网站后台,所以一个网站有两个域名(其实域名只有一个,就是project1.com,那两个域名只不过是二级域名罢了),这两个本地域名都指向IP 127.0.0.1 ,127.0.0.1代表电脑本地(本机)。

         

6.完成以上步骤后,在浏览器的地址栏里输入前台和后台的地址,就能访问网站前台和后台了,如下图。如果你不能访问,可以通过各种方式联系我。



二 、配置数据库信息。

1.数据库配置文件在项目根目录下的common下的config下的main-local.php文件,如果你的数据库表需要前缀,可在password下加上‘tablePrefix’=>表前缀,例如’yii1_‘(注意一定要有一条下划线) 。


2.下载sqlYOG或其它数据库管理工具软件到电脑,我一直用sqlYOG,一开始不习惯,后来就很喜欢用了,sqlYOG是要收费的,但是网上有破解版,有序列号(购买后的一串凭证字符),相当于免费。在数据库里新建一个数据库,名称最好跟你项目名一致,例如我的项目名叫“wangyutan1”,数据库名也叫“wangyutan1”,“基字符集”选“utf8mb4”(在我还没了解utf8mb4前,我一直都是选utf8),“数据库排序规则”选“utf8mb4_unicode_ci”(在我还没了解utf8mb4_unicode_ci前我一直都是选utf8mb4_general_ci),不了解这些区别的朋友可以自己去百度。

3.有了数据库,起码需要有一张表,这张表将储存我们登录后台的账号、密码等信息,这里有个亮点:yii2对安全做得比较好,例如管理员凭账号、密码登录后台,密码采用了哈希加密,比传统的md5加密更安全,举个栗子,两个人都用123456作为密码,用md5加密的话,被加密成一长串没有规律的字符,这两个被加密后的字符串是完成相同的(你一定想说:当然是完全相同啦,因为都是123456嘛),但是用哈希加密的话,即使两个人的密码都是123456,但是被加密后的这两个密码却是完全不同的,没有任何规律可循,因为哈希加密考虑了这两个注册密码的时间不是同一个时间(精确到毫秒),所以生成的密码不一样。现在网上付费破解md5加密,甚至是双重md5加密的有很多,世界最顶尖的数学家能够破解多重md5加密,但是基本上破解不了哈希加密。这张表可以叫“用户表”(user),也可叫“会员表”(member),还可以叫“管理员表”(admin)。如果这张表要同时储存后台管理员以及前台注册会员的信息,就应该叫“用户表”(user)合适;如果这张表只储存前台注册会员的信息,就应该叫“会员表”(member)合适;如果这张表只储存后台管理员的信息,就应该叫“管理员表”(admin)合适;这里我以user表为例。


创建user数据表,我们后面要实现后台登录

CREATE TABLE IF NOT EXISTS `wyt1_user`( 
`id` INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT "自增ID", 
`username` VARCHAR(25) NOT NULL COMMENT '用户名', 
`auth_key` VARCHAR(32) NOT NULL COMMENT '自动登录密钥', 
`password_hash` VARCHAR(60) NOT NULL COMMENT '经过哈希加密后的密码', 
`password_reset_token` VARCHAR(43) DEFAULT NULL COMMENT '密码重置口令', #注册成功后此字段没有值,输入邮箱重置密码时才有。
‘verification_token’  VARCHAR(255) NOT NULL COMMENT '验证令牌', 
`email` VARCHAR(255) NOT NULL COMMENT '邮箱', 


`role` TINYINT(2) NOT NULL DEFAULT '10' COMMENT'角色等级', 

#注意:这个字段可以不加入到user表里,如果加了,则要在\common\models\User.php的const STATUS_ACTIVE = 10;下新增代码,例如

    const ROLE_USER = 10;
    const ROLE_MODERATOR = 20;
    const ROLE_ADMIN = 30;


`status` TINYINT(1) NOT NULL DEFAULT '10' COMMENT'状态', 
`created_at` INT(11) NOT NULL COMMENT '创建时间', 
`updated_at` INT(11) NOT NULL COMMENT '更新时间'
)COMMENT='用户表'; 


或者用cmd/dos命令行切换到当前项目的根目录下,因为yii官方文件\console\migrations\m130524_201442_init.php里少了一个数据表字段的代码(官方新版本已经解决这个问题,\console\migrations下多了一个文件,里面就是让user表新增一个字段verification_token,但是要注意,如果你在数据库配置文件\common\config\main-local.php里增设了表前缀tablePrefix,那么,你就要在\console\migrations\m190124_110200_add_verification_token_column_to_user_table.php文件里两处代码{{user}}改成{{%user}},这个%就是表前缀的变量。新版本可以忽略后面的关于verification_token的教程。),所以要在这个文件的第21行代码'email' => $this->string()->notNull()->unique(),下补充一行代码'verification_token' => $this->string()->notNull()->unique(),然后在命令行工具里输入 yii migrate console/migrations/m130524_201442_init.php 然后会有提示Apply the above migration? (yes|no) [no]: 输入y或yes即可,这样,数据库里就会自动生成两个数据表:user表和migration表。需要注意的是:E:\www\project1\console\migrations\m130524_201442_init.php文件里的代码好像少了一个字段“verification_token”,如果没有这个字段的话,前台注册时会报错,提示数据表缺少这个字段。这可能是yii官方的一个小小漏洞之一,migration表其实要不要都没多大关系,这个表是用来迁移数据用的。本步骤需要保证前面的数据库配置文件main-local.php对数据库的配置准确无误,否则会执行失败。关于“Yii2如何用migrate快速建表”,可参考https://www.cnblogs.com/longzhankunlun/p/6261417.html


注意:新版本比旧版本做了一点改进,其中一点就是,新版本的\common\models\User.php里只有status(const STATUS_DELETED = 0;const STATUS_INACTIVE = 9;const STATUS_ACTIVE = 10;),而旧版本除了status,还有role,所以旧版的user表需要有role字段。


4.访问网站前台,注册一个用户,在后台登录时,会用到在前台注册的这个账号、密码。前端注册成功后,user表就有一条数据,把status的值改为10,如果有role字段,把role的值改为30,就把前端注册的这个用户变成后台管理员,就可以登录了。

在E:\www\project1\frontend\models\SignupForm.php文件里添加attributeLabels方法,

效果如下:

yii2自带了ajax无刷新异步验证,就是不用等用户填完信息后点击“注册”按钮跳转页面后才验证邮箱、密码等字段是否合法、是否为空等规则,在model文件的rules方法里定义你想要的规则即可,除了yii2自带的规则,你还可以自己写规则。
如上图,什么内容都没填,当鼠标离开用户名、邮箱、密码这三个文本输入框后,马上就会显示错误提示信息,并且字体变成红色,“用户名 cannot be blank.”显然不是我们想要的提示文字,可以在E:\www\project1\frontend\models\SignupForm.php文件的rules()方法里完善代码,如下图这样:

经过如上图那样,添加了一些代码,现在前台注册界面的效果如下:


如果你不想用邮箱注册,想改成手机号,或者其它内容的修改,增加手机短信验证码、确认密码这两个字段,可以联系我。

注册功能升级,加了“确认密码”和“验证码”:

1.注册功能的视图文件E:\www\project1\frontend\views\site\signup.php的全部代码如下:

<?php

use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\captcha\Captcha;

$this->title = '注册';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="site-signup">
    <p>带红点的为必填项</p>

    <div class="row">
        <div class="col-lg-5">
            <?php $form = ActiveForm::begin(['id' => 'form-signup','enableAjaxValidation'=>true]); ?>
                
                <?= $form->field($model, 'username',['template'=>"<div class='field_input'>{label}\n<span class='text_red'>*</span>{input}\n{error}</div>"])->textInput(['autofocus' => true,'placeholder'=>'汉字或字符或数字,最多7个。不能与已有的重复。将作为账号']) ?> 

                <?= $form->field($model, 'email',['template'=>"<div class='field_input'>{label}\n<span class='text_red'>*</span>{input}\n{error}</div>"])->textInput(['placeholder'=>'请输入自己的邮箱,因为此邮箱将会接收验证邮件']) ?>

                <?= $form->field($model, 'password',['template'=>"<div class='field_input'>{label}\n<span class='text_red'>*</span>{input}\n{error}</div>"])->passwordInput(['placeholder'=>'至少6位,设置后请牢记']) ?>

                <?= $form->field($model, 'repassword',['template'=>"<div class='field_input'>{label}\n<span class='text_red'>*</span>{input}\n{error}</div>"])->passwordInput(['placeholder'=>'必须与密码完全一致']) ?>

                <?= $form->field($model, 'captcha',['template'=>"<div class='field_input'>{label}\n<span class='text_red'>*</span>{input}\n{error}</div>"])->widget(Captcha::className(),['captchaAction'=>'site/captcha','imageOptions'=>['class'=>"captcha",'title'=>'点击更换'],'options'=>['placeholder'=>'不区分大小写']]) ?>

                <div class="form-group">
                    <?= Html::submitButton('注册', ['class' => 'btn btn-primary', 'name' => 'signup-button']) ?>
                </div>

            <?php ActiveForm::end(); ?>
        </div>
    </div>
</div>

2.在 E:\www\project1\frontend\model\SignupForm.php文件的rules内增加一个规则 ['captcha', 'codeVerify'],//因Yii2验证码Captcha原校验方式有bug,总是报错:验证码不正确,导致无法实现Ajax验证,所以自己写了一个方法,替代上一行的captcha。

/*
    使用自定义的codeVerify验证方法进行验证,避开Yii2的验证Bug
     */
    public function codeVerify($attribute) {
        //参数:'captcha',即控制器中actions()内的名称'captcha';Yii::$app->controller,调用验证的当前控制器(必须设置)
        $captcha_validate  = new \yii\captcha\CaptchaAction('captcha',Yii::$app->controller);
        if($this->$attribute){
            $code = $captcha_validate->getVerifyCode();
            $verify = $this->$attribute;
            if(strtolower($verify)==strtolower($code)){
                return true;
            }else{
                $this->addError($attribute,'验证码不正确');
            }
        }
    }
在attributeLabels方法内增加代码

'repassword' => '确认密码',
'captcha' => '验证码',

把signup方法的最后一行代码return $user->save()  && $this->sendEmail($user);改为return $this->sendEmail($user) && $user->save();其实就是调一下顺序。

在sendEmail方法内的最后增加代码

if($mail){
                return true;
            }else{
                return false;
            }

3. 控制器文件 E:\www\project1\frontend\controllers\SiteController.php内的actionSignup方法全部代码如下:

public function actionSignup()
    {
        $model = new SignupForm();
        if($model->load(Yii::$app->request->post())){
            if(Yii::$app->request->isAjax){
                Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
                return \yii\bootstrap\ActiveForm::validate($model);
                Yii::$app->end();

                $captcha_validate  = new \yii\captcha\CaptchaAction('captcha',$this);//数据存储成功后,要重新生成新的验证码,否则原验证码不会改变
                $captcha_validate->getVerifyCode(true);
            }

            if($model->signup()){  
                Yii::$app->response->cookies->add(new \yii\web\Cookie(['name'=>'inactive_email','value'=>$model->email,'expire'=>time()+3600*24*30]));
                //注册成功后,验证邮箱前,通过cookie设置信息提示条“您的邮箱 xxx@xxx.com 还未验证,请尽快登录邮箱查收邮件并激活。如果您未收到邮件,点此重新发送。”,只要用户还没验证邮箱,在30天内打开这个浏览器,都会显示。这个功能替换下面的那一行代码的功能。设置cookie后,在E:\www\project1\vendor\yiisoft\yii2\base\Controller.php文件的renderContent方法内的第399行代码增加了“ ,'inactive_email'=>Yii::$app->request->cookies->get('inactive_email') ”,这样,就可以在公共页面layouts/main.php文件里读取到变量$inactive_email了!                       
                // Yii::$app->session->setFlash('success', '您的邮箱'.$model->email.'还未验证,请尽快登录邮箱查收邮件并激活,激活邮箱后方可登录。如果您未收到邮件,点此'.Html::a('重新发送', ['site/resend-verification-email']).'。');
                return $this->goHome();
            }
        }

        return $this->render('signup', [
            'model' => $model,
        ]);
    }

4.在上述文件的actions方法内的开头增加如下代码,就能在30天后自动删除没验证邮箱的用户数据了。

$user = \common\models\User::find()->where(['email'=>Yii::$app->request->cookies->get('inactive_email'),'status'=>User::STATUS_INACTIVE])->one();
        if(!empty($user) && time()-$user->updated_at>3600*24*30){//注册后30天内未验证的邮箱将会在注册30天后自动被删掉数据,到时候,可以重新注册。
            $user->delete();
        }
5.最后有一个小问题(新版本已经解决这个问题):如果用户用不存在的邮箱,例如666@qq.com注册的话,会报错,可以把t调试模式关掉:把入口文件index.php的第一行代码的YII_DEBUG设置成false即可,在error.php文件做判断,全部代码如下:

<?php

use yii\helpers\Html;

$this->title = $name;

?>
<div class="site-error">

    <h1><?= Html::encode($this->title) ?></h1>

    <div class="alert alert-danger">
        <?php if(strpos($exception,'Expected response code 354 but got code "503"')){ ?>
            <?php echo '此邮箱不存在!请检查。';?>
        <?php }else{ ?>
            <?php echo nl2br(Html::encode($exception)) ?>
        <?php } ?>
    </div>

    <p>
        Web服务器处理您的请求时发生上述错误。
    </p>
    <p>
        如果您认为这是服务器错误,请联系我们。谢谢您。
    </p>
    <a href="<?= Yii::$app->request->referrer ?>">返回上一页</a><!-- 这个是我加上去的 -->
</div>

完。



回到E:\www\project1\common\config\main-local.php文件,在刚才配置了数据库代码的下方,配置邮件自动发送(免费),代码如下图:

username值就是由哪个邮箱发送邮件,这里当然是我自己的邮箱wangyutan1986@qq.com,password值不是邮箱密码,而是由这个邮箱提供商为你提供的一个授权码,以QQ邮箱为例,登录你的QQ邮箱主页,点击“设置”按钮,点击“帐户”按钮,找到“生成授权码”按钮,注意要先开启POP3和IMAP服务,有时候还要用绑定了这个邮箱的手机编辑“配置邮件客户端”发送一条短信到1069070069,发送成功后才能点击“我已发送”按钮,才能获取这个授权码,授权码可多次生成,都有效,第二个授权码不会覆盖掉第一个,所以可以不用记住这些授权码,当然,你要记住也行,方便以后在别的项目直接复制粘贴就可以用。如果这个授权码错误的话,yii不会提示授权码错误,而是直接显示“Swift_TransportException”。


完成了上面的邮件自动发送配置,每当有一位网站浏览者注册成功,他注册时填写的邮箱地址就会马上收到一封来自网站的邮件,这封邮件的内容只有一条链接,注册者必须点击这条链接才能确认注册时填写的邮件是自己的,这就是注册的邮件验证,跟注册时填写手机号收到手机短信验证码确认填写的手机号是自己的同理,发送手机验证码短信每一条需要几分钱,还要跟短信服务提供商对接、注册账户、提交工商营业执照等等繁杂手续,一次性要至少充值一千元,有些提供商(例如阿里云)的服务是有期限的,你充了一千元,假如每条短信是5分钱,一千元总共可以发送两万条短信,但是要在一年内(我忘了是一年还是两年)发送完这两万条短信,期限一到,清空!还是非常坑爹的。深圳创蓝的就没有期限。像我这样的小小的个人网站,一年都没有十个人注册,所以我还是采用邮箱注册,毕竟邮箱注册是免费的。

如果注册者没有点击收到的邮件里面的链接或者根本就没收到邮件(基本上不会出现这种情况),虽然数据表user里有他的数据,但是他不能通过注册的用户名配合密码登录,因为他还没通过邮件验证,数据表user的字段“status”(状态)的值是9,(9是我们随意设定的,只要不是10就不能登录),只有当他在他收到的验证邮件里点击确认链接后,这条数据的字段“status”的值才会变成10,他才可以登录。