PHP Data Object

PDO一是PHP数据对象(PHP Data Object)的缩写。

因为最近再用laravel/lumen框架,所以我觉得有必要把这东西重新梳理一下,以便能够更精确地处理各个细节。

1、创建连接

原型:

dsn 有多种方式可以来实现。
1、标准dsnmysql:dbname=testdb;host=127.0.0.1;port=3306
2、文件模式。将标准dsn写入文件,然后使用uri:file:///path/to/dsnfile来导入。
3、将信息定义在php.ini中。不能是在 .htaccesshttpd.conf 中 。

username 用户名, password 密码, driver_options 选项(将在下文说明)。

这里只进行对标准dsn的实现。

创建成功返货一个PDO对象。创建失败者会抛出一个PDOException异常。

2、执行SQL语句

执行成功将返回受影响行数,执行失败将返回布尔类型false
exec可执行包括但不仅限于insertupdatedelete等类型的SQL
select语句无效。

可是使用lastInsertId来获取insert语句的自增ID

对于执行失败的语句可以使用errorCodeerrorInfo来获取错误信息。

3、查询SQL语句

query查询失败返回false, 查询成功后pdo会返回一个statement对象。statement对象实现了Traversable接口,所以我们可以通过foreach遍历来获取数据。

另外,官方文档中说到Traversable接口无法在 PHP 脚本中实现的内部引擎接口。IteratorAggregateIterator 接口可以用来代替它。

刚刚说到exec方法,可以执行insertupdatedelete等类型的SQL,但是不能执行selectSQL。而query方法这个2种都可以执行。

4、PDOStatement

PDOStatement代表一条预处理语句,并在该语句被执行后代表一个相关的结果集。

上面无论exec方法,还是query方法都存在sql注入的风险。使用预处理执行就可以消除这种风险。

prepareexecute这2个方法,是核心方法。

预处理执行有2种占位符:一种是命名参数占位符、还有一种是问号占位符。下面进行代码演示。

fetch方法获取一个结果,并将指针移向下一个结果。
fecthAll方法获取所有结果。

这2个方法可以传入参数fetch_style,来控制返回数据的格式。

除了可以在execute传参的方式来绑定参数,还可以使用bindParambindColumnbindValue3个方法来绑定参数。

bindValue 对应 命名参数占位符
bindColumn 对应 问号占位符
bindParam 2者都可以

这里主要说明下演示bindParam

这里需要说明下,bindParam有3个参数。

第一个参数传入绑定变量名称,如果是问号占位符, 从索引1开始递增。
第二个参数, 变量, 不能直接传值
第三个参数, 可选, 变量类型 PDO::PARAM_STR、 PDO::PARAM_INT …

预处理不仅可以执行select语句,也可以执行insertupdatedelete语句。
并且提供了debugDumpParams方法可以用来调试。

5、设置数据库连接属性

连接属性可以在初始化pdo对象的时候设置,也可以使用getAttributesetAttribute进行设置查看。

上面是可以设置的属性,但是对于mysql数据库来说,并不是所有属性都可以设置的。

6、错误模式

PDO有3中错误模式:PDO::ERRMODE_SLINETPDO::ERRMODE_WARNINGPDO::ERRMODE_EXCEPTION

PDO::ERRMODE_SLINET是静默模式,pdo的默认模式,在这种模式下,sql执行失败返回结果为false

PDO::ERRMODE_WARNING是警告模式。在这种模式下,sql执行失败返回结果为false并且会抛出一个warning的错误,但是不影响程序执行。

PDO::ERRMODE_EXCEPTION是异常模式。在这种模式下,sql执行失败会抛出一个PDOException的知名错误,如果不将它捕获,程序将停止执行。laravel/lumen框架默认为异常模式。

6、事务

这里只是一个简单的示例,事务涉及很多方面,不在这里扩展叙述了。

pipe和fifo

简介

pipe称之为无名管道fifofirst in first out的缩写,称之为有名管道

pipe是最初的进程间通信IPC形式,但是由于他没有名字,所以只能局限于有亲缘关系的进程间使用(父子进程)。之后引入了fifo,就解决了这个问题。

历史上的pipe通常是指半双工管道,只允许数据单向流动。现代系统大都提供全双工管道,数据可以沿着管道双向流动。

fifo是半双工的

pipe

原型

fd[2]为两个文件描述符:fd[0]fd[1],前者打开负责读,后者打开负责写。

1、单进程内单向数据流

2、父子进程间的数据流
尽管管道是有单个进程创建的,却很少在单个进程内使用,下图将展示父子进程间的管道通信。

3、父子进程间的单向数据流
如果说父进程关闭读,子进程关闭写,那么父子进程就提供了一个单向数据流。如下图

4、*nix系统shell管道数据流

假设命令为:

fifo

原型

pathname是一个普通的路径名称,它是这个fifo的名字。
mode是指文件的权限位

fifo的模型大致与pipe类似,它的真正优势表现在服务端可以长期运行一个进程,与客户端无亲缘关系。建立一个经典的C/S架构

客户端将自己的pid告诉服务端,服务端可以通过组合找到客户端fifo名称,然后继续传出信息。

fifo需要注意一下几点

1、 fifo的写操作是原子性的,也就是说2个客户端发送消息,不会混乱在一起。
2、 fifo不支持nfs文件系统。fifo只能在单台主机上使用的IPC形式。
3、 当2个客户端几乎同时向服务端发送请求,第一台发送10M数据,需要10秒,第二台发送10字节,只需要1秒,那么第二台必须等待第一台完成发送后才能被处理。这种形式叫做迭代服务端。可以将其改造为并发服务端来解决这个问题。最常见的方式是,服务端为每一个发送数据的客户端fork一个子进程来接收数据。
4、 fifo的容量是有限的,为64K,并且不能修改。

php实现

代码已经上传到packagist.org

只需要composer require pangou/fifo 下来就可以了。

主要为2点:
1、 createFifo方法主要思路:
1) 判断fifo文件是否存在,类型是否为fifo,不是这备份后删除
2) 判断fifo文件是否存在,不存在则创建,创建失败抛异常
3) 判断文件类型是否为fifo,不是抛异常
2、 *nix系统一切皆文件的观点,所以fifo也是以文件读取写入的方式进行交互。

案例一、 单进程交互

需要注意的是read方法必须传入正好能够接收消息的长度。过长则进程进入阻塞状态,无数据写入的话永远阻塞着了。过短则,无法接受完整数据。

案例二、父子进程交互

非亲缘关系进程交互与父子进程交互类似,只是分为2个文件执行而已。

传输协议

上面2个示例中可以看到,接收数据方,必须传入节后数据大小才可以接收完成数据。但是真实环境中怎么可能知道需要接收多少字节?

这里引入了数据长度传输协议,消息体前N个字节为消息长度,那么就可以完美解决这个问题了。

重新改造fifo

使用方式

压测

曾经也做过一篇关于共享内存文件MemcacheCache的压测, 天然的memcache —— /dev/shm

由于管道也是存在于内核中的所以性能还算不错,10W次读写0.4秒左右。是/dev/shm性能的双倍。当然这个使用场景不一样,完全没有可比性 : ) 。

PHP中的Promise

简介

前几天看到一篇文章理解 Promise 的工作原理,想起了之前自己写过的一篇文章jQuery.Deferred对象DeferredjQueryPromise的实现。我就在想世界上最好的语言没有对这东西的实现吗?

一查,果然发现2个比较靠谱的库react/promiseguzzlehttp/promises。看了一下文档比较一下之后,觉得react/promise跟靠近Promise的实现。而guzzlehttp/promises库中可以对promise对象进行resolvereject的,这个是有误的,具体参考文章jQuery.Deferred对象,里面有说,哈哈哈哈~~~。

基本用法

创建一个项目文件夹,初始化项目,下载react/promise

1、 回调金字塔

上面代码虽然实现了功能,但是结构复杂。如果用promise来实现就相对简单多了。

react/promise提供了一个promise的变种FulfilledPromise。这个promse默认为fulfilled状态,是操作更简单。

2、 传值

then方法会把上一次return的结果自动传递至下一个方法中。

3、受保护的

为了保证Deferred对象不被误操作,通常在方法内部创建Deferred对象,返回promise对象。那么Deferred对象就可以只受本方法操作,不会受到误操作的影响。

4、 延迟执行

上面方法中当获取到promise的时候,getPromise方法就已经被执行了。
react/promise提供了一种延迟执行的方法。

当获取到promise的时候,方法本体还没有被执行。当调用then的时候才会被去执行。

其实我觉得这并没有什么意义。

高级用法

php由于本身并没有像JavaScript中的Ajax那样的EventLoop事件,上面那些东西都是同步执行,最多只是执行时间的早晚区别。并没有发挥Promse最大的优势。

但是,。。。。。
转折来了~~~
php提供了很多扩展比如libevent扩展、swoole扩展等,这些都可以帮我们实现。

react/event-loop库是对lebevent扩展的封装,我们可以用它来实现一些高级用法。

1、准备

并且php需要安装上libevent扩展。

2、 真正延迟执行

在这个时候,我们可以使用notify方法和外面进行通讯,让外部感知内部执行进度。

创建自己的Composer包

事先准备:

  1. Github帐号 以及 composer帐号
  2. git 以及 composer

第一步:

创建一个Github库,并且创建项目上传到Github上。

在本地创建项目

第二部:

初始化composer.json

初始化完成后再次提交到Github

第三部:

Github上的项目提交到packagist.org上。

1、 点击submit, 输入仓库地址

2、 确认提交

3、 成功提交

4、 在Github注册hook,当我们对仓库触发事件时候,同步到packagist.org

第四步:

完成composer项目

1、 编辑 composer.json 添加需要的信息

在这里我加上了这个项目的autoload规则。

可以看到,我使用了psr-4规则。那么要想通过autoload访问它,必须把命名空间写成namespace Pangou\HelloWorld;

2、 完成项目内容

通过autoload的规则,我们创建src目录,并且在src目录下创建了Greeting.php

3、 上传至Github

由于我们之前设置了hook,此时packagist.org上的项目将被会同步。

之前项目的特征码为:596a0f66098ba40ef481d09dd331c96760ab91b8,
现在为:bdefdc5d407f3bf6b4b1deabe44d14d0a4eb30da,同步成功。

第五步:

至上一步,一个composer项目基本完成。我们就可以在其他项目中进行使用。

接下来就是编写我们自己的代码,然后运行它。

在项目根目录下创建index.php

然后再项目根目录下运行

浏览器访问127.0.0.1:8080

成功调用。

第六步:

为项目打包。

刚刚创建项目使用的命令是:composer require pangou/hello-world dev-master

加了一个dev-master,表示我们项目正在开发阶段,还未正式发布。如果不添加的话是composer不下来的。

接下来就为项目打包。

1、 创建并切换到分支,并且将其推送到服务器上去。

接下来打包

可以看到packagist.org上项目已经存在0.1版本了。

把刚刚的项目删了,使用composer require pangou/hello-world重新创建。这次会发现,可以创建了。

composer.json中的版本也变成了0.1.0版本。 重新测试,一样可以答应出hello world!!!


over

搭建HTTPS服务器

一、申请https证书

StartSSL可以免费申请https证书,但是免费证书只能使用在一个域名中。

1、登录或注册账号

有账号就登录,没账号就注册。

选择地区、填写邮件,等待确认验证码。

安装浏览器证书

安装完成,点击选择证书,登录。

2、域名验证

选择Validations Wizard -> Domian Validation 域名验证

填写域名

等待获取域名信息,选择验证方式,输入验证码,确认验证,完毕。

3、申请证书

选择 Certificates -> Web Server SSL/TLS Certificate 网页服务器SSL认证

输入域名,以及密钥,点击提交。

系统会根据刚刚输入的密钥生成一个私钥,我们需要将其保存下来。

之后StartSSL就会通过我们的申请。我们只需要将其下载下来上传到服务器即可。

二、服务器配置

www.iter-cc.com.zip解压后得到不同版本服务器的证书,我需要使用的是Nginx Server.zip

解压Nginx Server.zip

服务器配置

编辑nginx配置

当我们重启服务器的时候,系统会让我们输入刚刚生成密钥的命令

输入确认后即可完成。

访问网站,OK!

如果嫌每次重启服务器的时候需要输入密码比较烦,我们可以解密私钥。然后将nginx的路径指向解密后的密钥即可。

编辑服务器配置

之后重启服务器就可以无需密码。

访问网站确认ok!!!

搭建自己的邮件服务器

一、配置域名解析

  1. 确认主域名有A记录指向服务器IP
  2. 添加一个邮件二级域名比如 mail.iter-cc.com 指向服务器ip
  3. 主域名下添加一则MX记录指向邮件二级域名 比如 mail.iter-cc.com。如果你作为邮件服务器的域名没有多个,那么MX优先级可以随便写,最高1,最低50,当优先级高的解析无效时,就会去解析低的。
  4. 添加一则txt记录作为SPF(Sender Policy Framework)。关于SPF的格式可以去http://www.openspf.org/SPF_Record_Syntax 查看。 比如我设置的是

一下为我的域名解析

enter image description here

二、安装Postfix

安装完毕后进行配置

三、安装Dovecot

安装完毕后进行配置

最后返回编辑Postfix配置

注意:
postfixdovecot的分工作用为:
postfix管邮件收发
dovecot负责邮件管理,上传,下载,删除等。

最后记得启动或者重启postfix以及dovecot

最后创建用户,收发邮件

设置foxmail账号,

发送邮件

接收邮件