php

03 28,2019

消息队列RabbitMQ(三):PHP的使用示例

之前的文章已经介绍RabbitMQ以及安装,本文就介绍PHP使用RabbitMQ的示例。

安装PHP的RabbitMQ扩展

本文介绍AMQP 0-9-1,这是一个开放的、通用的协议消息,这里我们使用php-amqplib这个PHP扩展。更多PHPAMQP扩展见官网

通过composer安装

composer require php-amqplib/php-amqplib -vvv

如果你还不知道composer,那就out了。:)

Publisher(生产者,消息发送方)

创建publisher.php文件,并引入composer自动加载文件

require_once __DIR__ . '/vendor/autoload.php';

use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Exchange\AMQPExchangeType;
use PhpAmqpLib\Message\AMQPMessage;

Connection(创建连接)

创建RabbitMQ连接以及channel通道,AQMP的命令都是通过通道发出去的。

$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
// 创建通道
$channel = $connection->channel();

Send(发送消息)

发消息前,我们必须声明一个队列为我们发送做准备;然后我们可以向队列发布消息:

/**
 * 创建队列(Queue)
 * name: hello         // 队列名称
 * passive: false      // 如果设置true存在则返回OK,否则就报错。设置false存在返回OK,不存在则自动创建
 * durable: true       // 是否持久化,设置false是存放到内存中的,RabbitMQ重启后会丢失
 * exclusive: false    // 是否排他,指定该选项为true则队列只对当前连接有效,连接断开后自动删除
 *  auto_delete: false // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
 */
$channel->queue_declare('hello', false, false, false, false);

/**
 * 创建交换机(Exchange)
 * name: vckai_exchange// 交换机名称
 * type: direct        // 交换机类型,分别为direct/fanout/topic,参考另外文章的Exchange Type说明。
 * passive: false      // 如果设置true存在则返回OK,否则就报错。设置false存在返回OK,不存在则自动创建
 * durable: false      // 是否持久化,设置false是存放到内存中的,RabbitMQ重启后会丢失
 * auto_delete: false  // 是否自动删除,当最后一个消费者断开连接之后队列是否自动被删除
 */
$channel->exchange_declare('vckai_exchange', AMQPExchangeType::DIRECT, false, false, false);

// 绑定消息交换机和队列
$channel->queue_bind('hello', 'vckai_exchange');

/**
 * 创建AMQP消息类型
 * delivery_mode 消息是否持久化
 * AMQPMessage::DELIVERY_MODE_NON_PERSISTENT  不持久化
 * AMQPMessage::DELIVERY_MODE_PERSISTENT      持久化 
 */
$msg = new AMQPMessage('Hello World!', ['delivery_mode' => AMQPMessage:: DELIVERY_MODE_NON_PERSISTENT]);

/**
 * 发送消息
 * msg: $msg                // AMQP消息内容
 * exchange: vckai_exchange // 交换机名称
 * queue: hello             // 队列名称
 */
$channel->basic_publish($msg, 'vckai_exchange', 'hello');

echo " [x] Sent 'Hello World!'\n";

这里需要特别说明的是关于Exchange、Queue和Message持久化的问题

如过将Queue的持久化标识durable设置为true,则代表是一个持久的队列,那么在服务重启之后,也会存在,因为服务会把持久化的Queue存放在硬盘上,当服务重启的时候,会重新加载之前被持久化的Queue。

队列是可以被持久化,但是里面的消息是否为持久化那还要看消息的持久化设置。也就是说,重启之前那个Queue里面还没有发出去的消息的话,重启之后那队列里面是不是还存在原来的消息,这个就要取决于发生着在发送消息时对消息的设置了。

上面阐述了队列的持久化和消息的持久化,如果不设置Exchange的持久化对消息的可靠性来说没有什么影响,但是同样如果Exchange不设置持久化,那么当Broker服务重启之后,Exchange将不复存在,那么既而发送方RabbitMQ Producer就无法正常发送消息。

Close(关闭链接)

$channel->close();
$connection->close();
04 26,2016

WEB/APP开发安全

最近公司被攻击了,然后才发现公司代码简直一点安全防范意识都没有,连基本的SQL,XSS过滤都没有,发现大部分PHP程序员都缺乏安全相关的了解。下面就我们遇到的一些攻击进行科普以及防范方案。

SQL注入

SQL注入是WEB攻击中最常见的注入方式。也是我们这次被攻击中最多的。
由于我们的程序中大部分都是进行拼装SQL的方式,然后对于用户输入的参数也没有进行过滤,导致给攻击者留下了漏洞。
具体为,登录的操作,一般是通过POST方式将username和password传递过来。

SELECT * FROM user WHERE username='$username' AND password='$password'

正常情况下,我们希望执行的SQL是

SELECT * FROM user WHERE username='vckai' AND password='123456'

但是如果攻击者传递的用户为非法用户名vckai' or 1=1--,在SQL里面—是注释标记,所以查询语句会在此中断。这就让攻击者在不知道任何合法用户名和密码的情况下成功登录了。

SELECT * FROM user WHERE username='vckai' or 1=1--' AND password='123456'

甚至于,攻击者可以用同样的方式执行其他SQL,查询出你其他DB和表数据。

现在知道SQL注入的危害了,那怎么预防呢?

  • 首先在PHP中,首先对于int类型的数据,一定要在接收数据的时候进行(int) $_POST['pagesize']进行强转义。
  • 根据业务做参数验证,如用户名一般只允许4-20位字符和数字。这样攻击者就没办法根据这个进行注入了。
  • 虽然MySQL和PHP本身由提供过滤函数addslashesmysql_real_escape_string进行转义,但是仍然有被绕过的风险,所以最佳方法是使用PDO的预处理。

XSS攻击

XSS通常可以分为两大类:一类是存储型XSS,主要出现在让用户输入数据,供其他浏览此页的用户进行查看的地方,包括留言、评论、博客日志和各类表单等。应用程序从数据库中查询数据,在页面中显示出来,攻击者在相关页面输入恶意的脚本数据后,用户浏览此类页面时就可能受到攻击。这个流程简单可以描述为:恶意用户的Html输入Web程序->进入数据库->Web程序->用户浏览器。另一类是反射型XSS,主要做法是将脚本代码加入URL地址的请求参数里,请求参数进入程序后在页面直接输出,用户点击类似的恶意链接就可能受到攻击。

XSS目前主要的手段和目的如下:

  • 盗用cookie,获取敏感信息。
  • 利用植入Flash,通过crossdomain权限设置进一步获取更高权限;或者利用Java等得到类似的操作。
  • 利用iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻击者)用户的身份执行一些管理动作,或执行一些如:发微博、加好友、发私信等常规操作,前段时间新浪微博就遭遇过一次XSS。
  • 利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动。
  • 在访问量极大的一些页面上的XSS可以攻击一些小型网站,实现DDoS攻击的效果

如何预防XSS攻击
答案很简单,坚决不要相信用户的任何输入,并过滤掉输入中的所有特殊字符。这样就能消灭绝大部分的XSS攻击。

  • 使用htmlspecialchars函数进行参数过滤,将<>转换为HTML实体。注意,有一些APP开发的时候,会直接输出HTML实体,导致用户正常数据处理错误,所以返回给APP的时候,建议再转义回来htmlspecialchars_decode,或者让客户端做统一处理。
03 30,2016

使用GDB调试PHP core dump

最近线上服务器出现了访问不上的情况,查看php-fpm发现大量的WARNING: [pool www] child 11274 exited on signal 31 (SIGSYS) after 0.089068 seconds from start错误,然后php-fpm进程在不断的重启。

查看PHP的错误日记并没有太多可用信息,既然如此那就尝试抓取core dump使用gdb调试看下吧。

关于core dump

我们经常听到大家说到程序core掉了,需要定位解决,这里说的大部分是指对应程序由于各种异常或者bug导致在运行过程中异常退出或者中止,并且在满足一定条件下(这里为什么说需要满足一定的条件呢?下面会分析)会产生一个叫做core的文件。

通常情况下,core文件会包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息还有各种函数调用堆栈信息等,我们可以理解为是程序工作当前状态存储生成第一个文件,许多的程序出错的时候都会产生一个core文件,通过工具分析这个文件,我们可以定位到程序异常退出的时候对应的堆栈调用等信息,找出问题所在并进行及时解决。

core dump默认是不生成的文件,所以首先我们要开启下。

设置core dump路径

# echo "/tmp/core.%p" > /proc/sys/kernel/core_pattern

修改ulimit允许生成core dump文件

# ulimit -c unlimited

重启php-fpm。 过一会进入/tmp,就会发现生成很多core.xxx的文件。这个时候设置关闭core dump并重启php-fpm。

# ulimit -c 0

这个时候就可以使用gdb进行调试core dump,注意因为生成core dump的是php-fpm,所以这里需要使用php-fpm进行调试。如果在cli模式使用php生成的core dump才是使用php程序进行调试。

01 06,2015

centos6安装nginx1.7.9+php5.6+mysql5.6

该文章是由于我在docker安装LNMP环境时出现的,原型是张宴大哥这篇文章:http://zyan.cc/nginx_php_v7/ ,只是做了一些软件升级变更。

软件版本

CentOS 6
NGINX 1.7.9
PHP 5.6.2
MySQL 5.6.2

安装关联库

# mkdir -p /data/tgz
# cd /data/tgz
# yum install wget
# yum install pcre
# yum install openssl*
# yum install tar
# yum -y install gcc gcc-c++ autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel openldap openldap-devel nss_ldap openldap-clients openldap-servers make gd gd2 gd-devel gd2-devel

# ulimit -SHn 65535
# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.36.tar.gz
# tar zxvf pcre-8.36.tar.gz
# cd pcre-8.36
# ./configure --prefix=/data/apps/pcre
# make && make install
# cd ../
12 28,2014

Docker创建centos的LNMP镜像

前段时间重装了系统,今天刚好有时间,就用docker安装一个lnmp开发环境,下面是我的安装笔记。

安装docker

这个就不说了,不会的可以看下我之前的文章《Docker介绍及安装》。

启动docker

# service docker start

下载docker镜像

官网docker镜像网站:https://www.docker.com/ ,可以在这里查看官网或者第三方的docker镜像。当然如果没有VPN,网络比较慢的情况下,可以考虑使用:https://docker.cn/ ,这是一个国内的镜像网站。

# docker pull docker.cn/docker/centos:centos6

说明:docker pull命令是从远程下载镜像的命令,类似git pull。docker.cn/docker/centos 是国内镜像网站centos镜像的地址,如果要下载官方centos镜像,直接使用centos即可。:centos6是指这个镜像的tag,我下载的是centos6,如果要下载最新版本,可以使用:latest或者:centos7

下一页