yii2 amqp 接收和发送数据(和外部系统对接)

  1. 配置queue(amqp)
'bootstrap' => [
        'queue', // The component registers own console commands
    ],
    
    'components' => [
        'queue' => [
            'class' => 'zhuravljov\yii\queue\amqp\Queue',
            'host'  => '192.168.221.56',
            'port'  => 5672,
            'user'  => 'admin',
            'password' => 'admin',
            'queueName' => 'productDropshipQN',
            'exchangeName' => 'productDropshipEX',
        ],
    ],

 

2.console  controller

 

<?php
/**
 * FecShop file.
 *
 * @link http://www.fecshop.com/
 * @copyright Copyright (c) 2016 FecShop Software LLC
 * @license http://www.fecshop.com/license/
 */

namespace fecshop\app\console\modules\Amqp\controllers;

use Yii;
use yii\console\Controller;
use fecshop\app\console\modules\Amqp\block\PushTest;

use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

/**
 * @author Terry Zhao <2358269014@qq.com>
 * @since 1.0
 * 这是一个测试RabbitMq 的一个例子。这里作为消息生产方。
 * 你可以通过执行 ./yii amqp/test/test 来生产数据。
 */
class TestController extends Controller
{
    const EXCHANGE_DIRECT = 'direct';
    const EXCHANGE_TOPIC = 'topic';
    const EXCHANGE_FANOUT = 'fanout';
    
    public $host = '192.168.221.56';
    public $port = 5672;
    public $user = 'admin';
    public $password        = 'admin';
    
    public $queueName       = 'productDropshipQN';
    public $exchangeName    = 'productDropshipEX';
    public $routingKey      = 'productDropshipRT';
    public $exchangeType    = self::EXCHANGE_DIRECT;
    
    /**
     * @var AMQPStreamConnection
     */
    private $connection;
    /**
     * @var AMQPChannel
     */
    private $channel;
    
     /**
     * 生产数据
     */
    public function actionTest()
    {
        Yii::$app->queue->push([
            'name'  => 'water',
            'age'   => 331,
        ]);
    }
    /**
     * 接收数据
     */
    public function actionListen()
    {
        $this->open();
        $callback = function(AMQPMessage $message) {
            if ($this->handleMessage($message->body)) {
                $message->delivery_info['channel']->basic_ack($message->delivery_info['delivery_tag']);
            }
        };
        $this->channel->basic_qos(null, 1, null);
        $this->channel->basic_consume($this->queueName, '', false, false, false, false, $callback);
        while(count($this->channel->callbacks)) {
            $this->channel->wait();
        }
        
    }
    
    
    /**
     * Opens connection and channel
     */
    protected function open()
    {
        if ($this->channel) return;
        $this->connection = new AMQPStreamConnection($this->host, $this->port, $this->user, $this->password);
        $this->channel = $this->connection->channel();
        $this->channel->queue_declare($this->queueName,true, true);
        $this->channel->exchange_declare($this->exchangeName, $this->exchangeType, false, true, false);
        $this->channel->queue_bind($this->queueName, $this->exchangeName,$this->routingKey);
    }
    /**
     * 这里处理接收到的数据
     */
    protected function handleMessage($message)
    {
        // $message = unserialize($message);
        var_dump($message);
        //  do some thing ...
        // \Yii::info($message,'fecshop_debug');
        return true;
    }
    
    
    
    /*
    public function actionListen3()
    {
          Yii::$app->queue->listen();
        
    }
    */
    
}

 

 

 

 

rabbitmq php 安装amqp扩展

一:安装rabbitmq-c-0.7.1

没有安装就会提示上面的错误
下载地址:https://github.com/alanxz/rabbitmq-c
我选择的是最新版本0.7.1

wget https://github.com/alanxz/rabbitmq-c/releases/download/v0.7.1/rabbitmq-c-0.7.1.tar.gz
tar zxf rabbitmq-c-0.7.1.tar.gz
 
cd rabbitmq-c-0.7.1
./configure --prefix=/usr/local/rabbitmq-c-0.7.1
make && make install

备注:如果下面的下载比较慢,您可以到百度云盘下载我下载下来的文件,云盘地址:http://pan.baidu.com/s/1kVwRD2Z#list/path=%2F,打开这个链接,找到文件rabbitmq-c-0.7.1.tar下载下来即可。

二:安装amqp

下载地址https://pecl.php.net/package/amqp
我选择的是1.6.1

!!!对于php7.1,需要下载高版本:

wget https://pecl.php.net/get/amqp-1.9.3.tgz   //php 7.1
wget https://pecl.php.net/get/amqp-1.6.1.tgz   // php 5.6
tar zxf amqp-1.6.1.tgz
cd amqp-1.6.1
 
/usr/local/php/bin/phpize
 
./configure --with-php-config=/usr/local/php/bin/php-config --with-amqp --with-librabbitmq-dir=/usr/local/rabbitmq-c-0.7.1

注意:这里的/usr/local/rabbitmq-c-0.7.1要跟上面rabbitmq-c安装的地址一样

make && make install

然后打开/etc/php.ini

添加配置:

extension=amqp.so

重启php,phpinfo就可以看到配置了

到这里就完成了,之前找了很多资料就会报错,唯有这个方式没有问题,我的linux是centos6,php版本5.4和7都安装通过了。

参考资料:https://www.phpsong.com/2223.html

php 7 环境安装

1.安装php:

yum 安装必备

yum install libxml2 libxml2-devel openssl openssl-devel bzip2 bzip2-devel libcurl libcurl-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel gmp gmp-devel libmcrypt libmcrypt-devel readline readline-devel libxslt libxslt-devel
yum  install ntp vim-enhanced gcc gcc-c++ gcc-g77 flex bison autoconf automake glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel libtool* zlib-devel libxml2-devel libjpeg-devel libpng-devel libtiff-devel fontconfig-devel freetype-devel libXpm-devel gettext-devel curl curl-devel pam-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel openldap openldap-devel nss_ldap openldap-clients openldap-servers gzip  make bzip2bzip2-devel pcre-devel wget ncurses-devel cmake make perl

 

yum -y install gcc automake autoconf libtool make   gcc-c++ glibc  libmcrypt-devel mhash-devel libxslt-devel libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel lib

上面的yum安装存在重复,不去细细排查了,您复制上面三个安装即可

wget -O php7.tar.gz http://cn2.php.net/get/php-7.1.1.tar.gz/from/this/mirror

解压

tar -xvf php7.tar.gz
cd php-7.1.1

编译:

./configure \
--prefix=/usr/local/php \
--with-config-file-path=/etc \
--enable-fpm \
--with-fpm-user=nginx \
--with-fpm-group=nginx \
--enable-inline-optimization \
--disable-debug \
--disable-rpath \
--enable-shared \
--enable-soap \
--with-libxml-dir \
--with-xmlrpc \
--with-openssl \
--with-mcrypt \
--with-mhash \
--with-pcre-regex \
--with-sqlite3 \
--with-zlib \
--enable-bcmath \
--with-iconv \
--with-bz2 \
--enable-calendar \
--with-curl \
--with-cdb \
--enable-dom \
--enable-exif \
--enable-fileinfo \
--enable-filter \
--with-pcre-dir \
--enable-ftp \
--with-gd \
--with-openssl-dir \
--with-jpeg-dir \
--with-png-dir \
--with-zlib-dir \
--with-freetype-dir \
--enable-gd-native-ttf \
--enable-gd-jis-conv \
--with-gettext \
--with-gmp \
--with-mhash \
--enable-json \
--enable-mbstring \
--enable-mbregex \
--enable-mbregex-backtrack \
--with-libmbfl \
--with-onig \
--enable-pdo \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd \
--with-zlib-dir \
--with-pdo-sqlite \
--with-readline \
--enable-session \
--enable-shmop \
--enable-simplexml \
--enable-sockets \
--enable-sysvmsg \
--enable-sysvsem \
--enable-sysvshm \
--enable-wddx \
--with-libxml-dir \
--with-xsl \
--enable-zip \
--enable-mysqlnd-compression-support \
--with-pear \
--enable-opcache

在centos7下面,会报错:Don’t know how to define struct flock on this system, set –enable-opcache=no

解决办法:vim /etc/ld.so.conf.d/local.conf # 编辑库文件
/usr/local/lib # 添加该行
:wq # 保存退出
ldconfig # 执行这个命令行,使之生效
!!记得编译完后不能移除这行,会导致php无法启动!!

 

make && make install

复制配置文件到/etc

cp php.ini-development /etc/php.ini

创建快捷方式:

ln -s /usr/local/php/bin/php  /usr/bin/php

配置php-fpm:

cp php.ini-production /etc/php.ini
cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf
cp /usr/local/php/etc/php-fpm.d/www.conf.default /usr/local/php/etc/php-fpm.d/www.conf
cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
chmod +x /etc/init.d/php-fpm

启动:

/etc/init.d/php-fpm start

2.安装扩展:

oauth
imap
mongodb
redis  (Yii2 不安装redis扩展也是可以用的,可以不用安装)

2.1安装oauth扩展:

wget http://pecl.php.net/get/oauth-2.0.2.tgz
tar -zxf oauth-2.0.2.tgz 
cd oauth-2.0.2
/usr/local/php/bin/phpize  
./configure --with-php-config=/usr/local/php/bin/php-config  
make && make install  
vim /etc/php.ini  # 添加 extension=oauth.so
/etc/init.d/php-fpm restart

2.2 安装imap 扩展

cd php-7.1.1/ext/imap
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config --with-imap=/usr/lib64 --with-imap-ssl --with-kerberos
make && make install
vim /etc/php.ini
extension=imap.so

如果报错:Cannot find imap library (libc-client.a)

 yum install libc-client-devel.x86_64
ln -s /usr/lib64/libc-client.so /usr/lib/libc-client.so

 

2.3 安装 mongodb

wget https://pecl.php.net/get/mongodb-1.2.5.tgz
tar zxvf mongodb-1.2.5.tgz
cd mongodb-1.2.5
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make && make install

vim /etc/php.ini
extension=mongodb.so

 

3. 配置

3.1 mysql的配置,要使用127.0.0.1 不要使用localhost

localhost 会使用unix socket,而不是tcp连接。

4.到这里基本就都配置好了。

 

 

css js 后面加版本号的原因和方式

在网站加载的时候,为了快速,浏览器一般会缓存js和css,但是,我们网站如果更新了css和js,怎么告诉浏览器呢、?我么可以通过js和css url的参数方式来解决。

譬如:

/assets/dbdba3fa/js/js.js?v=2

在fecshop中,可以通过参数配置的方式,全部更改js和css的版本号。

如果我们更改了js,那么我们修改为

/assets/dbdba3fa/js/js.js?v=3

,由于是不同的链接,浏览器本地没有这个链接的内容,自然就会去服务器获取这个js的内容。

这也就是为什么我们看到很多网站的css和js后面带这个奇怪的v参数的原因。

Yii2 账号登录需要注意的地方 – 生成密码函数generatePasswordHash很慢

Yii2默认的用户组件,在登录用户,都需要先把密码加密,然后去数据查询核对,

密码加密的代码如下:

\Yii::$app->security->generatePasswordHash($password);

Yii2/base/Security.php

public function generatePasswordHash($password, $cost = null)
    {
        if ($cost === null) {
            $cost = $this->passwordHashCost;
        }

        if (function_exists('password_hash')) {
            /** @noinspection PhpUndefinedConstantInspection */
            return password_hash($password, PASSWORD_DEFAULT, ['cost' => $cost]);
        }

        $salt = $this->generateSalt($cost);
        $hash = crypt($password, $salt);
        // strlen() is safe since crypt() returns only ascii
        if (!is_string($hash) || strlen($hash) !== 60) {
            throw new Exception('Unknown error occurred while generating hash.');
        }

        return $hash;
    }

最后,发现代码耗时卡在   $hash = crypt($password, $salt);

也即是php的crypt函数。在我的linux上面耗费了520ms

现在的系统验证码,有很多包,是可以破的,玩爬虫的,都有付费的机器学习类的破验证码,普通的文字数字验证码,很轻松能破,验证码一破,账号注册登录被爬虫搞起来,很快就把php进程堵死了。

如果你的系统,登录注册很频繁,建议重写一下这个函数,不过是否在某些方面存在安全性,这个我说不好,自己取舍一下。

上面是我测试的结果,大家有兴趣可以都测试试试。

顶级PHP大师的开发原则

1. 在合适的时候使用PHP – Rasmus Lerdorf

没有谁比PHP的创建者Rasmus Lerdorf明白PHP用在什么地方是更合理的,他于1995年发布了PHP这门语言,从那时起,PHP就像燎原之火,烧遍了整个开发阵营,改变了互联 网的世界。可是,Rasmus并不是因此而创建PHP的。PHP是为了解决web开发者的实际问题而诞生的。

和许多开源项目一样,PHP变得流行,流行的动机并不能用正常的哲学来进行解释,甚至流行得有些孤芳自赏。它完全可以作为一个案例,一个解决各种Web问题的工具需求所引起的案例,因此当PHP刚出现的时候,这种工具需求全部聚焦到PHP的身上。

但是,你不能奢望PHP可以解决所有问题。Lerdorf是第一个承认PHP只是一种工具的人,并且PHP也有很多力所不能及的情况。

根据工作的不同来选择合适的工具。我跑了很多家公司,为了说服他们部署和使用PHP,但是这并不意味着PHP对所有问题都适用。它只是可以一个解决大部分问题的front-end脚步语言。

作为一个web开发者,尝试用PHP解决所有问题是不科学的,同时也会浪费你的时间。当PHP玩不转的时候,不要犹豫,试用一下其他的语言吧。

2. 使用多表存储提高规模伸缩性 – Matt Mullenweg

没有人愿意质疑Matt Mullenweg在PHP方面的权威性,他开发了这个星球上最流行的blog系统,(依靠一个强大的社区力量支持): WordPress. 创建Wordpress以后,Matt和他的团队启动了WordPress.com平台,一个基于WordPress MU的免费blog站点。现在,Wordpress.com已经拥有大约400万用户, 这些用户每天提供超过 140,000篇的日志。 (要查看更多Wordpress.com的统计情况,请点击这里.)

如果有人知道如何让网站的规模伸缩自如,这个人一定是Matt Mullenweg。2006年的时候 Matt对Wordpress的数据结构进行了前瞻性的改进,并且解释了为什么Wordpress MU对每个blog使用独立的MYSQL表格, 而不是把所有的blog数据都塞进一个巨大的表格。

我们测试过这个方法,但是发现如果要扩展它的伸缩性,代价太高。如果用一个整体的数据结构,在大流量面前,你将会面临服务器 硬件的问题。在MU里面。用户们都被分布到独立的表格当中,并且可以轻易地组织起来。举个例子,WordPress.com把用户的数据分散存储到 4096个数据库中,这些数据库可以分散大规模的数据访问,实现流量和压力分流。

数据表的可迁移性让代码(blog)可以运行得更快,并且让系统具备更强的伸缩性。依靠强大的缓存策略和灵活的数据库运用策略, Matt向人们展示了时下最流行的Facebook和Wordpress.com都可以在PHP下稳定运行,并且处理惊人的访问量。

3. 千万不要相信用户 – Dave Child

Dave Child是Added Bytes (previously ilovejackdaniels.com) 网站的核心人物,这个网站以他出色的《cheat sheets for many programming languages》而闻名。 Dave为很多英国的公司服务,并且已经在编程世界里树立起相当的权威。

Dave为PHP开发者提供了很多深谋远虑的建议,并总结成了《writing secure code in PHP》:千万不要相信你的用户,他们甚至可能会伤害你。

有一条web开发的基本原则,我重复多少遍都觉得不够,那就是:千万不要相信你的用户,同时要假设你网站中的每个数据单元都是从用户那里收集来 的恶意代码。很多时候,你必须用javascript在客户端检验表单提交过来的内容, 如果你习惯了如此,那么,这是一个好习惯。如果安全性对你来说很重要,这就是最重要最需要学习的原则。

Dave目前正致力于为它的《Writing Secure PHP》系列书籍整理实例,书的最后他说:

最后,变得偏执一点吧。除非你认为你的站点永远不会受到攻击,否则就正视所有的问题,当问题真正发生的时候,你的情况会变得很糟。你需要把每个用户都看成会带来一场攻防站的黑客,想尽一切办法来保护站点的安全,同时想好相应问题的解决方案。

 4. 多使用PHP缓存 – Ben Balbo

Ben Balbo开发了Site Point,一个为developers和designers提供指导的网站。他是墨尔本PHP开发和开源俱乐部的成员, 因此他对PHP有一定的了解,同时对PHP caching有一定的想法和经验。

如果你拥有一个访问量很大,但更新并不频繁的站点(比如blog,基于某种CMS),或许它需要进行一些改造,这些改造不会花费太多的时间,但是对性能有突出的贡献。 如果要为一个复杂/更新频率很快的站点建立缓存机制,过程可能会很曲折,但是好处也是显而易见的。

PHP缓存技术有很多种,Ben为我们推荐了如下一些:

◆缓存函数的运行结果

◆设置过期时间

◆缓存IE下载的文件

◆模板缓存技术

◆Cache_Lite

由于PHP作为动态语言的特性,缓存机制对于更新频率并不快的站点来说非常重要。

5. 使用IDE, Templates和Snippets加速PHP开发 – Chad Kieffer

当Chad Kieffer从UI设计和数据库优化的工作中抽身出来的时候,他会在他的博客2 tablespoons上分享很多技术经验。由于Chad多方面的全面发展,他经常可以发现其他程序员不能发现的问题,并形成相关经验,尤其是他开发网站 的方法。他参与了网站开发的各个环节,因此他的建议对于提高网站开发的大局观非常有用。

Chad认为使用Eclipse PDT(Eclipse’s PHP development package) 这样的IDE,同时使用一些模板技术和开源项目可以有效地提高PHP的开发速度。

紧凑的计划,长长的to do lists以及deadlines让开发人员非常苦闷。不过有些功能,比如Eclipse Templates,可以有效减少编码的时间和出错的几率。

通常来说,任何项目都可以自动化,自动化程度越高, 你完成项目的时间就越短。花时间来开发使用频率很高的框架和模板,将会节省你以后更多时间。同时,使用像Eclipse and the PDT package这样的IDE,你会发现效率得到明显提高,IDE可以自动闭合,补全分号并且可以在本地debug。

 6. 利用好PHP的过滤函数 – Joey Sochacki

或许Joey Sochacki并不像Matt Mullenweg那样有名 ,但他也是一个经验丰富的开发者,并且通过他的博客Devolio分享了很多技术经验

Joey发现在编写php代码的过程中有很多地方需要进行过滤,但却并没有太多的coder关注php的内置过滤函数。

过滤数据是我们经常需要做的事情,但是很多功能丰富的PHP内置过滤函数却不为人知。使用类似filter_* 的PHP内置函数,我们几乎可以处理所有的过滤任务,包括数据类型验证/URL/email和IP地址验证/特殊字符处理等等。

过滤是一件复杂的事情,但是我相信joey的发现会给你很多启发,让你认识到PHP强大的过滤功能。

7. 使用PHP框架 – Josh Sharp

对于是否应该使用Zend, CakePHP, Code Igniter, 或者 其他PHP框架,一直存在着很多争议,但是在web开发者的心中,他们有自己衡量的标准。

Josh Sharp自己创建了一家提供面包和黄油服务的网站,因此他对于使用PHP框架来开发网站有一定的经验。他认为使用一个PHP框架来进行项目开发(use a PHP framework ),可以有效地节省时间,并且减少出错的几率。为什么?因为他觉得PHP实在是太好上手了。

PHP的易于使用有时候也有缺陷,因为并不严格的语法,经常会导致很多错误代码的诞生。但如果使用一个PHP框架,出错的几率就会大大减少。

PHP框架可以让你的代码结构更加规范,并且节省大量时间。

8. 不要使用PHP框架 – Rasmus Lerdorf

与Josh的观点恰恰相反,PHP的鼻祖Rasmus Lerdorf却认为最好不要使用PHP框架,为什么?因为不基于框架的PHP性能更好。Rasmus在Drupalcon 2008的演讲上,用“Hello World”的例子来对比了一些框架PHP和简单PHP之间的性能,结果显示框架PHP的性能要远远落后。

9. 使用批处理 – Jack D. Herrington

Jack Herrington对PHP世界并不陌生, 并且为大名鼎鼎的IBM developerWorks贡献过超过30篇的专搞, 同时出版过《PHP Hacks》的书,因此他是一个真正的专家。

Herrington推荐使用批处理和Cron来代替那些可以运行在后台的程序脚步,Web用户并不愿意在线等待你的处理过程,所以有些事情更适合放到后台来处理。

诚然,在某些情况下,这有点大材小用了,但是你可以清楚地看到,使用Cron, MySQL, PHP面向对象的方法以及Pear::DB这些便捷的工具来创建一个批处理工具并不是一件复杂的事情。

Jack认为使用cron, PHP和MySQL在后台处理一些任务,比起多进程的业务逻辑要划算得多。

两种方法我都尝试过,我认为Cron非常符合”Keep It Simple, Stupid” (KISS) 的原则,它让后台处理变得简单。与多进程的业务逻辑相比,它没有内存 溢出的风险。你可以创建一个简单的批处理脚本,并且在cron中运行,这个脚本会定时检查是否有任务需要处理,处理完之后就会自动退出,因此你不用担心是 否有进程卡壳,或者陷入死循环。

 10. 及时启用错误报告 – David Cummings

David Cummings有一个专门提供CMS软件服务的公司 ,并且获得过几次奖 ,他有非常丰富的PHP开发经验。David曾经写过《two PHP tips he wished he’d learned in the beginning》,其中一点就是:及时启用错误报告,这会节省大量的时间。

我告诉人们,最重要的事情就是最大程度地开启PHP的错误报告,为什么?因为PHP可能会隐藏很多小问题:

◆变量没有预定义

◆在代码片段中引用了不可用的变量

◆使用了未定义的常量这些因素看起来并不是什么大事,除非你在使用面向对象的方法编写一些类库。通常,关闭错误报告将可能使你付出更大的成本来维护你的代码。

错误报告可以帮你轻易地找到代码的问题所在,如果错误报告的等级够高,细微的错误都能被立即发现,帮助你节省整体debug的时间。

yii2 AR 结构进行数据类型转换的原理(PDO)

通过PDO,默认出来的数据都是string类型,在Yii2的AR(Active Record)中,按照类型进行了数据转换,但是如果查询的时候使用了asArray(),则不会进行转换,也就是说

User::find()->asArray()->all()

查询的结果,包括id在内的所有结果,都是字符串类型

User::find()->all() ,返回的是对象数组,结果会进行类型转换

ActiveRecord转换的原理为下面:

yii\db\ActiveRecord

public static function populateRecord($record, $row)
   {
       $columns = static::getTableSchema()->columns;
       foreach ($row as $name => $value) {
           if (isset($columns[$name])) {
               $row[$name] = $columns[$name]->phpTypecast($value);
           }
       }
       parent::populateRecord($record, $row);
   }

通过上面的方法进行了类型的转换,也就是phpTypecast方法。

 

如果查询的时候加上了asArray(),则不会进行类型转换,出来的数据都是String

譬如代码:

$data = \fecadmin\models\AdminMicroRoleBrand::find()->asArray()
          ->where([
            'in','role_id',$micro_role_arr
          ])->all();

出来的是数据都是字符串

如果按照下面的代码,查询出来的对象里面的属性都是相应的数据库的类型:

$data = \fecadmin\models\AdminMicroRoleBrand::find()
          ->where([
            'in','role_id',$micro_role_arr
          ])->all();

所以,在加入asArray()查询的时候,速度是最快的,但是要注意一下数据类型,适当的时候需要手动转换。