邢栋博客

邢栋博客,Action博客,记录工作和生活中的点点滴滴

Connection could not be established with host smtp.exmail.qq.com [ #0]
今天在用yii2发送邮件的时候提示

Connection could not be established with host smtp.exmail.qq.com [ #0]

openssl没啥问题,函数权限也有打开了

折腾半天后终于找到解决办法

出问题之前的代码
/common/config/main-local.php中mailer配置
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
'viewPath' => '@common/mail',
'useFileTransport' => false,//false发送邮件,true只是生成邮件在runtime文件夹下,不发邮件
'transport'=>[
    'class' => 'Swift_SmtpTransport',
    'host' => 'smtp.exmail.qq.com',
    'username' => '这里是公司的邮箱账号',
    'password' => '邮箱密码',
    'port' => '465',
    'encryption' => 'ssl',
],
'messageConfig'=>[
    'charset'=>'UTF-8',
    'from'=>['这里是公司的邮箱账号'=>'Admin']
],
],

控制器中代码
$mail = Yii::$app->mailer->compose();
$mail->setTo('xingdong1117@126.com');
$mail->setSubject('测试邮件');
$mail->setHtmlBody('这里是内容'); //发布可以带html标签的文本
if ($mail->send()) {
    echo "success";
}else {
    echo "failse";
}


解决办法
在/common/config/main-local.php中mailer配置
'transport'=>[
    'class' => 'Swift_SmtpTransport',
    'host' => 'smtp.exmail.qq.com',
    'username' => '这里是公司的邮箱账号',
    'password' => '邮箱密码',
    'port' => '465',
    'encryption' => 'ssl',
    //这里是新加入的内容
    'StreamOptions'=>[
       'ssl'=>[
            'verify_peer' => false, //是否需要验证 SSL 证书
            'verify_peer_name'=>false,//Require verification of peer name.
            'allow_self_signed' => true//是否允许自签名证书
        ],
    ]
],


//更多参数可以查看 http://php.net/manual/zh/context.ssl.php


其实在
在vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php 266行代码中
$streamContext = stream_context_create($options);
$this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $streamContext);
中间加入
$streamContext = stream_context_create($options);
//----
stream_context_set_option($streamContext, 'ssl', 'verify_peer',false);
stream_context_set_option($streamContext, 'ssl', 'verify_peer_name',false);
stream_context_set_option($streamContext, 'ssl', 'allow_self_signed',true);
//-----
$this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $streamContext);
也得到了解决,不过不如上面的办法


如果在使用phpmailer的时候也出现此问题,可以这样解决

$mail = new PHPMailer;
//$mail->SMTPDebug = 4;
$mail->isSMTP();
$mail->Host = 'smtp.exmail.qq.com';
$mail->SMTPAuth = true;
$mail->Username = '这里是公司的邮箱账号';
$mail->Password = '邮箱密码';
$mail->SMTPSecure = 'ssl';
$mail->Port = 465;
$mail->SMTPOptions = array(
    'ssl' => array(
        'verify_peer' => false,
        'verify_peer_name'=>false,
        'allow_self_signed' => true
    )
);
$mail->setFrom('这里是公司的邮箱账号','Admin');
$mail->addAddress('xingdong1117@126.com');
$mail->addReplyTo('这里是公司的邮箱账号', 'Admin');
$mail->isHTML(true);
$mail->Subject = '测试邮件';
$mail->Body    = '邮件内容';

if ($mail->send()) {
    echo "success";
}else {
    echo "failse";
}


ps:不知道啥原因导致的这样的情况,我本地是mac环境,没有这样的问题,到了linux服务器上就出现了这样的问题,只有加上这几个参数才可以。等找到真正原因再来写。
php实现异步调用无阻塞
php实现异步调用无阻塞


之前web端的数据统计用的是嵌入一个img标签,src指向脚本文件/index.php?name=xingdong,这种方法倒是挺快,不过需要的是页面加载,现在是在给客户端写接口,就不太合适.于是找了下解决办法

1.popen() (转)
resource popen ( string command, string mode );
//打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。

所以可以通过调用它,但忽略它的输出。
pclose(popen("/home/xinchen/backend.php &", 'r'));
这个方法避免了第一个方法的缺点,并且也很快。但是问题是,这种方法不能通过HTTP协议请求另外的一个WebService,只能执行本地的脚本文件。并且只能单向打开,无法穿大量参数给被调用脚本。
并且如果,访问量很高的时候,会产生大量的进程。如果使用到了外部资源,还要自己考虑竞争。


2.curl
这个方法,设置CUROPT_TIMEOUT为1(最小为1,郁闷)。也就是说,客户端至少必须等待1秒钟
$ch = curl_init();
$curl_opt = array(CURLOPT_URL, 'http://www.example.com/backend.php',CURLOPT_RETURNTRANSFER, 1,CURLOPT_TIMEOUT, 1,);
curl_setopt_array($ch, $curl_opt);
curl_exec($ch);
curl_close($ch);

3.fsockopen和stream_socket_client,可以直接替换
ps:PHP5中可以使用新增的stream_socket_client()函数直接替换掉fsocketopen()
在使用之前出现了很多问题,我的服务器配置比较低,nginx配置中worker_processes为1,出现了请求后没有异步处理,改成2解决
执行一个时间比较长的异步请求后,不能全部执行,查看php-fpm日志发现
WARNING: [pool www] child 19307, script '/work/www/live/manage/index.php' (request: "GET /index.php") execution timed out (130.098597 sec), terminating
修改php-fpm.ini中的request_terminate_timeout=0解决(不知道还有什么别的坑没有),默认是120

我尝试着用了swoole扩展解决异步,暂时没发现问题,但是要是用swoole的话,所有的服务器都得装,太麻烦了,先这样,如果再出现问题,在用swoole扩展试下

无数据传输
<?php
 
    $fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
  if (!$fp){
        echo 'error fsockopen';
  }else{
         //stream_set_blocking($fp,0);//为资源流设置阻塞或者阻塞模式
         $http = "GET /index.php HTTP/1.1\r\n";
         $http .= "Host:www.example.com\r\n";
         $http .= "Connection: Close\r\n\r\n";
         fwrite($fp,$http);
         //while (!feof($fp)) {
           //  echo fgets($fp, 128);

         // }
        //usleep(1000);//如果异步调用不成功,可以加上这句话

         fclose($fp);
  }
?>

get数据
<?php
$param = array(  
    'name' => 'xingdong'    
);  
  
$url = $url.'?'.http_build_query($param); 

    $fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
  if (!$fp){
        echo 'error fsockopen';
  }else{
         //stream_set_blocking($fp,0);//为资源流设置阻塞或者阻塞模式
         $http = "GET ${url} HTTP/1.1\r\n";
         $http .= "Host:www.example.com\r\n";
         $http .= "Connection: Close\r\n\r\n";
         //fputs($fp,$http);
         fwrite($fp,$http);
         fclose($fp);
  }

?>


post数据
<?php
$param = array(  
    'name' => 'xingdong'    
);  
  $data = http_build_query($param); 
$url = '/index.php'; 

    $fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
  if (!$fp){
        echo 'error fsockopen';
  }else{
         //stream_set_blocking($fp,0);//为资源流设置阻塞或者阻塞模式
         $http = "POST ${url} HTTP/1.1\r\n";
         $http .= "Host:www.example.com\r\n";
         $http .= "Connection: Close\r\n\r\n";
         $http .= "Content-type:application/x-www-form-urlencoded\r\n";  
         $http .= "Content-length:".strlen($data)."\r\n";  
         $http .= "Connection:close\r\n\r\n";  
         $http .= "${data}"; 
         //fputs($fp,$http);
         fwrite($fp,$http);
         fclose($fp);
  }

?>


php的$GLOBALS["HTTP_RAW_POST_DATA"]为空
php的$GLOBALS["HTTP_RAW_POST_DATA"]为空

微信公众号开发用$GLOBALS["HTTP_RAW_POST_DATA"]接收数据为空

解决方案
1.php7 的话改为  file_get_contents('php://input')
2.php.ini中设置 always_populate_raw_post_data = On,适用于php7之前版本,因为php7的时候废除了HTTP_RAW_POST_DATA


php DatePeriod类

php DatePeriod类 

获取一个日期列表

<?php


$start = new DateTime('2016-05-01');
//$interval  = new DateInterval('P1D'); //  P2W  正序日期,P1D间隔是天,P2W间隔是两周
$interval  = DateInterval::createFromDateString('-1 day'); // 倒序
$period  = new DatePeriod($start,$interval,3);
foreach ($period as  $dateTime) {
$date = $dateTime->format('Y-m-d');
echo $date;
echo "<br>"; 

}


php回调、匿名函数、闭包事例
<?php
//php回调、匿名函数、闭包 事例
class Product{
public $name;
public $price;
function __CONSTRUCT($name,$price){
$this->name = $name;
$this->price = $price;
}
}

class ProcessSale{
private $callbacks;
public function registerCallback($callback){
if(!is_callable($callback)){
throw new Exception("Error Processing Request", 1);
}
$this->callbacks[] = $callback;
}
public function sale($product){
print "{$product->name}:Processing <br>";
foreach ($this->callbacks as $callback) {
call_user_func($callback,$product);
}
}
}

class Totalizer{
static function warnAmount($amt){
$count = 0;
return function ($product) use ($amt,&$count){
$count += $product->price;
print "count : $count <br>";
if($count > $amt){
print "high price reached: {$count} <br>";
}
};
}
}

$processor = new ProcessSale();
$processor->registerCallback(Totalizer::warnAmount(8));
$processor->sale(new Product("shoes",6));
$processor->sale(new Product("coffes",6));



?>
关于php的延迟静态绑定
<?php
abstract class Shop{
public static function create(){
//new static(); static类似于self,但它指的是被调用的类而不是包含类。他的意思是将生成一个新的Shop2对象,而不是试图实例化一个shop对象
return new self();  
}
}
class Shop1 extends Shop{
public static function create(){
return  'shop1';
}
}
class Shop2 extends Shop{
public static function create(){
return  'shop2';
}
}

print_r(Shop2::create());

?>
php设计模式之单例模式简单示例
<?php
//单例模式 
class Singleton {

    private static $instance=null;
    private $value=null;
    
    private function __construct($value) {
        $this->value = $value;
    }

    public static function getInstance() {
        //echo self::$instance."<br/>";
        if ( self::$instance == null ) {
            echo "<br>new<br>";
            self::$instance = new Singleton("values");
        } else {
            echo "<br>old<br>";
        }
        return self::$instance;
    }
}

$x = Singleton::getInstance();
var_dump($x); // returns the new object


$y = Singleton::getInstance();
var_dump($y); // returns the existing object


?>

php几个实用少见的函数
1.函数的任意数目的参数 func_get_args()
你可能知道PHP允许你定义一个默认参数的函数。但你可能并不知道PHP还允许你定义一个完全任意的参数的函数
例子
<?php
function foo(){
   $numargs  =  func_num_args ();
   echo  "Number of arguments:  $numargs <br />\n" ;
   if ( $numargs  >=  2 ) {
       echo  "Second argument is: "  .  func_get_arg ( 1 ) .  "<br />\n" ;
   }
   $arg_list  =  func_get_args ();
   for ( $i  =  0 ;  $i  <  $numargs ;  $i ++) {
       echo  "Argument  $i  is: "  .  $arg_list [ $i ] .  "<br />\n" ;
   }
}
foo ( 1 ,  2 ,  3 );
?> 


2.使用 Glob() 查找文件
例子
// 取得所有的后缀为PHP的文件 
$files = glob('*.php');
// 取PHP文件和TXT文件 
$files = glob('*.{php,txt}', GLOB_BRACE); 
//还可以加上路径:
$files = glob('../images/a*.jpg'); 
//如果你想得到绝对路径,你可以调用?realpath() 函数:
$files = glob('../images/a*.jpg');       
// applies the function to each array element 
$files = array_map('realpath',$files); 


3. 内存使用信息
PHP 是有垃圾回收机制的,而且有一套很复杂的内存管理机制。你可以知道你的脚本所使用的内存情况。要知道当前内存使用情况,你可以使用? memory_get_usage() 函数,如果你想知道使用内存的峰值,你可以调用memory_get_peak_usage() 函数。

echo "Initial: ".memory_get_usage()." bytes \n"; 
/* 输出 
Initial: 361400 bytes 
*/ 
// 使用内存 
for ($i = 0; $i < 100000; $i++) { 
    $array []= md5($i); 

// 删除一半的内存 
for ($i = 0; $i < 100000; $i++) { 
    unset($array[$i]); 
}
echo "Final: ".memory_get_usage()." bytes \n"; 
/* prints 
Final: 885912 bytes 
*/  
echo "Peak: ".memory_get_peak_usage()." bytes \n"; 
/* 输出峰值 
Peak: 13687072 bytes 
*/


4.CPU使用信息
使用?getrusage() 函数可以让你知道CPU的使用情况。注意,这个功能在Windows下不可用。
例子
<?php
$dat  =  getrusage ();
echo  $dat [ "ru_nswap" ];          // number of swaps
echo  $dat [ "ru_majflt" ];         // number of page faults
echo  $dat [ "ru_utime.tv_sec" ];   // user time used (seconds)
echo  $dat [ "ru_utime.tv_usec" ];  // user time used (microseconds)
?> 

5.生成唯一的ID
有很多人使用 md5() 来生成一个唯一的ID,如下所示:
// generate unique string 
echo md5(time() . mt_rand(1,1000000)); 

其实,PHP中有一个叫?uniqid() 的函数是专门用来干这个的:
// generate unique string 
echo uniqid(); 
可以加上前缀
 // 前缀 
echo uniqid('foo_'); 
/* 输出 
foo_4bd67d6cd8b8f 
*/ 

// 有更多的熵 
echo uniqid('',true); 
/* 输出 
4bd67d6cd8b926.12135106 
*/ 

// 都有 
echo uniqid('bar_',true); 
/* 输出 
bar_4bd67da367b650.43684647 
*/ 


6.字符串压缩

当我们说到压缩,我们可能会想到文件压缩,其实,字符串也是可以压缩的。PHP提供了?gzcompress() 和 gzuncompress() 函数:
$string = '****这里是比较大的字符串';
$compressed = gzcompress($string);       
echo "Original size: ". strlen($string)."\n"; 
/* 输出原始大小 
Original size: 800 
*/ 
echo "Compressed size: ". strlen($compressed)."\n"; 
/* 输出压缩后的大小 
Compressed size: 418 
*/ 
// 解压缩 
$original = gzuncompress($compressed); 

几乎有50% 压缩比率。同时,你还可以使用?gzencode() 和 gzdecode() 函数来压缩,只不用其用了不同的压缩算法。



优惠券
最新微语