[转载]二维码的生成细节和原理 - 大卫酱_David - 博客园

mikel阅读(838)

[转载][转]二维码的生成细节和原理 – 大卫酱_David – 博客园.

二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型:比如:字符,数字,日文,中文等等。这两天学习了一下二维码图片生成的相关细节,觉得这个玩意就 是一个密码算法,在此写一这篇文章 ,揭露一下。供好学的人一同学习之。

关于QR Code Specification,可参看这个PDF:http://raidenii.net/files/datasheets/misc/qr_code.pdf

基础知识

首先,我们先说一下二维码一共有40个尺寸。官方叫版本Version。Version 1是21 x 21的矩阵,Version 2是 25 x 25的矩阵,Version 3是29的尺寸,每增加一个version,就会增加4的尺寸,公式是:(V-1)*4 + 21(V是版本号) 最高Version 40,(40-1)*4+21 = 177,所以最高是177 x 177 的正方形。

下面我们看看一个二维码的样例:

定位图案
  • Position Detection Pattern是定位图案,用于标记二维码的矩形大小。这三个定位图案有白边叫Separators for Postion Detection Patterns。之所以三个而不是四个意思就是三个就可以标识一个矩形了。
  • Timing Patterns也是用于定位的。原因是二维码有40种尺寸,尺寸过大了后需要有根标准线,不然扫描的时候可能会扫歪了。
  • Alignment Patterns 只有Version 2以上(包括Version2)的二维码需要这个东东,同样是为了定位用的。
功能性数据
  • Format Information 存在于所有的尺寸中,用于存放一些格式化数据的。
  • Version Information 在 >= Version 7以上,需要预留两块3 x 6的区域存放一些版本信息。
数据码和纠错码
  • 除了上述的那些地方,剩下的地方存放 Data Code 数据码 和 Error Correction Code 纠错码。

数据编码

我们先来说说数据编码。QR码支持如下的编码:

Numeric mode数字编码,从0到9。如果需要编码的数字的个数不是3的倍数,那么,最后剩下的1或2位数会被转成4或7bits,则其它的每3位数字会被编成 10,12,14bits,编成多长还要看二维码的尺寸(下面有一个表Table 3说明了这点)

Alphanumeric mode字符编码。包括 0-9,大写的A到Z(没有小写),以及符号$ % * + – . / : 包括空格。这些字符会映射成一个字符索引表。如下所示:(其中的SP是空格,Char是字符,Value是其索引值) 编码的过程是把字符两两分组,然后转成下表的45进制,然后转成11bits的二进制,如果最后有一个落单的,那就转成6bits的二进制。而编码模式和 字符的个数需要根据不同的Version尺寸编成9, 11或13个二进制(如下表中Table 3)

Byte mode, 字节编码,可以是0-255的ISO-8859-1字符。有些二维码的扫描器可以自动检测是否是UTF-8的编码。

Kanji mode这是日文编码,也是双字节编码。同样,也可以用于中文编码。日文和汉字的编码会减去一个 值。如:在0X8140 to 0X9FFC中的字符会减去8140,在0XE040到0XEBBF中的字符要减去0XC140,然后把结果前两个16进制位拿出来乘以0XC0,然后再 加上后两个16进制位,最后转成13bit的编码。如下图示例:

Extended Channel Interpretation (ECI) mode主要用于特殊的字符集。并不是所有的扫描器都支持这种编码。

Structured Append mode用于混合编码,也就是说,这个二维码中包含了多种编码格式。

FNC1 mode这种编码方式主要是给一些特殊的工业或行业用的。比如GS1条形码之类的。

简单起见,后面三种不会在本文 中讨论。

下面两张表中,

  • Table 2 是各个编码格式的“编号”,这个东西要写在Format Information中。注:中文是1101
  • Table 3 表示了,不同版本(尺寸)的二维码,对于,数字,字符,字节和Kanji模式下,对于单个编码的2进制的位数。(在二维码的规格说明书中,有各种各样的编码规范表,后面还会提到)

下面我们看几个示例,

示例一:数字编码

在Version 1的尺寸下,纠错级别为H的情况下,编码: 01234567

1. 把上述数字分成三组: 012 345 67

2. 把他们转成二进制: 012 转成 0000001100; 345 转成 0101011001; 67 转成 1000011。

3. 把这三个二进制串起来: 0000001100 0101011001 1000011

4. 把数字的个数转成二进制 (version 1-H是10 bits ):8个数字的二进制是 0000001000

5. 把数字编码的标志0001和第4步的编码加到前面: 0001 0000001000 0000001100 0101011001 1000011

示例二:字符编码

在Version 1的尺寸下,纠错级别为H的情况下,编码: AC-42

1. 从字符索引表中找到 AC-42 这五个字条的索引 (10,12,41,4,2)

2. 两两分组: (10,12) (41,4) (2)

3.把每一组转成11bits的二进制:

(10,12) 10*45+12 等于 462 转成 00111001110
(41,4) 41*45+4 等于 1849 转成 11100111001
(2) 等于 2 转成 000010

4. 把这些二进制连接起来:00111001110 11100111001 000010

5. 把字符的个数转成二进制 (Version 1-H为9 bits ):5个字符,5转成 000000101

6. 在头上加上编码标识 0010 和第5步的个数编码: 0010 000000101 00111001110 11100111001 000010

结束符和补齐符

假如我们有个HELLO WORLD的字符串要编码,根据上面的示例二,我们可以得到下面的编码,

编码 字符数 HELLO WORLD的编码
0010 000001011 01100001011 01111000110 10001011100 10110111000 10011010100 001101

我们还要加上结束符:

编码 字符数 HELLO WORLD的编码 结束
0010 000001011 01100001011 01111000110 10001011100 10110111000 10011010100 001101 0000
按8bits重排

如果所有的编码加起来不是8个倍数我们还要在后面加上足够的0,比如上面一共有78个bits,所以,我们还要加上2个0,然后按8个bits分好组:

00100000 01011011 00001011 01111000 11010001 01110010 11011100 01001101 01000011 01000000

补齐码(Padding Bytes)

最后,如果如果还没有达到我们最大的bits数的限制,我们还要加一些补齐码(Padding Bytes),Padding Bytes就是重复下面的两个bytes:11101100 00010001 (这两个二进制转成十进制是236和17,我也不知道为什么,只知道Spec上是这么写的)关于每一个Version的每一种纠错级别的最大Bits限 制,可以参看QR Code Spec的第28页到32页的Table-7一表。

假设我们需要编码的是Version 1的Q纠错级,那么,其最大需要104个bits,而我们上面只有80个bits,所以,还需要补24个bits,也就是需要3个Padding Bytes,我们就添加三个,于是得到下面的编码:

00100000 01011011 00001011 01111000 11010001 01110010 11011100 01001101 01000011 0100000011101100 00010001 11101100

上面的编码就是数据码了,叫Data Codewords,每一个8bits叫一个codeword,我们还要对这些数据码加上纠错信息。

纠错码

上面我们说到了一些纠错级别,Error Correction Code Level,二维码中有四种级别的纠错,这就是为什么二维码有残缺还能扫出来,也就是为什么有人在二维码的中心位置加入图标。

错误修正容量
L水平 7%的字码可被修正
M水平 15%的字码可被修正
Q水平 25%的字码可被修正
H水平 30%的字码可被修正

那么,QR是怎么对数据码加上纠错码的?首先,我们需要对数据码进行分组,也就是分成不同的Block,然后对各个Block进行纠错编码,对于如何分组,我们可以查看QR Code Spec的第33页到44页的Table-13到Table-22的定义表。注意最后两列:

  • Number of Error Code Correction Blocks:需要分多少个块。
  • Error Correction Code Per Blocks:每一个块中的code个数,所谓的code的个数,也就是有多少个8bits的字节。

举个例子:上述的Version 5 + Q纠错级:需要4个Blocks(2个Blocks为一组,共两组),头一组的两个Blocks中各15个bits数据 + 各 9个bits的纠错码(注:表中的codewords就是一个8bits的byte)(再注:最后一例中的(c, k, r )的公式为:c = k + 2 * r,因为后脚注解释了:纠错码的容量小于纠错码的一半)

下图给一个5-Q的示例(因为二进制写起来会让表格太大,所以,我都用了十进制,我们可以看到每一块的纠错码有18个codewords,也就是18个8bits的二进制数)

数据 对每个块的纠错码
1 1 67 85 70 134 87 38 85 194 119 50 6 18 6 103 38 213 199 11 45 115 247 241 223 229 248 154 117 154 111 86 161 111 39
2 246 246 66 7 118 134 242 7 38 86 22 198 199 146 6 87 204 96 60 202 182 124 157 200 134 27 129 209 17 163 163 120 133
2 1 182 230 247 119 50 7 118 134 87 38 82 6 134 151 50 7 148 116 177 212 76 133 75 242 238 76 195 230 189 10 108 240 192 141
2 70 247 118 86 194 6 151 50 16 236 17 236 17 236 17 236 235 159 5 173 24 147 59 33 106 40 255 172 82 2 131 32 178 236

注:二维码的纠错码主要是通过Reed-Solomon error correction(里 德-所罗门纠错算法)来实现的。对于这个算法,对于我来说是相当的复杂,里面有很多的数学计算,比如:多项式除法,把1-255的数映射成2的n次方 (0<=n<=255)的伽罗瓦域Galois Field之类的神一样的东西,以及基于这些基础的纠错数学公式,因为我的数据基础差,对于我来说太过复杂,所以我一时半会儿还有点没搞明白,还在学习 中,所以,我在这里就不展开说这些东西了。还请大家见谅了。(当然,如果有朋友很明白,也繁请教教我)

最终编码

穿插放置

如果你以为我们可以开始画图,你就错了。二维码的混乱技术还没有玩完,它还要把数据码和纠错码的各个codewords交替放在一起。如何交替呢,规则如下:

对于数据码:把每个块的第一个codewords先拿出来按顺度排列好,然后再取第一块的第二个,如此类推。如:上述示例中的Data Codewords如下:

块 1 67 85 70 134 87 38 85 194 119 50 6 18 6 103 38
块 2 246 246 66 7 118 134 242 7 38 86 22 198 199 146 6
块 3 182 230 247 119 50 7 118 134 87 38 82 6 134 151 50 7
块 4 70 247 118 86 194 6 151 50 16 236 17 236 17 236 17 236

我们先取第一列的:67, 246, 182, 70

然后再取第二列的:67, 246, 182, 70, 85,246,230 ,247

如此类推:67, 246, 182, 70, 85,246,230 ,247 ……… ……… ,38,6,50,17,7,236

对于纠错码,也是一样:

块 1 213 199 11 45 115 247 241 223 229 248 154 117 154 111 86 161 111 39
块 2 87 204 96 60 202 182 124 157 200 134 27 129 209 17 163 163 120 133
块 3 148 116 177 212 76 133 75 242 238 76 195 230 189 10 108 240 192 141
块 4 235 159 5 173 24 147 59 33 106 40 255 172 82 2 131 32 178 236

和数据码取的一样,得到:213,87,148,235,199,204,116,159,…… ……39,133,141,236

然后,再把这两组放在一起(纠错码放在数据码之后)得到:

67, 246, 182, 70, 85, 246, 230, 247, 70, 66, 247, 118, 134, 7, 119, 86, 87, 118, 50, 194, 38, 134, 7, 6, 85, 242, 118, 151, 194, 7, 134, 50, 119, 38, 87, 16, 50, 86, 38, 236, 6, 22, 82, 17, 18, 198, 6, 236, 6, 199, 134, 17, 103, 146, 151, 236, 38, 6, 50, 17, 7, 236, 213, 87, 148, 235, 199, 204, 116, 159, 11, 96, 177, 5, 45, 60, 212, 173, 115, 202, 76, 24, 247, 182, 133, 147, 241, 124, 75, 59, 223, 157, 242, 33, 229, 200, 238, 106, 248, 134, 76, 40, 154, 27, 195, 255, 117, 129, 230, 172, 154, 209, 189, 82, 111, 17, 10, 2, 86, 163, 108, 131, 161, 163, 240, 32, 111, 120, 192, 178, 39, 133, 141, 236

这就是我们的数据区。

Remainder Bits

最后再加上ReminderBits,对于某些Version的QR,上面的还不够长度,还要加上Remainder Bits,比如:上述的5Q版的二维码,还要加上7个bits,Remainder Bits加零就好了。关于哪些Version需要多少个Remainder bit,可以参看QR Code Spec的第15页的Table-1的定义表。

画二维码图

Position Detection Pattern

首先,先把Position Detection图案画在三个角上。(无论Version如何,这个图案的尺寸就是这么大)

Alignment Pattern

然后,再把Alignment图案画上(无论Version如何,这个图案的尺寸就是这么大)

关于Alignment的位置,可以查看QR Code Spec的第81页的Table-E.1的定义表(下表是不完全表格)

下图是根据上述表格中的Version8的一个例子(6,24,42)

Timing Pattern

接下来是Timing Pattern的线(这个不用多说了)

Format Information

再接下来是Formation Information,下图中的蓝色部分。

Format Information是一个15个bits的信息,每一个bit的位置如下图所示:(注意图中的Dark Module,那是永远出现的)

这15个bits中包括:

  • 5个数据bits:其中,2个bits用于表示使用什么样的Error Correction Level, 3个bits表示使用什么样的Mask
  • 10个纠错bits。主要通过BCH Code来计算

然后15个bits还要与101010000010010做XOR操作。这样就保证不会因为我们选用了00的纠错级别和000的Mask,从而造成全部为白色,这会增加我们的扫描器的图像识别的困难。

下面是一个示例:

关于Error Correction Level如下表所示:

关于Mask图案如后面的Table 23所示。

Version Information

再接下来是Version Information(版本7以后需要这个编码),下图中的蓝色部分。

Version Information一共是18个bits,其中包括6个bits的版本号以及12个bits的纠错码,下面是一个示例:

而其填充位置如下:

数据和数据纠错码

然后是填接我们的最终编码,最终编码的填充方式如下:从左下角开始沿着红线填我们的各个bits,1是黑色,0是白色。如果遇到了上面的非数据区,则绕开或跳过。

掩码图案

这样下来,我们的图就填好了,但是,也许那些点并不均衡,如果出现大面积的空白或黑块,会告诉我们扫描识别的困难。所以,我们还要做Masking 操作(靠,还嫌不复杂)QR的Spec中说了,QR有8个Mask你可以使用,如下所示:其中,各个mask的公式在各个图下面。所谓mask,说白了, 就是和上面生成的图做XOR操作。Mask只会和数据区进行XOR,不会影响功能区。(注:选择一个合适的Mask也是有算法的

其Mask的标识码如下所示:(其中的i,j分别对应于上图的x,y)

下面是Mask后的一些样子,我们可以看到被某些Mask XOR了的数据变得比较零散了。

Mask过后的二维码就成最终的图了。

好了,大家可以去尝试去写一下QR的编码程序,当然,你可以用网上找个Reed Soloman的纠错算法的库,或是看看别人的源代码是怎么实现这个繁锁的编码

[转载]HTTP 错误 500.0 - Internal Server Error - 夜落朦空 - 博客园

mikel阅读(829)

[转载]HTTP 错误 500.0 – Internal Server Error – 夜落朦空 – 博客园.

工作需要,需要同时在服务器上运行PHP、ASP、.Net,考虑到方便,我用IIS7.5实现,以下是所需软件列表:

    1、Windows 2008 R2 Standard.
    2、IIS7.5

3、PHP5.3.8 Thread Safe.

5、PHP Manager 

这里不再赘述Windows和IIS7.5的安装方法,详细过程请上百度搜索。

按照正常创建网站流程,以下为简要步骤:

1、创建应用程序池,选择.NetFramework版本为无托管代码,托管管道模式为集成,然后右键点选刚新建的应用程序池,选择常规选项下的启用32位应用程序值为True;

2、创建网站,输入网站名称,应用程序池选择上一步创建好的就用程序池,选择物理路径,确定,并输入默认文档列表;

3、 安装PHP Manager,按照文档步骤设置PHP配置,只需几步便可,然后点击Check phpinfo()进行测试;

然后我遇到了这样的问题,页面出现了如下错误:”出现 HTTP 错误 500.0 – Internal Server Error”,以前也遇到过,用的是php5.2.17版本,很快解决了,按照以前方法,检查目录权限,检查配置项,但是这次问题依旧,反复检查,问题仍 然没有得到解决,郁闷中…………..。

思考一下,即然是用IIS7.5作为服务器进行配置,说不定在IIS官网会有更好的解决办法。上官网,反复搜索查看,眼前一亮,终于找到了解决方法,经实践操作,该问题最终得以解决,哈哈。(特别标注:必须使用x86版本,即使你的服务器是x64版本。

原来出现这个错误是因为PHP5.3是Visual C++ 2008 compiler (VC9)编译的,所以需要在服务器上安装Visual C++ 2008 runtime,至此,整个问题解决。

[转载]在CentOS6.4中安装配置LAMP环境的详细步骤 - Leroy-LIZH - 博客园

mikel阅读(924)

[转载]在CentOS6.4中安装配置LAMP环境的详细步骤 – Leroy-LIZH – 博客园.

本文详细介绍了CentOS6.4系统中安装LAMP服务并对其进行配置的过程,即安装Apache+PHP+MySQL,参照了网上大神的设置,其他Linux发行系统可以参考~

在本文中部分命令操作需要root权限,输入‘su –’命令后输入密码即可切换root身份。

一、修改设置对安装做准备

1. 防火墙设置

  设置/etc/sysconfig/iptables文件允许80端口和3306端口。因为80端口是http协议所使用的端口,如果防火墙禁止80端口的话,网站配置好了也无法从外网访问。3306端口是MySQL数据库的默认端口。使用VIM打开iptables文件并添加规则:

 

1 打开iptables文件进行修改
2 vim /etc/sysconfig/iptables
3 
4 加入下列两行
5 2 -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
6 3 -A INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT

 

 

 

添加好后文件应该如下图,如果以前修改过该文件责可能和笔者的图中略有不同:

 

 

修改完成注意检查下拼写,不要有错误。保存之后重启防火墙生效:

/etc/init.d/iptables restart

2. 关闭SELINUX

  SELinux 是 2.6 版本的 Linux 内核中提供的强制访问控制(MAC)系统。对于目前可用的 Linux安全模块来说,SELinux 是功能最全面而且测试最充分的。SELinux 提供了比默认ugo+rwx更详细的权限控制。打开SELinux后,即使因为0day漏洞被提权,相应程序的权限在SELinux控制下也不会造成太大 影响。但是在实际应用情况中,SELinux并不实用,没人会闲的去用0day漏洞攻击个人电脑,业务服务器基本上都是用负载均衡设备做流量分发,对外仅开放了仅有的几个端口。所以综合安全性和复杂性来说,SELinux的性价比并不高。修改/etc/selinux/config文件关闭SELinux,设置后如图:

vim /etc/selinux/config

注释掉如下两行,在行首添加#注释。
SELINUX=enforcing
SELINUXTYPE=targeted

在后面增加:
SELINUX=disabled

关闭SELinux后需要重启系统,输入‘shutdown -r now’重启系统。

 

二、开始安装软件

1. MySQL的安装和配置

安装MySql:

通过yum软件包管理器安装MySql,管理器会自动安装依赖项,遇到询问直接输入y确认,直到显示“Complete!”完成。
yum install mysql mysql-server

启动MySql
/etc/init.d/mysqld start

设置MySql服务为开机启动
chkconfig mysqld on

复制MySql默认配置文件,直接覆盖/etc/my.cnf
cp /usr/share/mysql/my-medium.cnf /etc/my.cnf

MySql设置:

  设置MySql管理员root账户的密码。

 

输入如下命令后需要连续输入两次密码确认,有询问输入Y同意即可,成功后显示Thanks for using MySQL!。
mysql_secure_installation

 

设置成功后需要重启MySql服务:

1 /etc/init.d/mysqld stop
2 /etc/init.d/mysqld start

 

2. Apache服务的安装和配置

安装httpd
yum install httpd

启动Apache服务
/etc/init.d/httpd start

编辑apache设置
vim /etc/httpd/conf/httpd.conf
查找 #ServerName www.example.com:80
修改成 ServerName www.XXXX.com:80
其中的“www.XXXX.com”自己的域名,没有可设置为localhost,如图

设置Apache服务开机启动
chkconfig httpd on

重启Apache服务
/etc/init.d/httpd restart

安装好Apache服务后,打开系统自带的火狐浏览器,打开localhost这个网址即可看到Apache的示例网页。

 

 

 

3.安装PHP

  安装PHP非常简单:

遇到询问直接输y确认
yum install php

安装PHP插件:

插件包括MySql支持等,遇到询问一如既往的y确认~~
yum install php-mysql php-gd libjpeg* php-imap php-ldap php-odbc php-pear php-xml php-xmlrpc php-mbstring php-mcrypt php-bcmath php-mhash libmcrypt

安装完成后不要忘了重启Apache和MySql:

/etc/init.d/mysqld restart
/etc/init.d/httpd restart

到此软件的安装就结束了,接下来进行配置和测试。

三、修改Apache和PHP的配置

1.修改Apache配置

  作为一个架设在公网上的服务器,我们可不能让服务器所使用的软件版本或者错误等信息暴露网页上,这就需要对Apache进行设置:

编辑文件Apache设置文件
vi /etc/httpd/conf/httpd.conf

44行: 修改 ServerTokens OS 为 ServerTokens Prod
防止错误页显示操作系统名字

76行: 修改 KeepAlive Off 为 KeepAlive On
允许程序性联机

83行: 修改 MaxKeepAliveRequests 100 为 MaxKeepAliveRequests 1000
增加同时连接数

331行: 修改 Options Indexes FollowSymLinks 为 Options Includes ExecCGI FollowSymLinks
允许服务器执行CGI及SSI,防止列出目录

338行: 修改 AllowOverride None 为 AllowOverride All
允许.htaccess

402行: 修改 DirectoryIndex index.html index.html.var 为 DirectoryIndex index.php Default.php index.html index.htm Default.html Default.htm
添加php默认文档

536行: 修改 ServerSignature On 为 ServerSignature Off
防止错误页显示Apache版本

554行: 修改 Options Indexes MultiViews FollowSymLinks 为 Options MultiViews FollowSymLinks
不显示树状目录结构

759行: 根据需要设置为 AddDefaultCharset UTF-8 或者 AddDefaultCharset GB2312
笔者大多数时候都在使用UTF-8编码,所以不进行修改

796行: 修改 #AddHandler cgi-script .cgi 为 AddHandler cgi-script .cgi .pl
允许扩展名为.pl的CGI脚本运行

修改完成后保存退出并重启Apache,删除测试网页:

/etc/init.d/httpd restart

删除测试网页
rm -f /etc/httpd/conf.d/welcome.conf /var/www/error/noindex.html

 

2. 修改PHP配置

编辑php设置文件
vim /etc/php.ini

946行: 修改 ;date.timezone = PRC 为 date.timezone = PRC (去掉分号)

386行: 修改 disable_functions = 为 disable_functions = passthru,exec,system,chroot,scandir,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,stream_socket_server,escapeshellcmd,dll,popen,disk_free_space,checkdnsrr,checkdnsrr,getservbyname,getservbyport,disk_total_space,posix_ctermid,posix_get_last_error,posix_getcwd,posix_getegid,posix_geteuid,posix_getgid,posix_getgrgid,posix_getgrnam,posix_getgroups,posix_getlogin,posix_getpgid,posix_getpgrp,posix_getpid,posix_getppid,posix_getpwnam,posix_getpwuid,posix_getrlimit,posix_getsid,posix_getuid,posix_isatty,posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid,posix_setpgid,posix_setsid,posix_setuid,posix_strerror,posix_times,posix_ttyname,posix_uname
设置PHP的禁用函数,若程序中需要使用的函数可以删除掉。

432行: 设置 expose_php = Off
禁止显示php版本的信息

745行: 设置 magic_quotes_gpc = On
打开magic_quotes_gpc,用于防止SQL注入

229行: 设置 short_open_tag = ON
支持php短标签

380行: 设置 open_basedir = .:/tmp/
设置允许访问的目录和/tmp/目录,防止php木马跨站

在CentOS6.4中安装配置LAMP环境的详细步骤

  本文详细介绍了CentOS6.4系统中安装LAMP服务并对其进行配置的过程,即安装Apache+PHP+Mysql,参照了网上大神的设置,其他Linux发行系统可以参考~

在本文中部分命令操作需要root权限,输入‘su –’命令后输入密码即可切换root身份。

一、修改设置对安装做准备

1. 防火墙设置

  设置/etc/sysconfig/iptables文件允许80端口和3306端口。因为80端口是http协议所使用的端口,如果防火墙禁止80端口的话,网站配置好了也无法从外网访问。3306端口是MySql数据库的默认端口。使用VIM打开iptables文件并添加规则:

 

1 打开iptables文件进行修改
2 vim /etc/sysconfig/iptables
3 
4 加入下列两行
5 2 -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
6 3 -A INPUT -p tcp -m state --state NEW -m tcp --dport 3306 -j ACCEPT

 

 

 

添加好后文件应该如下图,如果以前修改过该文件责可能和笔者的图中略有不同:

 

 

修改完成注意检查下拼写,不要有错误。保存之后重启防火墙生效:

/etc/init.d/iptables restart

2. 关闭SELINUX

  SELinux 是 2.6 版本的 Linux 内核中提供的强制访问控制(MAC)系统。对于目前可用的 Linux安全模块来说,SELinux 是功能最全面而且测试最充分的。SELinux 提供了比默认ugo+rwx更详细的权限控制。打开SELinux后,即使因为0day漏洞被提权,相应程序的权限在SELinux控制下也不会造成太大 影响。但是在实际应用情况中,SELinux并不实用,没人会闲的去用0day漏洞攻击个人电脑,业务服务器基本上都是用负载均衡设备做流量分发,对外仅开放了仅有的几个端口。所以综合安全性和复杂性来说,SELinux的性价比并不高。修改/etc/selinux/config文件关闭SELinux,设置后如图:

按 Ctrl+C 复制代码

按 Ctrl+C 复制代码

关闭SELinux后需要重启系统,输入‘shutdown -r now’重启系统。

 

二、开始安装软件

1. MySql的安装和配置

安装MySql:

 

按 Ctrl+C 复制代码

按 Ctrl+C 复制代码

 

MySql设置:

  设置MySql管理员root账户的密码。

 

输入如下命令后需要连续输入两次密码确认,有询问输入Y同意即可,成功后显示Thanks for using MySQL!。
mysql_secure_installation

 

设置成功后需要重启MySql服务:

1 /etc/init.d/mysqld stop
2 /etc/init.d/mysqld start

 

2. Apache服务的安装和配置

按 Ctrl+C 复制代码

按 Ctrl+C 复制代码

安装好Apache服务后,打开系统自带的火狐浏览器,打开localhost这个网址即可看到Apache的示例网页。

 

 

 

3.安装PHP

  安装PHP非常简单:

遇到询问直接输y确认
yum install php

安装PHP插件:

插件包括MySql支持等,遇到询问一如既往的y确认~~
yum install php-mysql php-gd libjpeg* php-imap php-ldap php-odbc php-pear php-xml php-xmlrpc php-mbstring php-mcrypt php-bcmath php-mhash libmcrypt

安装完成后不要忘了重启Apache和MySql:

/etc/init.d/mysqld restart
/etc/init.d/httpd restart

到此软件的安装就结束了,接下来进行配置和测试。

三、修改Apache和PHP的配置

1.修改Apache配置

  作为一个架设在公网上的服务器,我们可不能让服务器所使用的软件版本或者错误等信息暴露网页上,这就需要对Apache进行设置:

按 Ctrl+C 复制代码

按 Ctrl+C 复制代码

修改完成后保存退出并重启Apache,删除测试网页:

/etc/init.d/httpd restart

删除测试网页
rm -f /etc/httpd/conf.d/welcome.conf /var/www/error/noindex.html

 

2. 修改PHP配置

 

按 Ctrl+C 复制代码

按 Ctrl+C 复制代码

 

修改完成保存后重启服务:

/etc/init.d/mysqld restart
/etc/init.d/httpd restart

 

四、 测试PHP探针页面

 

 

  输入“vim /var/www/html/index.php添加PHP探针页面并输入以下代码:

 

1 <?php
2     phpinfo();
3 ?>

 

保存退出后在浏览器中输入localhost查看php信息:

 

 

设置文档文件夹权限:

chown apache.apache -R /var/www/html

 

LAMP服务器配置完成。

[转载] 悬赏¥15000.00 寻求公司内部使用拼车APP - iPhone - APP开发 - 猪八戒网

mikel阅读(946)

[转载]寻求公司内部使用拼车APP – iPhone – APP开发 – 猪八戒网.

具体要求:

背景:
我们公司在厦门,目前在泉州、石狮、漳州等有项目,经常会有来往。想实现,如有车的职员和没车职员,信息共享,拼车去,有车的职员可以得到相应有补助。

实在的目的和要求:
1、        用户名登录验证;公司内部使用。
2、        有车职员发布拼车信息,如从厦门至泉州,目前可提供4个车位。
3、        无车职员发布拼车需求,如从泉州至厦门,需求人共2人。
4、        无车职员可查询开车人员的信息,并直接加入。加入后,空余车位少一位。
5、        有车人员发布拼车信息时,最好有线路信息,如从厦门至泉州时,东渡——仙岳路——翔安高速——泉州。
6、        当拼车前往目的地后,判断相关人员是否有到该地点,如有三人从厦门至泉州后,到泉州后,让三人登录软件后,点击确认,取该人员的定位信息。
7、        补助信息:有车人员,拼车完成后,补助150元(管理员可后台调整),可查询自己所有记录和补助金额。
8、        无车人员可查询所有记录。
9、        查看信息时,可直接拨打相关人员手机。
10、        能提供相关报表,如本月厦门到各地有多少记录,补助多少等,销售部去各地多少次等。

支持平台:
IOS、Android

 

[转载]移动版网页以及Web App的那些meta们 - 萧瑟56 - 博客园

mikel阅读(914)

转载移动版网页以及Web App的那些meta们 – 萧瑟56 – 博客园.

移动版网页以及Web App的那些meta们

如今智能机遍布大街小巷,过年回家(农村的),村里人尽然也在讨论抢不上小米的事 情,看来,移动时代已经来临,而且很飞速,所以,如今的前端攻城师们要大 跨步的迈向移动互联网了,更何况Web App也应用广泛,可能原理还一样,但是一定会有新的东西出现,那就从“头”开始,看看头部那些Meta的新玩意。

1、

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />

这是一个移动端最常用的meta,定义页面的缩放,如上代表宽度以终端宽度为准,并且不允许用户缩放,更多属性如下:
width  — 宽度(范围从200到10,000,默认为980像素/device-width缩放至终端宽度)
height  — 高度(范围从223到10,000)
initial-scale  — 初始的缩放比例 (范围从 > 0 到 10)
minimum-scale  — 允许用户缩放到的最小比例
maximum-scale  — 允许用户缩放到的最大比例
user-scalable  —  用户是否可以手动缩放 (no,yes)
target-densitydpi  —  dpi_value | device-dpi | high-dpi | medium-dpi | low-dpi 定义为每英寸点的数量(dpi)

2、

<meta name="format-detection" content="telephone=no" />

禁止把数字转化为拨号链接

3、

<meta content="email=no" name="format-detection" />

禁止把邮箱地址作为邮件发送

4、

<meta name="apple-mobile-web-app-capable" content="yes" />

隐藏浏览器的工具栏和菜单栏,看到apple了吧,对iso系统起用

5、

<meta name="apple-mobile-web-app-status-bar-style" content="black" />

默 认值为 default(白色),可以定为black(黑色)和black-translucent(灰色半透明),需要说明的是值为“black- translucent”将会占据页面位置,浮在页面上方(会覆盖页面 20px高度 iphone4和itouch4的Retina屏幕为40px)

6、

<meta name="apple-touch-fullscreen" content="yes">

“添加到主屏幕“后,全屏显示

介于说到了“头”,也说到了Web App,那就捎带说说两个苹果私有link,
1、

<link rel="apple-touch-icon-precomposed" href="iphone_logo.png" sizes="72x72" />

这个 link 就是设置 Web App 的放置主屏幕上 icon 文件路径,href就是你ico的文件路径,sizes可以根据不同分辨率,对应不同的图片,尺寸如下:

IOS设备 最适尺寸(px)
iPhone 和 iTouch 57 x 57
retina iPhone 和 retina iTouch 114 x 114
iPad 72 x 72
retina iPad 144 x 144

如果没有指明 <sizes> 属性的大小,则默认值为57×57。
如 果所有的 <link> 标签序列中都没有符合官方推荐的最适尺寸的话,那么IOS会从所有比推荐的最适尺寸大的图标中选择尺寸最小的那一个,如果所有的 <link> 标签序列中的图标都比当前推荐的最适尺寸小的话,IOS会从这些图片中自动选择最大的那个来作为启动图标。
如果整个页面都没有指定任何的 apple-touch-icon 的图标的话,IOS则会自动去网站根目录寻找有 apple-touch-icon 和 apple-touch-icon-precomposed 前缀的图标文件。

2、

<link rel="apple-touch-startup-image" href="logo_startup.png" media="(device-width: 320px)" />

这个 link 就是设置启动时候的界面,可用媒体查询调用不同图片

Web App 才刚刚开始—

[原创]PHP中文保存到mySQL乱码问题

mikel阅读(1140)

最近又转PHP了,做了个简单的CRUD例子,发现存储到MySQL中的中文变成了“???”,于是百度了下,发现有如下问题的还很多

大多原因是因为没有设置mySQL的字符设置的问题

  1. PHP+MySQL出现中文乱码的原因。

    1. MYSQL数据库的编码是utf8,与PHP网页的编码格式不一致,就会造成MYSQL中的中文乱码。

    2. 使用MYSQL中创建表、或者选择字段时设置的类型不是utf8,而网页编码不是utf8,也可能造成MYSQL中文乱码.

    3. PHP页面的字符集与数据库的编码不一致。

    4. PHP连接MYSQL数据库,操作是设定的语句指定的编码和页面编码,PHP页面编码不一致。

    5. 用户提交的HTML页面编码,和显示数据的页面编码不一致 ,就肯定会造成PHP页面乱码.

  2. 怎么解决中文乱码的问题。

    1. 网页编码设置。一般在HTML代码中的文件头<html>中加入属性:

    <meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″>

    保证,网页是”utf-8″编码。

    2. PHP代码设置。在php代码的开始部分加入以下代码:

    header(”Content-type: text/html;charset=utf-8″);

    且要求保存的文件编码方式是utf-8(可以用EditPlus打开设置,如下图),这样就保证了该文件也是utf-8编码。

    3. 数据库中表的字段中存储中文的部分,要设置为utf8_general_ci类型。

    4.PHP在连接数据库操作时,要设置操作的字段类型为utf8,设置方法如下:

    mysql_connect(’localhost’,’user’,’password’);mysql_select_db(’db’);mysql_query(”set names utf8;”); //**设置字符集***

  3. 实例对比。通过上面的分析,我们按照解决方案,得到了正确的中文编码存储在MySQL中,效果如下图所示:

 

[转载]MySQL mysql_fetch_array 函数取得查询结果中的一行作为数组_PHP+MySQL数据库教程

mikel阅读(1055)

[转载]MySQL mysql_fetch_array 函数取得查询结果中的一行作为数组_PHP+MySQL数据库教程.

mySQL_fetch_* 列函数

mySQL_fetch_* 列函数的主要功能是从查询返回的结果集中取得相关的查询结果,主要包括:

  • mysql_fetch_array():从结果集中取得一行作为关联数组或索引数组,或二者兼有
  • mysql_fetch_row():从结果集中取得一行作为枚举数组
  • mysql_fetch_assoc():从结果集中取得一行作为关联数组
  • mysql_fetch_object():从结果集中取得一行作为对象
  • mysql_fetch_field():从结果集中取得字段信息并作为对象返回
  • mysql_fetch_lengths():取得结果集中取得一行每个字段内容输出的长度

mysql_fetch_array()

mysql_fetch_array() 函数用于从结果集中取得一行作为关联数组或索引数组,或二者兼有。成功返回一个数组,否则返回 FALSE 。

语法:

array mysql_fetch_array( resource result [, int result_type] )
参数说明:
参数 说明
result 查询函数(如 mysql_query)返回的数据集资源
result_type 可选常量,标明数组结果类型,可接受值如下:

  1. MYSQL_BOTH:默认,得到一个同时包含关联和数字索引的数组,用字段名作为键名
  2. MYSQL_ASSOC:只得到关联索引的数组
  3. MYSQL_NUM:只得到数字索引的数组

例子 1 ,使用 MYSQL_NUM :

<?php
$conn = @mysql_connect("localhost","root","root123");
if (!$conn){
    die("连接数据库失败:" . mysql_error());
}

mysql_select_db("test", $conn);
mysql_query("set character set 'gbk'");

$result = mysql_query("SELECT uid,username FROM user");
while($row = mysql_fetch_array($result, MYSQL_NUM)){
    echo "用户ID:".$row[0]."<br />";
    echo "用户名:".$row[1]."<br />";
}
?>

浏览器输出:

用户ID:1
用户名:admin
用户ID:2
用户名:小明
用户ID:3
用户名:Jack
用户ID:4
用户名:小王

例子 2 ,使用 MYSQL_ ASSOC :

//重复代码省略
$result = mysql_query("SELECT uid,username FROM user");
while($row = mysql_fetch_array($result, MYSQL_ ASSOC)){
    echo "用户ID:".$row['uid']."<br />";
    echo "用户名:".$row['username']."<br />";
}

浏览器输出内容同上。

当使用 MYSQL_BOTH 或省略该参数是,将同时具有 MYSQL_NUM 与 MYSQL_ ASSOC 的特性。

说明

  1. 本函数返回的字段名作为数组键值是区分大小写的
  2. 用 mysql_fetch_array() 并不明显 比用 mysql_fetch_row() 慢,而且还提供了明显更多的值
  3. 该函数只从当前数据指针取得一行数据作为结果返回,如果执行过一次,会将数据指针指向下一列数据
  4. 如果要取得多行或者全部数据,需要使用循环结构将数据逐行取出
  5. 如果结果中的两个或以上的列具有相同字段名,最后一列将优先。要访问同名的其它列,必须用该列的数字索引或给该列起个别名

[转载]获取mysql结果集的几个函数的区别 - PHP小菜鸟 -- PHP技术博客,苦逼的程序猿

mikel阅读(1065)

[转载]获取mysql结果集的几个函数的区别 – PHP小菜鸟 — PHP技术博客,苦逼的程序猿.

获取mySQL结果集有四个函数分别是  mySQL_fetch_row  mySQL_fetch_array mysql_fetch_object mysql_fetch_assoc

一直以来,有很多初学者搞不懂这些Mysql中从查询结果集中取得数据的几个函数之间有什么区别,今天我就针对这几个
函数做下解释以及测试,先给大家段代码

<!--?php <br ?--> $link=mysql_connect('localhost','root','');
mysql_select_db('blog',$link);
$sql = "select * from Emlog_blog";
$result = mysql_query($sql);
while($row = mysql_fetch_row($result)){
echo $row['gid'].'::'.$row[1].'
';
}
$result = mysql_query($sql);
while($row = mysql_fetch_array($result)){
echo $row['gid'].'::'.$row['title'].'
';
}
$result = mysql_query($sql);
while($row = ($result)){
echo $row-&gt;gid.'::'.$row-&gt;title."
";
}
$result = mysql_query($sql);
while($row = mysql_fetch_assoc($result)){
echo $row['gid'].'::'.$row['title'].'
';
}
?&gt;

分析:
mysql_fetch_row,这个函数是从结果集中取一行作为枚举数据,从和指定的结果标识关联的结果集中取得一行数据
并作为数组返回。每个结果的列储存在一个数组的单元中,偏移量从 0 开始。 注意,这里是从0开始偏移,也就是
说不能用字段名字来取值,只能用索引来取值,所以如下代码是取不到值的:
while($row = mysql_fetch_row($res)){
echo $row[‘gid’].’::’.$row[1].”;
} //这里的$row[‘gid’] 取不到值。
mysql_fetch_array,从结果集中取得一行作为关联数组,或数字数组,或二者兼有,除了将数据以数字索引方式储
存在数组中之外,还可以将数据作为关联索引储存,用字段名作为键名。 也就是说他得到的结果像数组一样,可以
用key或者索引来取值,所以
while($row = mysql_fetch_array($res)){
echo $row[‘gid’].’::’.$row[‘title’].”;
}//这里$row[‘gid’],$row[‘title’]都能得到相应的值。
mysql_fetch_object,顾名思义,从结果集中取得一行作为对象,并将字段名字做为属性。所以只有这样才能取到值
while($row = mysql_fetch_object($res)){
echo $row->gid.’::’.$row->title.””;
}
mysql_fetch_assoc,从结果集中取得一行作为关联数组,也就是说这个函数不能像mysql_fetch_row那样用索引来
取值,只能用字段名字来取,所以
while($row = mysql_fetch_assoc($res)){
echo $row[‘gid’].’::’.$row[1].”;
} //$row[1]这样是取不到值的

总结
mysql_fetch_array函数是这样定义的:array mysql_fetch_array ( resource result [, int result_type]),返回根
据从结果集取得的行生成的数组,如果没有更多行则返回 FALSE。
mysql_fetch_array() 中可选的第二个参数 result_type 是一个常量,可以接受以下值:MYSQL_ASSOC,MYSQL_NUM 和
MYSQL_BOTH。其中:
1、mysql_fetch_assoc($result)==mysql_fetch_array($result,MYSQL_ASSOC);
2、mysql_fetch_row($result)==mysql_fetch_array($result,MYSQL_NUM);
所以mysql_fetch_array()函数在某种程度上可以算是mysql_fetch_row()与 mysql_fetch_assoc()的集合。另外,
mysql_fetch_array()另外还有MYSQL_BOTH参数,将得到一个同时包含关 联和数字索引的数组。
在来说句 $row = $db->fetch_array($query);
$db是人数据库操作类,$db->fetch_array($query),fetch_array($query)是那个db类里的方法,
$row = $db->fetch_array($query)这句的意思是从记录集$query中得到数据库中的一行记录。
不用类可这样实现

@mysql_select_db($database,$conn);
$query=mysql_query($sql);
while($row=mysql_fetch_array($query)){
$rows[]=$row;
}

[转载]微信公众平台开发模式,成为开发者,实现自动回复和用户的关注事件的监听 - My bobo - 博客频道 - CSDN.NET

mikel阅读(1058)

[转载]微信公众平台开发模式,成为开发者,实现自动回复和用户的关注事件的监听 – My bobo – 博客频道 – CSDN.NET.

公司不忙的时候,自己研究了下微信公众平台。然后各种找资料各种研究。

这是我自己的php代码

<?php
/**
  * wechat php test
  */


//define your token
define("TOKEN", "token");
$wechatObj = new wechatCallbackapiTest();
if(isset($_GET["echostr"])){ #验证过token,成为开发者之后,可以直接$wechatObj->responseMsg();
$wechatObj->valid();
}else{
$wechatObj->responseMsg();
}




class wechatCallbackapiTest
{
public function valid()
    {
        $echoStr = $_GET["echostr"];


        //valid signature , option
        if($this->checkSignature()){
        echo $echoStr;
        exit;
        }
    }


    public function responseMsg()
    {
//get post data, May be due to the different environments
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];


      //extract post data
if (!empty($postStr)){
                
              $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); #这里有从用户通过公众平台接收过来的数据,具体是什么类型的数据,开发者文档上写的很清楚,可以去上面查。
                $fromUsername = $postObj->FromUserName;
                $toUsername = $postObj->ToUserName;
                $keyword = trim($postObj->Content);
$msgType = $postObj->MsgType;
                $time = time();
switch( $msgType ){
case "text": #这个xml格式的数据是你服务器上的数据,是要传回公众平台的。我在这刚开始有点糊涂了
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>

</xml>";         

#这里是我自己写的,关于时间的自动回复     
if( $keyword =='时间' || $keyword =='time' || $keyword =="shijian"){
$contentStr = date("Y-m-d H:i:s",time());
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $resultStr;
}
else
{
$msgType = "text";
$contentStr = "欢迎您来到博论天涯!";
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $resultStr;
}

break;


case "event": #这个是事件的操作,当关注的时候自动回复
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
$event = $postObj->Event;
$msgType = "text";
if( $event =='subscribe'){
$contentStr = "这里是博论天涯,谢谢您关注!";
}
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $resultStr;
break;
}
                


        }else {
        echo "";
        exit;
        }
    }

private function checkSignature() #这个函数验证过之后就可以删除了
{
        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];
       
$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );

if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
}


?> 

[转载]自制公众平台Web Api(微信) - KAnts - 博客园

mikel阅读(1109)

[转载]自制公众平台Web Api(微信) – KAnts – 博客园.

公众平台

提起公众平台当下最流行的莫过于腾讯的微信了,当然还有易信等公众平台,每个公众平台都提供了一些API接口供开发者进行二次开发,当然肯定不是这 些所有的API都是我们需要的也当然不是所有的功能都是能通过这些API可以实现的,所以抱着这个问题我自己写了一些常用的API,技术当然是百用不厌的 模拟请求了。

Rabbit.PublicPlatformWebApi

目前这个项目托管在:https://publicplatformwebapi.codeplex.com/

实现的功能有

– 获取公众账号用户信息(头像图片、名称、登录邮箱、原始ID、微信号、账号类型、地区、说明、二维码图片、认证状态)
– 开启或者关闭编辑模式
– 开启或关闭开发者模式
– 设置开发者接口信息

运行Demo

demo

Demo代码

code

接口方法

interface

有什么用?

下面给出一个目前我正在做的一个项目,这个项目是跟移动Web相关的,有其中的一个模块是公众平台模块,可以实现跟微信、易信的对接,但以微信提供的API来看是需要用户手动进行绑定的,而且信息容易出错,所以萌生了一个自动绑定的想法,那么这些API就是所需要的了。

项目应用截图

image

image

image

争议

直接输入账号密码安全性怎么样?

安全性取决于用的人,目前在做的项目是没有收集和记录任何跟微信、易信账号密码相关的东西。

API有效期是多久?

不知道,微信随时可以更改他们的公众账号管理后台,至于能不能用主要还是取决于微信本身。

写在最后

这个方案是折中方案,腾讯完全有能力封杀这个方案,至于封杀1次、2次还是3次就不得而知了,这样做确实存在了泄露账号密码的隐患,但希望广大软件工程师合理使用,不要存储相关的账号密码。

后面会写一下易信的相关API。

期待微信和易信官方可以推出类似的API。