PHP5.6

CentOS 默认的 yum 源安装的 PHP 版本过低,又想通过 yum 来安装 PHP5.6。

  • 查看系统上是否安装了 PHP,有就删除。
    查看系统是否安装了 PHP
    yum list installed | grep php
    # 删除PHP相关的模块
    yum remove phpxxx
    
  • 添加 EPEL 和 REMI 源
    rpm -Uvh http://ftp.iij.ad.jp/pub/linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
    rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
    
  • 查看 yum 源是否有 PHP5.6 及相关库
    yum list --enablerepo=remi --enablerepo=remi-php56 | grep php
    
  • 添加 REMI 源成功之后,安装 PHP5.6 及相关库
    yum install --enablerepo=remi --enablerepo=remi-php56 php-fpm php-opcache php-devel php-mbstring php-mcrypt php-mysqlnd
    

Nginx

  • 添加 nginx 的 yum 源
    wget http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm
    rpm -ivh nginx-release-centos-6-0.el6.ngx.noarch.rpm
    

    或者直接添加 /etc/yum.repos.d/nginx.repo

    [nginx]
    name=nginx repo
    baseurl=http://nginx.org/packages/centos/6/$basearch/
    gpgcheck=0
    enabled=1
    
  • 安装 nginx
    yum install -y nginx
    

MySQL

  • 删除系统中旧版本的MySQL
    # 检测到系统中有 mysql-libs-5.1.73-3.el6_5.x86_64
    rpm -qa | grep mysql   
    # 删除旧版本MySQL包和相关的依赖
    rpm -e --nodeps mysql-libs-5.1.73-3.el6_5.x86_64
    
  • 添加 MySQL 的 yum 源。
    到 https://dev.mysql.com/downloads/repo/yum/ 下载相应的 RPM 包,如:mysql57-community-release-el6-11.noarch.rpm

    wget https://repo.mysql.com//mysql57-community-release-el6-11.noarch.rpm
    rpm -Uvh mysql57-community-release-el6-11.noarch.rpm
    
  • 安装 MySQL
    yum install mysql-community-server
    

    更多信息可以参考:A Quick Guide to Using the MySQL Yum Repository

MariaDB

  • 添加 yum 源
    Setting up MariaDB Repositories 生成相应 的 yum 源,然后添加到 /etc/yum.repos.d/mariadb.repo

    [mariadb]
    name = MariaDB
    baseurl = http://yum.mariadb.org/10.2/centos6-amd64
    gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
    gpgcheck=1
    
  • 安装 MariaDB
    yum install -y MariaDB-server MariaDB-client MariaDB-devel
    

用官方源下载在没有翻墙的情况下是很慢的,可以用中国科学技术大学的镜像,不过也很不稳定。

调用请求说明

  • 请求 URL:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack

  • 是否需要证书:是

  • 请求方式: POST

请求参数(必填)

| 字段名 | 字段 | 示例值 | 类型 | 说明 |

|————|——–|————|———|———|

| 随机字符串 | nonce_str | 5K8264ILTKCH16CQ2502SI8ZNMTM67VS | String(32) | 随机字符串,不长于 32 位 |

| 商户号 | mch_billno | 1234567890 | String(32) | 微信支付的商户号 |

| 公众账号 appid | wxappid | wx1234567890abcdef | String(32) | 微信公众号的 appid (在mp.weixin.qq.com申请的) |

| 商户名称 | send_name | 京东商城 | String(32) | 红包发送者名称 |

|商户订单号 | mch_billno | 1234567890201606011234567890 | String(28) | 每个订单号必须唯一,组成:mch_id+yyyymmdd+10位一天内不能够重复的数字。|

| 用户 openid | re_openid | oxTWIuGaIt6gTKsQRLau2M0yL16E | String(32) | 接受红包的用户在 wxappid 下的 openid |

| Ip 地址 | client_ip | 192.168.0.1 | String(15) | 调用接口的机器的 IP 地址 |

| 付款金额 | total_amount | 1000 | int | 红包金额,单位是分。红包金额范围:¥1 ~ ¥200 |

| 红包发放总人数 | total_num | 1 | int | 红包发放总人数 |

| 红包祝福语 | wishing | 恭喜发财 | String(128) | 红包祝福语 |

| 活动名称 | act_name | 拜年 | String(32) | 活动名称 |

| 备注 | remark | 备注 | String(256) | 备注信息 |

| 签名 | sign | 5K8264ILTKCH16CQ2502SI8ZNMTM67VS | String(32) | 生成的签名 |

数据示例:



<xml> <sign><![CDATA[E1EE61A91C8E90F299DE6AE075D60A2D]]></sign> <mch_billno><![CDATA[0010010404201411170000046545]]></mch_billno> <mch_id><![CDATA[888]]></mch_id> <wxappid><![CDATA[wxcbda96de0b165486]]></wxappid> <send_name><![CDATA[send_name]]></send_name> <re_openid><![CDATA[onqOjjmM1tad-3ROpncN-yUfa6uI]]></re_openid> <total_amount><![CDATA[1000]]></total_amount> <total_num><![CDATA[1]]></total_num> <wishing><![CDATA[恭喜发财]]></wishing> <client_ip><![CDATA[127.0.0.1]]></client_ip> <act_name><![CDATA[拜年]]></act_name> <remark><![CDATA[备注]]></remark> <nonce_str><![CDATA[50780e0cca98c8c8e814883e5caa672e]]></nonce_str> </xml>

实现步奏

  • 获取随机字符串

/** * 获取指定长度的随机字符串 * ASCII 码: a-z: 97-122; A-Z: 65-90 * @param int $length * @return string */ public function getRandom($length = 32) { $nonce_str = ''; for ($i=0; $i<$length; $i++) { $random = rand(0, 61); $c = $random < 10 ? rand(0, 9) : chr(rand(1, 26) + rand(0, 1)*32 + 64); $nonce_str .= $c; } return $nonce_str; }
  • 整合请求发送的数据

/** * 微信发送红包的请求数据(除了签名参数 sign) * @return array */ public function angPaoData() { // 活动名称 $act_name = 'act_name'; // 备注 $remark = 'remark'; $data = array( 'nonce_str' => getRandom(32), 'mch_billno' => $mch_billno.date('YmdHis').rand(1000, 9999), 'mch_id' => $mch_billno, // 商户号 'wxappid' => $wxappid, // 公众号 appid 'send_name' => $send_name, // 商户名称 're_openid' => $open_id, // 用户 openid 'total_amount' => $total_amount, // 红包金额 'total_num' => 1, // 红包发放人数 'wishing' => $wishing, // 红包祝福语 'client_ip' => $client_ip, // 当前客户端 IP 地址 'act_name' => $act_name, 'remark' => $remark, ); return $data; }
  • 签名算法

function getSign($data) { global $_W; ksort($data, SORT_STRING); $stringA = ''; // 第一步,将所有发送的参数按照 key=value 的格式组成字符串 stringA, // 并且 key 要按照 ASCII 码从小到大排序(字典序) foreach ($data as $k => $v) { if ($k && $v && $k != 'sign') { $stringA .= "{$k}={$v}&"; } } // 第二步,在 stringA 最后拼接上 key 得到 stringSignTemp 字符串, // 并对 stringSignTemp 进行 MD5 运算,再将得到的字符串所有字符转换为大写 // key 设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 $setting = uni_setting($_W['uniacid'], array('payment')); $key = $setting['payment']['wechat']['apikey']; $stringSignTemp = $stringA . "key=" . $key; return strtoupper(md5($stringSignTemp)); }
  • 发送数据的时候,不要忘记了将数据转换成指定的 xml 格式

/** * 将数据转换成符合传送要求的 xml 格式 * @param $data * @return string */ function array2xml($data) { $xml = "<xml>"; foreach ($data as $k => $v) { $xml .= "<" . $k . "><![CDATA[" . $v . "]]></" .$k . ">"; } $xml .= "</xml>"; return $xml; }
  • 获取微信支付证书文件

为了安全,一般将证书的内容保存到数据库中,使用的时候读取出来,保存到文件中去,用完之后,及时删除掉。


/** * 获取微信支付文件: * 1、apiclient_cert.pem * 2、apiclient_key.pem * 3、rootca.pem */ public function getPayFile() { // 从数据库中取出来 $sec = m('common')->getSec(); $certs = iunserializer($sec['sec']); if (is_array($certs)) { if (empty($certs['cert']) || empty($certs['key']) || empty($certs['root'])) { message('未上传完整的微信支付证书,请到【系统设置】->【支付方式】中上传!', '', 'error'); } $certfile = IA_ROOT . "/addons/sz_yi/cert/apiclient_cert.pem"; file_put_contents($certfile, $certs['cert']); $keyfile = IA_ROOT . "/addons/sz_yi/cert/apiclient_key.pem"; file_put_contents($keyfile, $certs['key']); $rootfile = IA_ROOT . "/addons/sz_yi/cert/rootca.pem"; file_put_contents($rootfile, $certs['root']); $extras['CURLOPT_SSLCERT'] = $certfile; $extras['CURLOPT_SSLKEY'] = $keyfile; $extras['CURLOPT_CAINFO'] = $rootfile; } else { message('未上传完整的微信支付证书,请到【系统设置】->【支付方式】中上传!', '', 'error'); } return @$extras ?: array(); }
  • 用 CURL 发送数据

/** * @param $url * @param $vars * @param int $second * @param array $aHeader * @return bool|mixed */ function curl_post_ssl($vars, $second=30, $aHeader=array()) { $url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack'; $ch = curl_init($url); curl_setopt($ch, CURLOPT_TIMEOUT, $second); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //cert 与 key 分别属于两个.pem文件 //请确保您的libcurl版本是否支持双向认证,版本高于7.20.1 foreach ($this->getPayFile() as $k => $v) { curl_setopt($ch, constant($k), $v); } if( count($aHeader) >= 1 ){ curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader); } curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $vars); $data = curl_exec($ch); if($data){ curl_close($ch); return $data; } else { $error = curl_errno($ch); //echo "call faild, errorCode:$error\n"; curl_close($ch); return false; } }
  • 发送红包

/** * 发送红包 * @return bool|mixed */ public function angPaoPay() { // 红包请求数据 $data = $this->angPaoData(); $data['sign'] = $this->getSign($data); // 将数据转换成 xml 格式 $postXml = array2xml($data); $responseXml = $this->curl_post_ssl($postXml); // 为了证书安全,及时删掉 foreach ($this->getPayFile() as $file) { unlink($file); } return $responseXml; }

安装 Memcached 和 php memcached 扩展(ubuntu)


sudo apt-get install memcached php5-memcached

安装完 Memcached 服务会自动启动:


ps -ef | grep memcached memcache 11238 1 0 15:54 ? 00:00:00 /usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1

安装 Memcached 和 php memcache 扩展(ubuntu)

如果你不是用 php-memcached 扩展,而用 php-memcache 扩展,则


sudo apt-get install memcached php5-memcache

安装成功之后,还需要在 PHP 的配置文件 php.ini 中添加:


extension=memcache.so

保存,然后重启 PHP。

配置

Ubuntu 系统,Memcached 的配置文件为 /etc/memcached.conf。修改完配置之后,重启即可。

Memcache 和 Memcached

Memcache 是一个高性能的分布式的内存对象缓存系统。它可以应对任意多个连接,使用非阻塞的网络 IO。

工作机制是,通过在内存中开辟一块空间,然后建立一个HashTable,Memcached 程序管理这些 HashTable。这块内存空间能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。简单的说就是,将数据调用到内存中,然后,从内存中读取,从而大大提高读取速度。

  • Memcache:是该系统的项目名称。

  • Memcached:是该系统的主程序文件(d可以理解为 daemon),以守护进程方式运行于一个或多个服务器中,随时接收客户端的连接和操作。

Memcache 服务器端和客户端

  • 服务器端

Memcached 是 memcache 缓存系统的服务器端,它以守护进程方式运行于服务器上。同时,memcached 也是 memcache 服务器端的后台守护进程名。

  • 客户端

那么什么是 memcache 客户端呢?你可能用 PHP 开发网站,也可能用 Python、java 等其他语言,这些相对于 memcache 缓存系统就是是客户端,都是在使用服务器的服务。再细化一点来说(如 PHP),PHP 的 memcache 扩展 php-memcache 或 php-memcached 就是 memcache 系统的客户端。

php memcache 和 php memcached

PHP 想要使用 memcache 缓存系统,需要安装 memcache 客户端,即 memcache 的扩展。当安装 PHP 的 memcache 扩展的时候,发现有 php-memcache 和 php-memcached 两个。

  • php memcache:是完全在 PHP 框架内开发的,是原生实现的。

  • php memcached:则是使用了 libmemcached。在功能和性能上,都要比 php memcache 要好。

所以,PHP 安装 memcache 扩展的时候,建议安装 php-memcached。

#!/bin/sh

### BEGIN INIT INFO
# Provides:          php5-cgi
# Required-Start:    $remote_fs $network 
# Required-Stop:     $remote_fs $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: starts the php5-cgi
# Description:       Starts the PHP FastCGI Process Manager Daemon
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/spawn-fcgi
NAME=php5-cgi
CGI_FILE=/usr/bin/$NAME
PID_FILE=/var/run/${NAME}.pid
DAEMON_ARGS="-a 127.0.0.1 -p 9000 -C 32 -u lizs -g lizs -f $CGI_FILE -P $PID_FILE"

# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB functions.
. /lib/lsb/init-functions 

#
# Check if php5-cgi is running 
#
do_check() 
{
    # Return
    # 0 if php5-cgi doesn't has been started
    # 1 if php5-cgi was already running
    ps -ef | grep $NAME | grep -v grep > /dev/null || return 0
    return 0
}

#
# Start php5-cgi
#
do_start() 
{
    # Return 
    #   0 if daemon has been started successfully
    #   1 if daemon was already running
    #   2 if daemon could not be started
    start-stop-daemon --start --test --quiet --pidfile $PID_FILE --exec $DAEMON > /dev/null \
        || return 1 
    start-stop-daemon --start --quiet --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_ARGS 2> /dev/null \
        || return 2
    #spawn-fcgi -a 127.0.0.1 -p 9000 -C 32 -u lizs -g lizs -f /usr/bin/${NAME} -P $PID_FILE
}

# 
# Stop php5-cgi
#
do_stop() 
{
    # Return
    #   0 if daemon has beent stopped successfully
    #   1 if daemon was already stopped
    #   2 if daemon could not be stopped
    #   other if a failure occurred
    start-stop-daemon --stop --quiet --retry=QUIT/30/TERM/5/KILL/5 --pidfile $PID_FILE --name $NAME --remove-pidfile
    RETVAL="$?"
    return "$RETVAL"
    #killall $NAME
    #rm -f $PID_FILE
}

case "$1" in
    start)
        if init_is_upstart; then
            exit 1
        fi
        log_daemon_msg "Starting $NAME"
        do_start
        case "$?" in
            0|1)    log_end_msg 0 ;;
            2)      log_end_msg 1 ;;    
        esac
        ;;
    stop)
        if init_is_upstart; then
            exit 1
        fi
        log_daemon_msg "Stopping $NAME"
        do_stop
        case "$?" in
            0|1)    log_end_msg 0 ;;
            2)      log_end_msg 1 ;;
            *)      log_end_msg 1 ;;
        esac
        ;;
    restart)
        if init_is_upstart; then
            exit 1
        fi
        log_daemon_msg "Restarting $NAME"
        do_stop
        case "$?" in
            0|1)    
                do_start
                case "$?" in
                    0) log_end_msg 0 ;;
                    1) log_end_msg 1 ;;
                    2) log_end_msg 1 ;;
                    *) log_end_msg 1 ;;
                esac
                ;;
            *)  
                log_end_msg 1
                ;;
        esac
        ;;
    status)
        status_of_proc "$CGI_FILE" "$NAME" && exit 0 || exit $?
        exit 0;
        ;;
    reload|force-reload)
        # No-op
        exit 0
        ;;
    *)
        echo "Usage: $NAME {start|stop|status|help}" >&2
        exit 1
        ;;
esac

php-cgi 开机启动(ubuntu)

  • 将 php-cgi 的启动添加到系统启动服务 rc-local/etc/rc.local(个别版本可能不一样,具体查看/etc/init.d/rc.local

spawn-fcgi -a 127.0.0.1 -p 9000 -C 32 -u lizs -g lizs -f /usr/bin/php5-cgi -P /var/run/php5-cgi.pid
  • 自己写一个 LSBInitScript 脚本来启动服务。这样不但可以开机启动还可以随时用 service 来控制 php-cgi 程序的启动/关闭/重启等。

php-cgi 重启

php-cgi 的重启没有像 Nginx service nginx restart 那样的快捷方式,所以,我们可以通过先杀死所有 php-cgi 进程,再启动 php-cgi 的方式来达到重启的目的。

当然,如果可以自己写一个启动服务 LSBInitScript 最好,直接可以用 service 来实现重启功能。

  • 关闭所有 php-cgi 进程

sudo killall php-cgi
  • 启动 php-cgi

sudo spawn-fcgi -a 127.0.0.1 -p 9000 -C 32 -u lizs -g lizs -f /usr/bin/php5-cgi -P /var/run/php5-cgi.pid
  • spawn-fcgi:一个通用的 FastCGI 管理服务器,它是 lighttpd 的一部份,很多人都用 Lighttpd 的 Spawn-FCGI 进行 FastCGI 模式下的管理工作。

  • -a:address,绑定到的地址

  • -p:port,绑定到的端口

  • -C:指定产生的 FastCGI 的进程数

  • -u:user,运行的用户

  • -g:group,运行的用户组

  • -f:指定调用 FastCGI 的进程的执行程序

  • -P:指定产生的进程的 PID 文件路径

PHP 三元运算符 ?: 结合方向:自右往左

示例

如 status 有值为 1,2 和 3 三种情况,分别对应 type 的值:C,PHP 和 Python。

错误做法:


$type = $status == 1 ? 'C' : $status == 2 ? 'PHP' : 'Python';

无论 status 为任何值,得到的 type 的值都是 PHP。因为,PHP 三元运算符 ?: 的结合方向是自右往左

即,上面的代码实际上是这样执行的:


$type = ($status == 1 ? 'C' : $status == 2) ? 'PHP' : 'Python';

正确做法:


$type = $status == 1 ? 'C' : ($status == 2 ? 'PHP' : 'Python');

项目需求:

每天定时访问一次网站的某个网页,而且这个网页是需要登录才能够访问。

解决思路(linux系统):

解决其实很简单,只要每天定时用浏览器登录,然后访问就可以了。但是,这种做法是不现实的。我们可以利用 linux 的定时器(crontab) 来实现定时访问功能,然后用 PHP CURL 来模拟浏览器登录和访问。

  • 首先,在系统设置定时任务。定时执行某个 php 文件,如 timer.php

  • 在这个 php 文件中会实现两个功能,先登录,获取登录信息的 cookie,然后访问指定的网页。


/** * 先登录(登录需要获取 token) */ // 创建临时存放 cookie 的文件 $cookie_file = tempnam('./temp', 'cookie'); $login_url = 'http://..'; $ch = curl_init($login_url); // 是否将头文件的信息作为数据流输出 curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_POST, 1); // 先获取 token,已在登录页面设置好 curl_setopt($ch, CURLOPT_POST, array('curl_token' => 'curl_token')); $token = curl_exec($ch); // 登录 curl_setopt($ch, CURLOPT_POST, array( 'submit' => '登录', 'token' => $token, 'username' => 'xxx', 'password' => 'xxx', )); // 连接结束后,比如,调用 curl_close 后,保存 cookie 信息 curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file); // 再次连接,这次是登录 curl_exec($ch); curl_close($ch); /** * 利用登录获取的登录 cookie,访问页面 */ $url = 'http://...'; $ch = curl_init($url); curl_setopt($ch, CURLOPT_HEADER, 0); // 模拟登录状态的 cookie curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file); curl_exec($ch); curl_close($ch);

实践环境:ubuntu14.04

更新系统数据:


$ sudo apt-get update $ sudo apt-get upgrade

Nginx


$ sudo apt-get install nginx

成功安装之后,启动 Nginx 之后,访问localhost(127.0.0.1)会显示欢迎页面。

MySQL


$ sudo apt-get install mysql-server php5-mysql

如果需要,可以安装 phpmyadmin


$ sudo apt-get install phpmyadmin

PHP5

  • 安装 PHP5

$ sudo apt-get install php5-fpm

也可以同时安装其他 php5 库。


$ sudo apt-get install php5-fpm php5-cli php5-mysql php5-gd php5-mcrypt php5-curl

php5-cli:Command Line Interface,命令行界面。如果没有安装,你想要在终端执行 php 命令,或者执行一个 php 脚本文件(#!/usr/bin/php)等都是无法执行的。

php5-mysql:php5 的 mysql 数据库扩展,提供 php 能够访问 mysql 的接口。

php5-gd:gd 库是 php 处理图形的扩展库,gd 库提供了一系列用来处理图片的 API。

php5-mcrypt:php5 加密函数库

  • 配置 php5-fpm

更改配置文件 /etc/php5/fpm/php.inicgi.fix_pathinfo 的值为 0,然后,重启 php5-fpm 服务。

  • 配置 Nginx

配置 Nginx,是它支持 php 文件。

文件:/etc/nginx/sites-available/default


location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; # # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini # # # With php5-cgi alone: # fastcgi_pass 127.0.0.1:9000; # # With php5-fpm: fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; }

然后,重新载入 Nginx 配置:service nginx reload

PHP7

  • 添加 PPA(Personal Package Archives)

sudo apt-get install python-software-properties software-properties-common sudo add-apt-repository ppa:ondrej/php sudo apt-get update
  • 安装 php7.0

sudo apt-get install php7.0-fpm

也可同时安装 php7.0 的一些扩展


sudo apt-get install php7.0-fpm php7.0-mysql php7.0-cli php7.0-curl php7.0-mcrypt
  • 配置 php7.0-fpm

更改配置文件 /etc/php/7.0/fpm/php.inicgi.fix_pathinfo 的值为 0,然后,重启 php7-fpm 服务。

  • 配置 Nginx

location ~ \.php$ { fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; fastcgi_index index.php; include fastcgi_params; }