27-06-2018 0 条评论

我们在使用MYSQL的时候,并不是你建立了索引,你执行的SQL语句就一定会走索引,反之当数据量大的时候,走全表扫描,就会出现慢查询,为此我们有方法可以规避这种问题。
首先在这里不得不提下explain,关于它的用法,这里有详细的介绍 EXPLAIN的用法

索引列参与计算

如果where条件中age列中使用了计算,则不会使用该索引

SELECT `*` FROM `user` WHERE `age`=20; // 会使用索引
SELECT `*` FROM `user` WHERE `age`+10=30;// 不会使用索引!!因为所有索引列参与了计算
SELECT `*` FROM `user` WHERE `age`=30-10;//会使用索引

所以需要计算的话,不要放在索引列中,想办法放到右边去。

索引列使用了函数

同样的道理,索引列使用了函数,一样会导致相同的后果

SELECT `*` FROM `user` WHERE concat(`name`,'abc') ='bewynabc'; //不会使用索引,因为使用了函数运算,原理与上面相同
SELECT `*` FROM `user` WHERE `name` =concat('bewyn','abc');  // 会使用索引

索引列使用了Like %XXX

SELECT * FROM `user` WHERE `name` LIKE 'bewyn%'  //走索引
SELECT * FROM `user` WHERE `name` LIKE '%bewyn'  // 不走索引

所以当需要搜索email列中.com结尾的字符串而email上希望走索引时候,可以考虑数据库存储一个反向的内容reverse_email

SELECT * FROM `table` WHERE `reverse_email` LIKE REVERSE('%.com');  // 走索引

注:以上如果你使用REVERSE(email) = REVERSE(‘%.com’),一样得不到你想要的结果,因为你在索引列email列上使用了函数,MySQL不会使用该列索引

同样的,索引列上使用正则表达式也不会走索引。

字符串列与数字直接比较

这是一个坑,假设有一张表,里面的a列是一个字符char类型,且a上建立了索引,你用它与数字类型做比较判断的话:

 SELECT * FROM `user` WHERE `a`='1' //走索引
 SELECT * FROM `user` WHERE `a`=1   //字符串和数字比较,不走索引!

但是如果那个表那个列是一个数字类型,拿来和字符类型的做比较,则不会影响到使用索引

 SELECT * FROM `user` WHERE `b`='1'   //虽然b是数字类型,和'1'比较依然走索引

但是,无论如何,这种额外的隐式类型转换都是开销,而且由于有字符和数字比就不走索引的情况,故建议避免一切隐式类型转换

尽量避免 OR 操作

select * from user where name='bewyn' or address='sh' or phone=137xxx //这样的语句,即使条件中有带索引的列也不会走索引,除非全部建立索引。

所以除非每个列都建立了索引,否则不建议使用OR,在多列OR中,可以考虑用UNION 替换

select * from user where name='bewyn' union
select * from user where address='sh' union
select * from user where phone=137xxx
05-06-2018 0 条评论

在我们实际的应用开发中,可能会涉及到jquery validate验证表单的使用,同时对多个相同name的表单验证,如下图所示:
QQ截图20180605195230
这是一个很典型的例子,我们需要保证每个表单都是相同name,这时候如果使用传统的做法,只会验证第一个表单,显然这是我们所不愿意看到的结果,我们想要实现的如下图所示。
QQ截图20180605195520
解决的方法就是在你的JS里面写上:

$(function () {  
if ($.validator) {  
    $.validator.prototype.elements = function () {  
        var validator = this,  
            rulesCache = {};  
        return $([]).add(this.currentForm.elements)  
        .filter(":input")  
        .not(":submit, :reset, :image, [disabled]")  
        .not(this.settings.ignore)  
        .filter(function () {  
            var elementIdentification = this.id || this.name;  
            !elementIdentification && validator.settings.debug && window.console && console.error("%o has no id nor name assigned", this);  
            if (elementIdentification in rulesCache || !validator.objectLength($(this).rules()))  
                return false;  
            rulesCache[elementIdentification] = true;  
            return true;  
        });  
    };  
}  
});

以上的代码就是当name的值相同的时候,就会用id来区分,现在我们需要保证每个表单(input)的id值是不同的,简单的做法就是表单+序号来处理。

{for start="0" end="5"}
  <input name="name[]" id="name_{$i}" />
{/for}
03-07-2017 0 条评论

我们在编码的时候,通过php解析标准xml数据,可能一行代码就可以搞定

$array = json_decode(json_encode((array)simplexml_load_string($xml)),1);

然而在使用非标准xml的时候,就不能解析了,这时候我们可以使用xmlParser来解析,
xmlParser:

<?php
/**
 * xmlParser
 *
 * @author     shashank Patel
 */

class xmlParser
{
    public $ssBlankShow = true;

    /**
    * @todo convert xml to array
    * @param string $contents
    * @param string $get_attributes
    * @param string $priority
    * @access public
    * @return mixed
    */
    public function xml2array($contents, $get_attributes=1, $priority = 'tag')
    {
        if(!$contents)
            return array();

        if(!function_exists('xml_parser_create'))
        {
            return array();
        }

        $parser = xml_parser_create('');
        xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
        xml_parse_into_struct($parser, trim($contents), $xml_values);
        xml_parser_free($parser);

        if(!$xml_values)
            return;

        $xml_array = array();
        $parents = array();
        $opened_tags = array();
        $arr = array();

        $current = &$xml_array;

        $repeated_tag_index = array();

        foreach($xml_values as $data)
        {
            unset($attributes,$value);

            extract($data);

            $result = array();

            $attributes_data = array();

            if(isset($value))
            {
                if($priority == 'tag')
                    $result = $value;
                else
                    $result['value'] = $value;
            }

            if(isset($attributes) and $get_attributes)
            {
                foreach($attributes as $attr => $val)
                {
                    if($priority == 'tag')
                        $attributes_data[$attr] = $val;
                    else
                        $result['attr'][$attr] = $val;
                }
            }

            if($type == "open")
            {
                $parent[$level-1] = &$current;
                if(!is_array($current) or (!in_array($tag, array_keys($current))))
                {
                    $current[$tag] = $result;

                    if($attributes_data)
                        $current[$tag. '_attr'] = $attributes_data;

                    $repeated_tag_index[$tag.'_'.$level] = 1;

                    $current = &$current[$tag];

                }
                else
                {
                    if(isset($current[$tag][0]))
                    {
                        $current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;

                        $repeated_tag_index[$tag.'_'.$level]++;
                    }
                    else
                    {
                        $current[$tag] = array($current[$tag],$result);

                        $repeated_tag_index[$tag.'_'.$level] = 2;

                        if(isset($current[$tag.'_attr']))
                        {
                            $current[$tag]['0_attr'] = $current[$tag.'_attr'];

                            unset($current[$tag.'_attr']);
                        }

                    }
                    $last_item_index = $repeated_tag_index[$tag.'_'.$level]-1;
                    $current = &$current[$tag][$last_item_index];
                }

            }
            elseif($type == "complete")
            {
                if(!isset($current[$tag]))
                {
                    $current[$tag] = $result;
                    $repeated_tag_index[$tag.'_'.$level] = 1;
                    if($priority == 'tag' and $attributes_data)
                        $current[$tag. '_attr'] = $attributes_data;

                }
                else
                {
                    if(isset($current[$tag][0]) and is_array($current[$tag]))
                    {
                        $current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;

                        if($priority == 'tag' and $get_attributes and $attributes_data)
                        {
                            $current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;
                        }

                        $repeated_tag_index[$tag.'_'.$level]++;

                    }
                    else
                    {

                        $current[$tag] = array($current[$tag],$result);

                        $repeated_tag_index[$tag.'_'.$level] = 1;

                        if($priority == 'tag' and $get_attributes)
                        {
                            if(isset($current[$tag.'_attr']))
                            {
                                $current[$tag]['0_attr'] = $current[$tag.'_attr'];
                                unset($current[$tag.'_attr']);
                            }

                            if($attributes_data)
                            {
                                $current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;
                            }
                        }
                        $repeated_tag_index[$tag.'_'.$level]++;
                    }
                }

            }
            elseif($type == 'close')
            {
                $current = &$parent[$level-1];
            }
        }

        return($xml_array);
    }

    /**
    * @todo convert array to xml
    * @param mixed $array
    * @param string $level
    * @param string $KeyForBlank
    * @access public    
    * @return mixed
    */
    public function array_to_xml($array, $level=1, $KeyForBlank = 'row')
    {
        $xml = '';

        if ($level==1)
        {
            $xml .= '<?xml version="1.0" encoding="UTF-8"?>'.
                "<musicbox><response>";
        }
        else if($level==11)
        {
            $xml .= '<?xml version="1.0" encoding="UTF-8"?>'."\n".
                "<xml>";
        }
        foreach ($array as $key=>$value)
        {

            $key = strtolower($key);
            $eleKey = $key;

            if (is_array($value))
            {
                if(sizeof($value)) {
                    if ( preg_match('/^\d+$/', $eleKey) ) $eleKey = $KeyForBlank;
                    $xml .= str_repeat("",$level)."<$eleKey>";
                    $level++;
                    $xml .= $this->array_to_xml($value, $level, $KeyForBlank);
                    $level--;
                    $xml .= str_repeat("",$level)."</$eleKey>";
                }
                else
                {  
                    if($eleKey == 'genre' || $this->ssBlankShow == true)
                        $xml .= str_repeat("",$level)."<$eleKey></$eleKey>";
                    else
                        $xml .= str_repeat("",$level)."<$eleKey />";
                }
            }
            else
            {
                if (trim($value)!='')
                {
                    if ( preg_match('/^\d+$/', $eleKey) ) $eleKey = $KeyForBlank;
                    if (htmlspecialchars($value)!=$value || $this->otherchar($value))
                    {
                        $xml .= str_repeat("",$level).
                                "<$eleKey>$value</$eleKey>";
                    }
                    else
                    {
                        $xml .= str_repeat("",$level).
                            "<$eleKey>$value</$eleKey>";
                    }
                }
                else
                {
                    if($eleKey == 'genre' || $this->ssBlankShow == true)
                        $xml .= str_repeat("",$level)."<$eleKey></$eleKey>";
                    else
                        $xml .= str_repeat("",$level)."<$eleKey />";
                }
            }
        }
        if ($level==1)
        {
            $xml .= "</response></musicbox>";
        }
        else if($level==11)
        {
            $xml .= "</xml>";
        }
        return $xml;
    }
    /**
    * @todo remove other char ('/\:/')
    * @param string $str
    * @access public    
    * @return mixed
    */


    public function otherchar($str)
    {
        return preg_match('/\:/', $str);
    }

}
使用方法:
$oXmlParser = new xmlParser();
$asArray = $oXmlParser->xml2array($resultXml);

$resultXml是xml的数据。
这时候返回的可能是多维数组,再通过foreach把最终的结果输出。

10-02-2017 0 条评论

在开发中,常遇到mysql查询一对多时,会显示成多条记录组成,这样在PHP环境中,去读取数据的时候,就会很麻烦,不能按照循环记录去读取。
使用下面方法可以解决这个问题,就可以使用循环去读取数据,其它的多条记录,显示在字段中,并且默认以逗号隔开。

数据表结构

A 表

id pid text

1 2 123
2 3 456

B 表

id aid con

1 2 111
2 2 222

SELECT a.id,a.text,group_concat(b.con) as con FROM a RIGHT JOIN b ON a.id=b.aid WHERE a.id=2 GROUP BY b.aid;
mysql> SELECT a.id,a.text,group_concat(b.con) as con FROM a RIGHT JOIN b ON a.id=b.aid WHERE a.id=2 GROUP BY b.aid;
+----+------+---------+
| id | text | con |
+----+------+---------+
| 2 | 456 | 111,222 |
+----+------+---------+
1 row in set

这样我们就可以PHP中实现循环,并且其它的多条记录字段都是显示在循环中的一条记录中。

14-09-2016 0 条评论

1. ./configure –prefix=/usr/local/nginx –add-module=/app/ngx_http_consistent_hash-master
安装第三方模块一致性哈希

2. make && make install

netstat -antp
可以看到是哪个进程及服务占用端口。

pkill – p http 强制杀死所有http服务

nginx 信号量

1.通过命令显示nginx服务

ps aux|grep nginx

2.杀死相应的进程(INT)

kill -INT 26733

3.优雅的关闭进程,即等请求结束后再关闭(QUIT)

kill -QUIT 26733

4.平滑的重启nginx(HUP)(无需重启nginx,就可以加载修改过的配置文件,此时也是优雅的关闭进程)

kill -HUP 26733

(备注:通过nginx提供的命令也可以执行操作,./sbin/nginx -s reload)

5.重读日志(USR1)

linux系统下一个文件对应着一个inode节点,因为nginx监听着当前的access.log节点,所以不管是重命名或者什么操作,日志都是写这个文件上。
可以通过如下命令,更改inode节点,重读日志,通过这个信号,我们可以把nginx下面的日志,按照每天的时间来存储。

kill -USR1 26733
(备注:通过nginx提供的命令也可以执行操作,./sbin/nginx -s reopen)

6. 当升级nginx软件时(USR2)配合(WINCH),可以平滑的升级,优雅关闭旧的进程,启用新版本的nginx进程。

tips:有些人觉得每次命令都要输个进程号很麻烦,有一种方法可以获取相应的PID。
cat logs/nginx.pid 可以显示相应的进程ID,所以可以使用命令:kill -INT ‘cat logs/nginx.pid’。

7. 通过命令可以查看配置文件正确

./sbin/nginx -t

8. nginx配置段
全局区
worker_processes 1 说明有1个子进程,这个值太大无益处,因为要争夺CPU,一般设置为CPU数*核数(如一个CPU,其中为4核),只需设置为4。

Event
一般是配置nginx进程与连接的特性。(如一个worker同时允许多少个连接)。
worker_connections 1024 一个子进程最大允许连1024个连接。
http
可以在server里面配置虚拟主机,可配IP、域名、端口。

9. 日志管理
nginx的server段有一条信息
#access_log logs/host.access.log main;
说明格式的日志是main格式,当然你也可以自定义格式。
main格式:
log_format main ‘$remote_addr – $remote_user[$time_local]”$request””
‘$status $body_bytes_sent “$http_referer”‘
‘$http_user_agent'”$http_x_forwarded_for”;
其中主要说下$http_x_forwarded_for这个选项,主要是用户在使用代理时,会把最后一层代理的IP加在头部信息中。

按照年月目录存诸当月每天的日志记录,需要使用到shell脚本以及crontab -e设置定时(定时计划)
sh:
#!/bin/bash
LOGPATH=/usr/local/nginx/logs/abc.com.access.log
BASEPATH=/data/$(date -d yesterday +%Y%m)
mkdir -p $BASEPATH
BAK = $BASEPATH/$(date -d yesterday +%d%H%M).abc.access.log
mv $LOGPATH $BAK
touch $LOGPATH
kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`

10.Location
精准匹配
如果不写root html 这行,则会继承nginx的目录,如:/usr/local/nginx/html
location = /index.htm{
root /var/www/html/;
index index.htm index.html;
}
location = /{
root /var/www/html/;
index index.htm index.html;
}
location /index.htm{
root html;
index index.htm index.html;
}
通过上面的这三个location,我可以分析出,当浏览器输入一个地址的时候,如:localhost,那么默认就会走第二个location,因为第二个是走index.htm,又因为是走根目录,所以会再次转发,所以再一次走到第一个精准匹配,反之如果把第二个的换成index index.html index.htm;,则会走第三个,因为第一个精准匹配不到,只有第三个不是精准匹配,所以匹配成功。

Location总结流程:当一个URI发出来的时候,首先会去找精准匹配,如果有匹配到,则会返回;如果没有,那么就会走普通匹配,看是否命中多个,记忆最长的匹配结果,暂时不返回出去,继续去寻找正则匹配,如果有匹配正则,则会直接返回,如果没有的话,就会返回刚才记忆最长的普通匹配。

11.Rewrite
如可以禁用某个IP不允许访问
location = /{
if($remote_addr=192.16/8.1.100){
return 403;
}
//正则匹配
if($http_user_agent ~ msie){
rewrite ^.*$ /msie.html;
break; //这里如果不break,会循环重定向。
}
//通过变量自定义404
if(!-e $document_root$fastcgi_script_name){
rewrite ^.*$ /404.html;
break;
}
//set设置变量用法
可以用来达到多条件判断时作标记用,达到apache下的rewrite_condition的效果。
如下:判断IE并重写,且不用break;这里纯是学习set的用法。
if($http_user_agent ~* msie){
set $isie 1;
}
if($fastcgi_script_name == ie.html){
set $isie 0;
}
if($isie 1){
rewrite ^.*$ ie.html
}
root /var/www/html/;
index index.htm index.html;
}
注意:用url重写时,正则里如果有{},正则就要用双引号包起来。

12.Nginx与PHP整合
因为PHP与nginx是独立运行的,它不同于apache是把php当成一个模块在运行,所以nginx是通过fastcgi通讯,将所有的php请求转发到php-fpm进程。
配置如下:
location ~ \.php{
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /home/html/$fastcgi_script_name;
include fastcgi_param;
}
在linux下,如果使用mysql连接服务器的时候,如果是有localhost会采用socket连接,所以php.ini必须要配置,如:
修改php.ini的下面选项。
mysql.default_socket = /var/lib/mysql/mysql.sock
当然除此之外面不想修改的话,那么就使用127.0.0.1连接,采用的就是tcp协议连接。
13.gzip压缩
原理:
浏览器–请求–>声明可以接受gzip压缩或deflate压缩或sdch压缩等。
从http协议角度看,声明acceopt-encoding:gzip deflat sdch头部压缩的算法。
sdch是google推出的一种压缩方式。
gzip配置的常用参数
gzip on|off; #是否开启gzip
gzip_buffers 32 4k| 16 8k #缓冲(压缩在内存中缓冲几块?每块多大?)
gzip_comp_level[1-9] #推荐6 压缩级别(级别越高,压的越小,越浪费CPU计算资源)
gzip_disable #正则匹配 UA 什么样的uri不进行gzip
gzip_min_length 200 #开始压缩的最小长度(再小就不要压缩了,意义不大)
gzip_http_version 1.0|1.1 #开始压缩的http协议(可以不设置,目前都是1.1协议)
gzip_proxied #设置请求者代理服务器,该如何缓存内容。
gzip_types text/plain application/xml #对哪些类型的文件用压缩,如:text,html,css,xml,js
gzip_vary on|off #是否传输gzip压缩标志
注意:图片/mp3,这样的二进制文件,不必压缩。
因为压缩率比较小,比如100->80字节,而且压缩也是耗费CPU资源的。
特别小的文件,也没有必要压缩,因为压缩本身也是有字节的。
14.缓存设置(expires)
格式:
location ~ \.(jpg|jpeg|gif|png|css|js)${
root html
expires 1d;
}
其中日期格式为:expires 1s(秒),30m(分),2h(小时),1d(天)。
注意:服务器的日期格式一定要准确,否则可能造成缓存失效。
其实304状态也是一种好的缓存手段。
原理:服务器响应文件内容时,同时响应etag标签(内容的签名,内容一样,他也变),和last_modified_since标签。
下次浏览器去请求时,先发送头信息,如果检查出文件没有发生改变(修改时间及etag),如果没有,直接返回头信息,所以size是0,浏览 器知道没有文件没有改变,直接调用本地缓存。
15.nginx反向代理服务器+负载均衡
反向代理:
location ~ \.php${
proxy_pass http://192.168.1.2:8080;
}
这里把所有的php请求,转到192.168.1.2服务器,也就是反向代理。

负载均衡
location ~ \.(jpg|jpeg|gif|png)${
proxy_pass http://imgserver;
}
upstream imgserver{
server 192.168.1.200:81 weight=1 max_fails=2 fail_timeout=3;
server 192.168.1.200:82 weight=1 max_fails=2 fail_timeout=3;
}
server{
listen 81;
server_name localhost;
root html;
}
server{
listen 82;
server_name localhost;
root html;
}

16.nginx连接memcached
nginx首先连接memcache,如果有则输出数据,如果没有则连接到php,再去mysql找数据,再用memcache SET数据。
location / {
set $memcached_key “$uri”;
memcached_pass 127.0.0.1:11211;
error_page 404 /callback.php
}
首先连接memcache,添加一个key,这时key就是uri参数。
如果要给memcached,做集群就使用一致性哈希。
upstream mcserver{
consistent_hash $request_uri;//使用一致性哈希
server 192.168.1.250:11211;
server 192.168.1.250:11212;
server 192.168.1.250:11213;
}
location / {
set $memcached_key $request_uri;
memcached_pass mcserver;
error_page 404 /callback.php
}

memcache 也需要设置一致性哈希。
1.首先php需要添加多台memcache服务器。
2.修改php.ini,支持一致性哈希
memcache.hash_strategy=consistent
Upstream做负载均衡时,要用IP或者远程主机名,不要使用localhost。

17.安装统计模块,便于观察nginx状态
编译nginx的时候带上 –with-http_stub_status_module

location /status {
stub_status on;
access_log off;
allow 192.168.1.100;//允许这个IP访问
deny all;//其它禁止访问
}

18.nginx高并发优化

主要思路通过优化socket和文件
1.socket
系统层面:
最大连接数somaxconn
查看连接数 more /proc/sys/net/core/somaxconn
设置echo 50000 > /proc/sys/net/core/somaxconn
加快tcp连接的回收 recycle
cat /proc/sys/net/ipv4/tcp_tw_recycle 默认是0,不快速回收。需要改为1
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
空的tcp是否允许回收利用reuse
cat /proc/sys/net/ipv4/tcp_tw_reuse 默认是0,不回收利用。需要改为1
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse
洪水攻击 不做洪水抵御
more /proc/sys/net/ipv4/tcp_syncookies 为1就是抵御,需要改为0
echo 0 > /proc/sys/net/ipv4/tcp_syncookies
nginx:
子进程允许打开的连接(worker_connections)
http连接快速关闭(keep_alivetime=0)
2.文件
系统层面:
ulimit -n 设置一个比较大的值
ulimit -n 50000
nginx:
子进程允许打开的文件 worker_limit_nofile
worker_limit_nofile 10000
19.服务器集群搭建
php-fpm启动,监听多个端口。
start.sh
#!/bin/sh
/usr/local/php/sbin/php-fpm -y /usr/local/php/etc/php-fpm.conf
/usr/local/php/sbin/php-fpm -y /usr/local/php/etc/php-fpm9001.conf
/usr/local/php/sbin/php-fpm -y /usr/local/php/etc/php-fpm9002.conf
/usr/local/php/sbin/php-fpm -y /usr/local/php/etc/php-fpm9003.conf
/usr/local/php/sbin/php-fpm -y /usr/local/php/etc/php-fpm9004.conf

02-08-2016 0 条评论

因为发现很多人不会源码安装lnmp环境,刚好准备搭建环境,所以把基本步骤写出来,以后大家照着敲就可以。
本次搭建使用的都是最新的nginx1.11.3和php7(号称比5.6有2倍的性能提升),以及mysql5.7.13(号称有着一倍的性能提升)。
首先我们来安装mysql5.7.13
因为使用的是ubuntu12.04所以使用deb安装,见地址,先下载下来。

wget http://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-server_5.7.14-1ubuntu12.04_amd64.deb-bundle.tar

然后解压:

tar xvf mysql-server_5.7.14-1ubuntu12.04_amd64.deb-bundle.tar

会得到如下文件:

 1.mysql-common_5.7.14-1ubuntu14.04_amd64.deb
2.libmysqlclient20_5.7.14-1ubuntu14.04_amd64.deb
3.libmysqlclient-dev_5.7.14-1ubuntu14.04_amd64.deb
4.libmysqld-dev_5.7.14-1ubuntu14.04_amd64.deb
5.mysql-community-client_5.7.14-1ubuntu14.04_amd64.deb
6.mysql-client_5.7.14-1ubuntu14.04_amd64.deb
7.mysql-community-server_5.7.14-1ubuntu14.04_amd64.deb

依次安装执行:

sudo dpkg -i mysql-common_5.7.14-1ubuntu12.04_amd64.deb libmysqlclient20_5.7.14-1ubuntu12.04_amd64.deb libmysqlclient-dev_5.7.14-1ubuntu12.04_amd64.deb libmysqld-dev_5.7.14-1ubuntu12.04_amd64.deb mysql-client_5.7.14-1ubuntu12.04_amd64.deb mysql-community-server_5.7.14-1ubuntu12.04_amd64.deb

其间会提输入root密码。
添加mysql用户组和用户。
groupadd mysql
useradd -r -g mysql mysql
默认安装的文件在:
配置文件:/etc/mysql/my.cnf
datadir:/var/lib/mysql 需要赋予mysql权限 chown -R mysql:mysql ./
mysqld /usr/sbin/mysqld
如果安装完成之后没有看到data文件夹,可以操作下面的步骤。
/usr/sbin/mysqld –user=mysql –datadir=/var/lib/mysql/data/mysql –initial –initialize-insecure
现在可以启动mysql服务了。
/etc/init.d/mysql start
nginx安装
wget https://nginx.org/download/nginx-1.11.3.tar.gz
tar zxvf nginx-1.11.3.tar.gz
cd nginx-1.11.3
groupadd nginx
useradd -r -g nginx nginx

./configure --prefix=/usr/local/nginx \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--user=nginx \
--group=nginx \
--with-http_gzip_static_module \
--with-pcre \

通常安装nginx需要使用zip和pcre一个是用来数据传输压缩及使用正则表达式(rwrite)
make && make install
PHP安装
wget http://cn2.php.net/distributions/php-7.0.9.tar.gz
tar zxvf php-7.0.9.tar.gz
cd php-7.0.9

./configure --prefix=/usr/local/php7 \
--with-config-file-path=/usr/local/php7/etc \
--with-mcrypt=/usr/include \
--with-gd \
--with-iconv \
--with-zlib \
--enable-xml \
--enable-bcmath \
--enable-shmop \
--enable-sysvsem \
--enable-inline-optimization \
--enable-mbregex \
--enable-fpm \
--enable-mbstring \
--enable-ftp \
--enable-gd-native-ttf \
--with-openssl \
--enable-pcntl \
--enable-sockets \
--with-xmlrpc \
--enable-zip \
--enable-soap \
--without-pear \
--with-gettext \
--enable-session \
--with-curl \
--with-jpeg-dir \
--with-freetype-dir \
--enable-sockets \
--enable-opcache \
--with-mysqli=mysqlnd \
--with-pdo-mysql=mysqlnd

因为php7版本不支持mysql,所以这里不需要安装。
当然对于一个新的ubuntu系统,不能顺利的完成检测。
所以这时候就要根据系统的提示安装相应的软件,如:libxml2、jpg、png、curl等。
可以使用ubuntu系统自带的apt-get install。
make && make install
nginx与php-fpm通讯
一般安装完成php就有php-fpm,不过相应的配置文件可能要重新命名。
即php7/etc/php-fpm.conf.default
cp php-fpm.conf.default php-fpm.conf
因为fpm.conf默认使用的是nobody用户名及用户组,系统中是不存在的,所以需要新建。
groupadd nobody
useradd -r -g nobody nobody
现在切换到nginx,使它能与php-fpm通讯。
打开下面的注释。

 location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

至此,lnmp环境就已经装好了,现在你的程序开始启航了。

28-07-2016 0 条评论

因为之前的一个系统在使用PHPEXCEL导入的时候,出现了系统崩溃的问题,后面经过一步步的分析,在load()里面中断,系统无法响应。
解决这个问题其实很简单。
一般影响这个问题的原因,是你的excel里面的内容有出现特殊的字符。
解决方法:

try {
     $inputFileType = PHPExcel_IOFactory::identify($uploadfile);
     $objReader = PHPExcel_IOFactory::createReader($inputFileType);
     $objReader->setReadDataOnly(true);//只需要添加这个方法
     $objPHPExcel = $objReader->load($uploadfile);
    } catch(Exception $e) {
         die('Error loading file "'.pathinfo($uploadfile,PATHINFO_BASENAME).'": '.$e->getMessage());
    }

其意思就是读取相应的单元格的数据,忽略任何格式的信息。
我们来看下官方的代码。

    /**
     * Read data only?
     * Identifies whether the Reader should only read data values for cells, and ignore any formatting             information;
     * or whether it should read both data and formatting
     * @var boolean
     */
    protected $_readDataOnly = FALSE;

默认使用的是false。

20-06-2016 0 条评论

有时因为项目的需求,一个项目要布署多套系统,所以即使有版本控制往往也需要手动更新代码,造成项目维护性差。
下面通过shell脚本,可以通过svn up定时自动更新代码

#! /bin/sh
filelist=`ls /var/www/html/ |grep '^new_o2o_'`
for file in $filelist
do
   while read line
   do
   svn up ./$file/$line
   done < svn_update.txt
done

其中svn_update.txt 存储更新的文件路径,每行一个文件。
设置crontab -e 设置脚本运行时间。

14-06-2016 0 条评论

1.php错误日志保存
基本的方法是使用error_log进行保存,可以存放在一个目录下。
如:

error_log(
    date_default_timezone_set('asia/chongqing');

格式是:错误的日志,发生错误的级别,显示错误错的代码
如:
date().$a.’\r\n’,3,$b;

date(‘Y年m月d日—G小时i分钟s秒’).$变量名–将错误的日志赋值给这个变量.’\r\n’,3,’d:\dir—指的是存放的目录’;
)
2.php异常处理
请记住一点:PHP默认的异常处理是一个类,是系统默认的类,即:Exception。
1.基本语法

    try{
        //可能出现错误或是异常的代码
    }
    //catch 捕获  Exception 是异常类(是php定义好的一个类)
    catch(Exception e){
        //对异常处理
        //1.自己处理
        //2.自己不处理,将其抛出
    }

例子:

    try{
        a('addd');
        echo '12155';
    }catch(EXception $a){
    echo '失败了'.$a->getMessage();
    //可以继续抛出,这时将会启动PHP默认的异常处理器来处理。
    //你可以自定义一个顶级异常处理,见下文有介绍。
    }
    function a($name){
        if($name=='peng'){
            echo '这是正确的peng';
        }else{
            throw new Exception ('出错了');
        }
    }

//这种处理的方式,可以有效的控制错误,所以在开发中大量的使用。
注意事项:
1.当捕获到一个异常后,try{}里面后续代码将不会被执行,需要注意的是前面的代码可以执行,
那这到底是个什么样的意思呢?
如上的例子中,echo ‘12155’是不会被执行的,反之如果这样修改:

    try{
        echo '12155';
        a('addd');
        //这里的12155是会被执行的。
    }

2.定义一个顶级异常处理器

    function my_exception($e){
        echo '我是顶级异常处理器'.$e->getMessage();
    }

//修改默认的顶级异常处理函数(器)

set_exception_handler("my_exception");

3.如果一个异常发生,但是你没有catch捕获,则提示Uncatched Exception。
4.当catch一个异常,你可以处理,也可以不处理,不处就可以。

throw new Exception('信息');

5.使用多个catch代码块可以捕获不同种类的异常。

    try{
        //代码码...需要进行检测代码的异常
    }catch(PDOException $e){

    }catch(Exception $e){

    }

    try{
    $i=8/0;
    }catch(Exception $e){
    echo 'ok';
    echo $e->getMessage();
    }

这个例子并不会执行’ok’,原因是$i=8/0,并没有抛出异常。
所以可以看出,能不能捕获(catch)到异常,要取决于有没有真的抛出异常。

14-06-2016 0 条评论

我们知道在php里面,session默认保存的路径都是在/tmp/session或/var/lib/php5,这样就造成了这个目录里面的文件数太多,引发了PHP性能问题,所以我们可以设置多级目录,当然也可以把session放在mysql或者redis,这里我们只说分级目录,后续会讲mysql及redis方案。
首先,修改 php.ini的 session.save_path 选项修改如下:

session.save_path = “2;/tmp/session“  //这里设置2级就可以
session.hash_function = 1 //默认是为0(md5),这里设置为1(sha1)
session.hash_bits_per_character = 5 //指定在SID字符串中的每个字符内保存多少bit  4: 0-9, a-f ;5: 0-9, a-v; 6: 0-9, a-z, A-Z, “-“, “,”

找到PHP安装目录下的ext/session/mod_files.sh 通过脚本就可以生成目录。

#! /bin/sh
 
if test "$2" = ""; then
echo "usage: $0 basedir depth"
exit 1
fi
 
if test "$2" = "0"; then
exit 0
fi
 
hash_chars="0 1 2 3 4 5 6 7 8 9 a b c d e f"
if test "$3" -a "$3" -ge "5"; then
hash_chars="$hash_chars g h i j k l m n o p q r s t u v"
if test "$3" -eq "6"; then
hash_chars="$hash_chars w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z - ,"
fi
fi
 
for i in $hash_chars; do
newpath="$1/$i"
mkdir $newpath || exit 1
sh $0 $newpath `expr $2 - 1` $3
done

#cd /home
#./mod_files.sh /var/lib/php5 2 5 //参数表示 存放路径, 几级目录,每个目录生成多少个目录。
其中一点,需要注意其存储目录(/tmp/session或/var/lib/php5),要有相应的执行权限,可以给777。
因为通过使用session多级目录,php是不会释放资源的,所以需要我们自己写脚本定时清理。
rm_session_auto_mksession.sh

#! /bin/sh
rm -rf /var/lib/php5/*
/home/sh/session_mod_file.sh /var/lib/php5 2 5
chmod -R 777 /var/lib/php5

通过这个脚本和上面的脚本配合crontab -e就可以定时清理SESSION文件。
0 3 * * * /home/sh/rm_session_auto_mksession.sh,每天凌晨3点开始工作。