yii2 swift mailer 发送邮件不成功的问题

今天调试yii2自带的swift mailer发邮件,开始调试时,发送用的send()方法始终返回true,但是就是没有收到邮件,很是纳闷,于是开始了半个晚上的调试之旅,我把调试过程发出来,希望后面的小伙伴能少走一些弯路。
首先,根据热心网友的文章,配置邮箱的基础信息,我用的base项目,所以我的配置文件是web.php,配置内容为:
        ‘mailer’ => [
            ‘class’ => ‘yii\swiftmailer\Mailer’,
            ‘transport’ => [
                ‘class’ => ‘Swift_SmtpTransport’,
                ‘host’ => ‘smtp.163.com’,
                ‘username’ => ‘xxx@163.com’,
                ‘password’ => ‘xxx’,
                ‘port’ => ’25’,
                ‘encryption’ => ‘tls’,//    tls | ssl

            ],
            ‘messageConfig’=>[
                ‘charset’=>’UTF-8’,
                ‘from’=>[‘xxx@163.com’=>’admin’]
            ],
            ‘useFileTransport’ => false,
        ],
然后开始写了一个测试用的控制器,内容如下:
    public function actionMailer()
    {
        $mail= Yii::$app->mailer->compose();
        $mail->setTo(‘10000@qq.com’);
        $mail->setSubject(“Test title”);
        $mail->setTextBody(‘Test content’);
        //$mail->setHtmlBody(“Test HTML”);
        var_dump($mail->send());
    }
好了,信心满满的开始测试了,执行链接,满心欢喜的去查看QQ邮箱了,但是左等右等,前等后等,丫的就是没有,重新发送,还是没有,但是send()的返回值明明就是true!
 于是开始排错,总结了一下,出错的可能位置在以下几点:
 不同邮箱的host是不同的
如果是163邮箱,password是授权码
userFileTransport要设置成false,否则只会在runtime下生成缓存文件,不会真正发送
一一排查,确信没有错误,太奇怪了,于是我决定直接调用swiftmailer试一下,于是新建了下面的控制器:
    public function actionMailer2()
    {
        $mailer = new \yii\swiftmailer\Mailer();
        $mailer->transport=[
            ‘class’ => ‘Swift_SmtpTransport’,
            ‘host’ => ‘smtp.163.com’,
            ‘username’ => ‘xxxx@163.com’,
            ‘password’ => ‘xxxx’,
            ‘port’ => ’25’,
            ‘encryption’ => ‘tls’,//    tls | ssl
        ];
        $mailer->messageConfig=[
            ‘charset’=>’UTF-8’,
            ‘from’=>[‘xxxx@163.com’=>’admin’]
        ];
        $mailer->useFileTransport = false;
        $mail= $mailer->compose();
        $mail->setTo(‘10000@qq.com’);
        $mail->setSubject(“Test title”);
        $mail->setTextBody(‘Test content’);
        var_dump($mail->send());
    }

哎哟我去!发送成功了!这是为啥呢?首先证明这个类确是是可以发送邮件的了,那么下一步要细细的分析这两段代码区别在何处了。
我分别打印了两个类构造完成后的结果:
    public function actionMailer()
    {
        echo ‘<pre>’;
        var_dump(Yii::$app->mailer);
    }

    public function actionMailer2()
    {
        $mailer = new \yii\swiftmailer\Mailer();
        $mailer->transport=[
            ‘class’ => ‘Swift_SmtpTransport’,
            ‘host’ => ‘smtp.163.com’,
            ‘username’ => ‘xxxx@163.com’,
            ‘password’ => ‘xxxx’,
            ‘port’ => ’25’,
            ‘encryption’ => ‘tls’,//    tls | ssl
        ];
        $mailer->messageConfig=[
            ‘charset’=>’UTF-8’,
            ‘from’=>[‘xxxx@163.com’=>’admin’]
        ];
        $mailer->useFileTransport = false;
        echo ‘<pre>’;
        var_dump($mailer);
    }

在长长的内容中慢慢的对比,终于发现了端倪,
第一个方法中:[“useFileTransport”]=>bool(true)
第二个方法中:[“useFileTransport”]=>bool(false)
上面也说过了,useFileTransport必须设置成false才能发送成功,那问题总算是找到了,那为什么会出现这样的问题呢?我上面明明是设置过的,为什么没生效?难道是测试环境的原因吗?
我测试使用的url是http://goonwin.com/index-test.php?r=liyang/mailer,注意那个index-test.php,就是他的原因了,于是我把index-test.php改成index.php立马发送成功了,丫的,这么隐蔽一个坑啊!!!
但是我还是希望测试环境可以发送邮件的,于是,稍微改动了一下调用的方法:
    public function actionMailer()
    {
        $mail = Yii::$app->mailer;
        $mail->useFileTransport = false;
        $mail= $mail->compose();
        $mail->setTo(‘10000@qq.com’);
        $mail->setSubject(“Test title”);
        $mail->setTextBody(‘Test content’);
        var_dump($mail->send());
    }

Oh,终于可以发送了,看到论坛中有些朋友也在问同样的问题,估计现在你已经可以解决了。洋洋洒洒写了这么多,其实就一个目的,希望能给新手一点调试的经验吧,老手你当然乐呵乐呵就得了。
浪费一晚上青春,睡觉!

JS压缩方法(使用uglify工具在本地压缩)及批量压缩

一、压缩JS的好处:

1、减小了文件的体积 
2、减小了网络传输量和带宽占用 
3、减小了服务器的处理的压力 
4、提高了页面的渲染显示的速度

二、压缩JS的方法如下:

1、首先在本地安装node.js和npm,一般npm集成于nodejs,即安装nodejs,同时也安装了npm。

2、安装uglify插件。在cmd命令行执行:

3、开始压缩js文件。

首先在命令行,进入JS文件所在目录。

然后执行压缩文件命令:uglifyjs pdf.js -o pdf.min.js

我要压缩的文件为pdf.js,生成的压缩文件名为pdf.min.js。-o是一个参数,关于参数的具体解析大家可以去官网看,https://www.npmjs.com/package/uglify-js。最后看一看压缩的结果:

可以看到文件由719KB,被压缩到了536KB。

三、批量压缩方法:

1)新建txt文件,内容如下

@echo off
:: 设置压缩JS文件的根目录,脚本会自动按树层次查找和压缩所有的JS(注意路劲中不能有空格)
SET JSFOLDER=D:\uglifyDestination
echo 正在查找JS文件
chdir /d %JSFOLDER%
for /r . %%a in (*.js) do (
    @echo 正在压缩 %%~a ...
    uglifyjs %%~fa  -m -o %%~fa
)
echo 完成!
pause & exit

2)另存为.bat文件

3)将需要压缩的js文件放置目录

4)运行bat文件

详解JavaScript+Canvas绘制环形进度条

目录

效果图

思考

移动端的场景里经常会出现环形进度条的功能,在实现这个功能前,我预想的解决方案大致有: echarts、antv、canvas、svg

前面两种第三方提供的解决方案当然是简单,拿到案例修整一下即可,但是需要下载依赖,而且代码量不小。有没有不需要依赖第三方包,采用原生的写法,独立封装成一个组件,降低耦合,而且性能优越?

当然,那就主要介绍canvas的使用

实现思路

可以展示整个圆、半圆以及任意角度弧形(左右对称)的进度条。整体思路如下:

1.先确定展示的形状,是整个圆、半圆还是一般的弧形

2.把确定好形状的圆弧均分100等份,计算出每一份所占的弧度

3.灰色圆弧占100份,红色圆弧最终占的份数由参数确定

4.设置setInterval定时器,重复执行画图操作

  • 清空画布
  • 先画灰色的圆弧,占100份
  • 再画红色的圆弧:红色圆弧的份数从0开始,每次加1
  • 画红色圆弧末端的红色圆:难点在于根据角度确定红色圆的圆心,这里面涉及到三角函数,在草稿纸上画个图就大致明白了
  • 当红色圆弧的份数达到指定值(传的参数)的时候,清除定时器

具体代码实现

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
  <title>Canvas</title>
</head>
<body>
  <canvas id="canvas" width="300" height="300"></canvas>

  <script>
    draw(66);
    /**
     * [顺时针方向画图,起始点在左侧]
     * @param  {[number]} percent [所占的进度百分比,比如66%,则传66即可,0 <= percent <= 100]
     * @param  {[number]} sR      [圆弧起始角度,可不传,默认是π/2,Math.PI/2 <= sR < 3/2 * Math.PI]
     */
    function draw(percent, sR) {
      if (percent < 0 || percent > 100) {
        return;
      }
      if (sR < Math.PI/2 || sR >= 3/2 * Math.PI) {
        return;
      }

      var canvas = document.querySelector('#canvas'),
          cxt = canvas.getContext('2d'),
          cWidth = canvas.width,
          cHeight = canvas.height,
          baseColor = '#e1e1e1',
          coverColor = '#fe4d43',
          PI = Math.PI,
          sR = sR || 1/2 * PI; // 默认圆弧的起始点弧度为π/2

      var finalRadian = sR + ((PI + (PI - sR) * 2) * percent / 100); // 红圈的终点弧度
      var step = (PI + (PI - sR) * 2)/100; // 一个1%对应的弧度大小
      var text = 0; // 显示的数字
      var timer = setInterval(function() {
        cxt.clearRect(0, 0, cWidth, cHeight);
        var endRadian =  sR + text * step;
        // 画灰色圆弧
        drawCanvas(cWidth/2, cHeight/2, 80, sR, sR + (PI + (PI - sR) * 2), baseColor, 2);
        // 画红色圆弧
        drawCanvas(cWidth/2, cHeight/2, 80, sR, endRadian, coverColor, 2);

        // 画红色圆头
        // 红色圆头其实就是一个圆,关键的是找到其圆心,涉及到三角函数知识,自己画个图一看就明了
        var angle = 2*PI - endRadian; // 转换成逆时针方向的弧度(三角函数中的)
        xPos = Math.cos(angle) * 80 + cWidth/2; // 红色圆 圆心的x坐标
        yPos = -Math.sin(angle) * 80 + cHeight/2; // 红色圆 圆心的y坐标
        drawCanvas(xPos, yPos, 2, 0, 2*PI, coverColor, 2);

        // 数字
        cxt.fillStyle = coverColor;
        cxt.font = '40px PT Sans';
        var textWidth = cxt.measureText(text+'%').width;
        cxt.fillText(text+'%', cWidth/2 - textWidth/2, cHeight/2 + 15);
        text++;

        if (endRadian.toFixed(2) >= finalRadian.toFixed(2)) {
          clearInterval(timer);
        }
      }, 30);

      function drawCanvas(x,y,r,sRadian,eRadian,color,lineWidth) {
        cxt.beginPath();
        cxt.lineCap = "round";
        cxt.strokeStyle = color;
        cxt.lineWidth = lineWidth;
        cxt.arc(x, y, r, sRadian, eRadian, false);
        cxt.stroke();
      }
    }
  </script>
</body>
</html>

关于动画部分,可以使用requestAnimationFrame做优化,函数改写如下:

function draw(percent, sR) {
  if (percent < 0 || percent > 100) {
    return;
  }
  if (sR < Math.PI/2 || sR >= 3/2 * Math.PI) {
    return;
  }

  var canvas = document.querySelector('#canvas'),
      cxt = canvas.getContext('2d'),
      cWidth = canvas.width,
      cHeight = canvas.height,
      baseColor = '#e1e1e1',
      coverColor = '#fe4d43',
      PI = Math.PI,
      sR = sR || 1/2 * PI; // 默认圆弧的起始点弧度为π/2

  var finalRadian = sR + ((PI + (PI - sR) * 2) * percent / 100); // 红圈的终点弧度
  var step = (PI + (PI - sR) * 2)/100; // 一个1%对应的弧度大小
  var text = 0; // 显示的数字

  window.requestAnimationFrame(paint);
  function paint() {
    cxt.clearRect(0, 0, cWidth, cHeight);
    var endRadian =  sR + text * step;
    // 画灰色圆弧
    drawCanvas(cWidth/2, cHeight/2, 80, sR, sR + (PI + (PI - sR) * 2), baseColor, 2);
    // 画红色圆弧
    drawCanvas(cWidth/2, cHeight/2, 80, sR, endRadian, coverColor, 2);

    // 画红色圆头
    // 红色圆头其实就是一个圆,关键的是找到其圆心,涉及到三角函数知识,自己画个图一看就明了
    var angle = 2*PI - endRadian; // 转换成逆时针方向的弧度(三角函数中的)
    xPos = Math.cos(angle) * 80 + cWidth/2; // 红色圆 圆心的x坐标
    yPos = -Math.sin(angle) * 80 + cHeight/2; // 红色圆 圆心的y坐标
    drawCanvas(xPos, yPos, 2, 0, 2*PI, coverColor, 2);

    // 数字
    cxt.fillStyle = coverColor;
    cxt.font = '40px PT Sans';
    var textWidth = cxt.measureText(text+'%').width;
    cxt.fillText(text+'%', cWidth/2 - textWidth/2, cHeight/2 + 15);
    text++;

    if (endRadian.toFixed(2) < finalRadian.toFixed(2)) {
      window.requestAnimationFrame(paint);
    }
  }

  function drawCanvas(x,y,r,sRadian,eRadian,color,lineWidth) {
    cxt.beginPath();
    cxt.lineCap = "round";
    cxt.strokeStyle = color;
    cxt.lineWidth = lineWidth;
    cxt.arc(x, y, r, sRadian, eRadian, false);
    cxt.stroke();
  }