PHP中简单记录Log

在写简单的代码的时候有一个非常方便的记录Log日志的方法:log_error。
让我们来看一下log_error的用法:
bool error_log ( string $message [, int $message_type = 0 [, string $destination [, string $extra_headers ]]] )

message
应该被记录的错误信息。

message_type
设置错误应该发送到何处。可能的信息类型有以下几个:

error_log() 日志类型
0 message 发送到 PHP 的系统日志,使用 操作系统的日志机制或者一个文件,取决于 error_log 指令设置了什么。 这是个默认的选项。
1 message 发送到参数 destination 设置的邮件地址。 第四个参数 extra_headers 只有在这个类型里才会被用到。
2 不再是一个选项。
3 message 被发送到位置为 destination 的文件里。 字符 message 不会默认被当做新的一行。
4 message 直接发送到 SAPI 的日志处理程序中。
destination
目标。它的含义描述于以上,由 message_type 参数所决定。

extra_headers
额外的头。当 message_type 设置为 1 的时候使用。 该信息类型使用了 mail() 的同一个内置函数。

所以我们可以利用这个函数将一些日志保存到我们的邮箱地址,自定义日志文件,PHP系统日志,SAPI日志中去,在调试的时候非常方便。

form元素的enctype属性的选择

因为一个项目里面需要上传文件,所以在网上了解了一下资料之后就选择了通过修改enctype参数实现文件上传。在此,写一下自己关于这个参数的理解。

首先是默认的enctype参数——application/x-www-form-urlencoded。当你没有指定enctype参数的时候,浏览器以这样的enctype参数汇总表单提交项并且通过指定content-type的参数的形式告知服务器。

我们来看一下提交只有一个test提交项的表单,而且没有指定x-www-form-urlencoded,使用Fiddle抓包的结果:

POST http://192.168.164.12/ HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-US
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: 192.168.164.12
Content-Length: 17
DNT: 1
Connection: Keep-Alive
Pragma: no-cache

test=%B2%E2%CA%D4

这就是一个x-www-form-urlencoded的服务器请求,就像参数名字中urlencoded描述的一样,你的提交信息都被进行了urlencoded一下。关于什么是urlencoded,具体请参考这篇文章

在enctype这个参数中有三个可选的选项,其中text/plain和x-www-form-urlencoded有点类似,它的特点是不对提交的字符进行编码,只是简单的将空格转换为 "+" 符号。

然后,我在自己机器上试验了一下PHP服务器端,发现如果通过text/plain进行提交数据的话,就只能通过读php://input来获取了,不会像默认提交那样会自动帮你解析成$_POST方便你调用。

那么关于multipart/form-data的话,在这篇文章里面有个很好的解释。在PHP中我们可以通过$_FILES来获取上传的文件数据和$_POST来获取上传的普通数据。

application/x-www-form-urlencoded这种模式适合上传参数,不适合上传大量文件,因为上传数据可以通过分行进行区别不同的参数,但是一个文件会有很多行, 自然不能通过简单的分行进行区分。

那么有什么解决办法呢?multipart/form-data给出的方法是采用专门设计的分隔符,这种办法虽然看上去土了一点,但是实际上非常有用,至少在当时解决了燃眉之急,后来也一直沿用了下来。

另外有一点比较特别,在PHP的实现里面,当multipart/form-data时,PHP负责帮你解析成$_POST和$_FILES,但是你是获取不到原始数据流的,也就是通过php://input读不到 enctype="multipart/form-data"上传的内容。

Git基础教程1——本地单分支的版本控制工具

以前面向公司的一些代码开发人员(非专业程序员)做了一次基于Git的命令行的Git培训。
第一次培训向所有培训者介绍了Git的革新和伟大,然而不出意外,所有人的表情都是一脸懵懂的表情,然后持续到第一次培训结束。然后第二次培训的话,来的人就只有第一次培训的一半不到。
因此,在这一次的系列培训中,我将不会给你介绍Git的功能有多么高级,Git的实现由多么伟大,我只会带你切身感受Git给我们带来的开发上的便利。

首先,先问大家一个问题:你有没有手动做过版本控制?可能大家有所疑问:什么是版本控制。
给大家看一张图片:

阿里云的磁盘IO真垃圾

今天在使用阿里云的虚拟服务器(VPS)的时候,用了一个命令find /user -type d | grep "xxx"。然后令人惊讶的是,就此停留在那里,一动不动没有动静。我等了几分钟,终于忍耐不住给Ctrl+C了。

难不成我这命令天赋异于常人,于是换了台服务器测了一下这个命令,三秒时间不到结果就出来了。那么到底是什么原因呢?

我就输入top命令查看一下CPU的占用情况,好家伙 wa 那一项的占用率达到了90%+。

使用man top找到了这一项的解释:wa, IO-wait : time waiting for I/O completion

原来命令卡的问题是IO啊,不行我得看看到底卡到什么程度了,使用time dd测速命令从服务器上拷一份数据,测个速。

额,使用time dd测出来的速度居然是正常的,大概30+M/s,虽然貌似慢了点,但是还是过得去的。首先排除大文件的读写问题!

那么我们来测测小文件的读写,这个实在没有找到工具,就找了一个小文件比较多的目录直接copy了。然后果然,同样的事情发生了,在其他服务器上三秒copy完的目录在这台机器上copy了两分钟。

所以问题很大概率确定了,小文件的读写IO有问题,而find的时候需要读很多小文件,结果速度超级慢。
正准备给阿里云发工单的时候,突然情况缓解许多,估计是因为宿主机其他机器的影响。

以前经常听说阿里云的服务器IO坑太多,自己没多少感觉,毕竟我也不在上面放什么应用。但是今天却给我当头一棒,连普通的命令都卡,或许我应该换个其他的云服务商了。

如何利用SSH进行端口转发

江苏电信的网络不太好,连接linode tokyo服务器比较卡。相比而言,我在阿里云华东区的服务器连接Linode要好很多(不过阿里云的磁盘IO性能太烂了,这个还得写一篇博客)。然后,如果能利用阿里云服务器做跳板的话,相信网络一定会好很多。

因为平时使用linode tokyo的机器只是用来进行谷歌搜索的,所以对带宽的要求不是很高。正常情况下使用SSH动态转发就能满足我的需求,但是偶尔卡卡卡让人心生不爽。因此,在此介绍一种使用SSH将阿里云当成跳板机的方法。但是切记ssh是单线程的,网速仅仅能够满足网页浏览的需求,如果有视频浏览等流量较大的需求,请使用ShadowSocks等工具。

SSH提供了一种叫做端口转发的功能,详细的介绍见此文《实战 SSH 端口转发》,原理就是跳板机将目标机器的端口转发到自己的某个端口上。我们需要使用到SSH的-L参数,我们来看看SSH是如何定义这个参数的用法的:

 [-L [bind_address:]port:host:hostport]

也就是说需要跳板机的地址,跳板机的端口,服务器的地址,服务器的端口。
在这边我们需要填入的是 0.0.0.0:2017:127.0.0.1:22。

然后该在客户机上如何访问跳板机呢?使用如下命令:

ssh xxx@xxx.xxx.xxx.xxx -D xxxx -p 2017

相信大家了解了解其中的几个xxxx的含义吧,这样我们就ssh连接上的其实是目标服务器的22端口。