对 Laravel 5.5 和 ThinkPHP 5.0.20 进行了 ab 压力测试

是不是我配置有问题?

Laravel 5.5 输出 echo ‘hello world’

Server Software:        nginx/1.11.5
Server Hostname:        laravel55.a.cc
Server Port:            80

Document Path:          /
Document Length:        11 bytes

Concurrency Level:      10
Time taken for tests:   36.029 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      101442 bytes
HTML transferred:       1100 bytes
Requests per second:    2.78 [#/sec] (mean)
Time per request:       3602.922 [ms] (mean)
Time per request:       360.292 [ms] (mean, across all concurrent requests)
Transfer rate:          2.75 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.4      0       1
Processing:   348 3458 724.6   3592    4386
Waiting:      348 3457 724.6   3592    4386
Total:        349 3458 724.6   3592    4386

ThinkPHP 5.0.20 输出 echo ‘hello world’

Server Software:        nginx/1.11.5
Server Hostname:        thinkphp50.a.cc
Server Port:            80

Document Path:          /
Document Length:        11 bytes

Concurrency Level:      10
Time taken for tests:   4.198 seconds
Complete requests:      100
Failed requests:        9
   (Connect: 0, Receive: 0, Length: 9, Exceptions: 0)
Non-2xx responses:      9
Total transferred:      20852 bytes
HTML transferred:       2558 bytes
Requests per second:    23.82 [#/sec] (mean)
Time per request:       419.839 [ms] (mean)
Time per request:       41.984 [ms] (mean, across all concurrent requests)
Transfer rate:          4.85 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.5      0       1
Processing:    64  401 123.5    401     604
Waiting:       64  401 123.6    401     604
Total:         64  402 123.5    402     604

电脑配置

使用 Apache 的 ab 工具进行 PHP WordPress 的压力测试

使用 Apache 的 ab 工具测试了下几个网站的并发

本机配置

本地测试 echo ‘hello world’

./ab -c10 -n1000 http://localhost/helloworld.php
Server Software:        nginx/1.11.5
Server Hostname:        wp.a.cc
Server Port:            80

Document Path:          /helloworld.php
Document Length:        25 bytes

Concurrency Level:      10
Time taken for tests:   1.041 seconds
Complete requests:      1000
Failed requests:        12
   (Connect: 0, Receive: 0, Length: 12, Exceptions: 0)
Non-2xx responses:      1000
Total transferred:      219284 bytes
HTML transferred:       26776 bytes
Requests per second:    960.29 [#/sec] (mean)
Time per request:       10.414 [ms] (mean)
Time per request:       1.041 [ms] (mean, across all concurrent requests)
Transfer rate:          205.64 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.4      0       1
Processing:     2   10   4.7      9      22
Waiting:        2   10   4.6      8      22
Total:          3   10   4.7      9      22

测试 phpinfo()

./ab -c10 -n1000 http://localhost/phpinfo.php
Server Software:        nginx/1.11.5
Server Hostname:        wp.a.cc
Server Port:            80

Document Path:          /phpinfo.php
Document Length:        98215 bytes

Concurrency Level:      10
Time taken for tests:   4.408 seconds
Complete requests:      1000
Failed requests:        107
   (Connect: 0, Receive: 0, Length: 107, Exceptions: 0)
Non-2xx responses:      17
Total transferred:      96733608 bytes
HTML transferred:       96548186 bytes
Requests per second:    226.85 [#/sec] (mean)
Time per request:       44.083 [ms] (mean)
Time per request:       4.408 [ms] (mean, across all concurrent requests)
Transfer rate:          21429.39 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.4      0       1
Processing:    10   44   8.9     43      78
Waiting:        9   43   8.9     42      78
Total:         10   44   8.9     43      78

测试新装 WordPress

./ab -c10 -n100 http://localhost/wordpress/
Server Software:        nginx/1.11.5
Server Hostname:        wp.a.cc
Server Port:            80

Document Path:          /wordpress/
Document Length:        52976 bytes

Concurrency Level:      10
Time taken for tests:   45.738 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      5323100 bytes
HTML transferred:       5297600 bytes
Requests per second:    2.19 [#/sec] (mean)
Time per request:       4573.759 [ms] (mean)
Time per request:       457.376 [ms] (mean, across all concurrent requests)
Transfer rate:          113.66 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.5      0       1
Processing:   447 4366 790.2   4507    5239
Waiting:      446 4366 790.2   4507    5239
Total:        447 4367 790.2   4507    5240

WordPress 安装 WP Super Cache 缓存插件

./ab -c10 -n100 http://localhost/wordpress/
Server Software:        nginx/1.11.5
Server Hostname:        wp.a.cc
Server Port:            80

Document Path:          /wordpress/
Document Length:        53120 bytes

Concurrency Level:      10
Time taken for tests:   2.721 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      5338000 bytes
HTML transferred:       5312000 bytes
Requests per second:    36.75 [#/sec] (mean)
Time per request:       272.131 [ms] (mean)
Time per request:       27.213 [ms] (mean, across all concurrent requests)
Transfer rate:          1915.58 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.4      0       1
Processing:    32  260  47.2    268     328
Waiting:       32  260  47.2    268     328
Total:         32  261  47.2    269     328

PHP 多版本共存 PHP5.6 PHP7.2

先安装 php7,正常安装

php7.2 安装完成后,进行 php5.6 的安装

安装 php5

[root@VM_0_2_centos ~]# cd ~
[root@VM_0_2_centos ~]# wget -c http://cn2.php.net/distributions/php-5.6.30.tar.gz
[root@VM_0_2_centos ~]# tar -zxvf php-5.6.30.tar.gz
[root@VM_0_2_centos ~]# cd php-5.6.30/
[root@VM_0_2_centos php-5.6.30]# ./configure  --prefix=/usr/local/php5 --enable-fpm --with-mysql  --with-mysqli --with-zlib --with-curl --with-gd --with-jpeg-dir --with-png-dir --with-freetype-dir --with-openssl --enable-mbstring --enable-xml --enable-session --enable-ftp --enable-pdo
[root@VM_0_2_centos php-5.6.30]# make

make 可能会报错:make: *** [sapi/cli/php] error 1 ,

则使用

[root@VM_0_2_centos php-5.6.30]# make clean
[root@VM_0_2_centos php-5.6.30]# make ZEND_EXTRA_LIBS='-liconv'

安装

[root@VM_0_2_centos php-5.6.30]# make install

复制 php 配置文件

[root@VM_0_2_centos php-5.6.30]# cp php.ini-production /usr/local/php5/etc/php.ini

已经安装完成,查看版本号

[root@VM_0_2_centos php-5.6.30]# /usr/local/php5/bin/php -v

返回

PHP 5.6.30 (cli) (built: Aug 29 2018 09:09:28) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

配置 php-fpm

[root@VM_0_2_centos php-5.6.30]# cp /usr/local/php5/etc/php-fpm.conf.default /usr/local/php5/etc/php-fpm.conf
[root@VM_0_2_centos php-5.6.30]# vim /usr/local/php5/etc/php-fpm.conf

查找 user 将

user = nobody
group = nobody

改成

user = www
group = www

查找 listen 将

listen = 127.0.0.1:9000

改成

listen = 127.0.0.1:9001

配置 php-fpm 服务

[root@VM_0_2_centos php-5.6.30]# cp sapi/fpm/php-fpm.service /usr/lib/systemd/system/php5-fpm.service
[root@VM_0_2_centos php-5.6.30]# vim /usr/lib/systemd/system/php5-fpm.service 

将:

PIDFile=${prefix}/var/run/php-fpm.pid
ExecStart=${exec_prefix}/sbin/php-fpm --nodaemonize --fpm-config ${prefix}/etc/php-fpm.conf

改成

PIDFile=/usr/local/php5/var/run/php-fpm.pid
ExecStart=/usr/local/php5/sbin/php-fpm --nodaemonize --fpm-config /usr/local/php5/etc/php-fpm.conf

重新载入 systemd

[root@VM_0_2_centos php-5.6.30]# systemctl daemon-reload

可以设置开机启动:

[root@VM_0_2_centos php-5.6.30]# systemctl enable php5-fpm

返回结果

Created symlink from /etc/systemd/system/multi-user.target.wants/php5-fpm.service to /usr/lib/systemd/system/php5-fpm.service.

启动:

[root@VM_0_2_centos php-5.6.30]# systemctl start php5-fpm

关闭:

[root@VM_0_2_centos php-5.6.30]# systemctl stop php5-fpm

查看状态:

[root@VM_0_2_centos php-5.6.30]# systemctl status php5-fpm

返回

● php5-fpm.service - The PHP FastCGI Process Manager
   Loaded: loaded (/usr/lib/systemd/system/php5-fpm.service; disabled; vendor preset: disabled)
   Active: active (running) since Wed 2018-08-29 09:36:39 CST; 47s ago
 Main PID: 14996 (php-fpm)
   CGroup: /system.slice/php5-fpm.service
           ├─14996 php-fpm: master process (/usr/local/php5/etc/php-fpm.conf)
           ├─14997 php-fpm: pool www
           └─14998 php-fpm: pool www

配置不同的 nginx 站点使用不用的 PHP 版本

[root@VM_0_2_centos php-5.6.30]# cd /usr/local/nginx/conf/vhost/
[root@VM_0_2_centos vhost]# vim test.liuguofeng.com.conf 
server {
    listen       80;
    server_name  test.liuguofeng.com;
    root         /home/wwwroot/test.liuguofeng.com
    location / {
        index  index.php index.html index.htm;
    }
    location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9001;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}

PHP 5 使用 9001 端口, PHP 7,使用 9000端口。

重载 nginx 服务

[root@lnmp conf.d]# systemctl reload nginx

访问 PHPINFO

PHP url 缺少 www 自动补全 www 函数

稍后继续优化

<?php
function addWww($url){
	$parse = parse_url($url);

	$scheme = isset($parse['scheme'])?$parse['scheme']:'';
	$host = isset($parse['host'])?$parse['host']:'';
	$path = isset($parse['path'])?$parse['path']:'';
	$query = isset($parse['query'])?$parse['query']:'';
	$fragment = isset($parse['fragment'])?$parse['fragment']:'';

	preg_match('/^(([www]{3})|([\w]{1,}))[\.][\w]*?[\.][com|cn|com.cn|cc|net]{2,}/',$host,$match);

	if($match){
		$resUrl = $url;
	}else{
		$resUrl = $scheme.'://'.'www.'.$host.$path.'?'.$query.'#'.$fragment;
	}
	return $resUrl;
}

PHP 二维数组按照某个键值重新排序

需求:可预订排在前,不可预订排在后,即对既有数据进行重新排序,数据为二维数组,问题转换为根据二维数组的某 key 的值对二维数组进行重排

最开始使用 二维数组降为一维数组,使用 asort/arsort 进行排序,排序完成后根据一维数组的位置替换成二维数组

结果是可以重拍,但问题是对 value 值相同的数据也会打乱重排。

第二种方法使用冒泡排序,也是用二维数组降为一维数组,使用冒泡排序重拍一维,再根据一维的序号替换成二维数组

结果不可重拍,因为冒泡只替换了 value 的位置,key 的位置并没有重拍。常规的冒泡仅是解决索引数组的排序,若想用冒泡的方式,需要对关联数组进行冒泡

第三种方法使用 array_multisort() 函数

array_multisort() 函数对多个数组或多维数组进行排序。
参数中的数组被当成一个表的列并以行来进行排序 – 这类似 SQL 的 ORDER BY 子句的功能。第一个数组是要排序的主要数组。数组中的行(值)比较为相同的话,就会按照下一个输入数组中相应值的大小进行排序,依此类推。

/**数组根据某一value值进行排序
 * @param $arr 二维数组
 * @param $keys 指定按哪列排序
 * @param string $order_by 正序 or 倒叙
 * @param bool $key 原 key 是否保留
 * @param string $way 排序方法
 * @return array 二维数组
 */
private function array_sort($arr,$keys,$order_by='desc',$key=FALSE,$way='bubble'){
  $tmp_array = $new_array = array();
  foreach($arr as $k=>$v){
    $tmp_array[$k] = $v[$keys];
  }

  if($way == 'sort'){
    //sort 方法排序,可以重拍,但是相同值的顺序会被打乱
    if($order_by =='asc'){
      asort($tmp_array);
    }else{
      arsort($tmp_array);
    }
  }elseif($way == 'bubble'){
    //冒泡排序,不能重拍
    if($order_by == 'desc') {
      for ($i = 0; $i < count($tmp_array) - 1; $i++) {
        for ($j = 0; $j < count($tmp_array) - $i - 1; $j++){
          if ($tmp_array[$j]<$tmp_array[$j+1]) {
            $t = $tmp_array[$j];
            $tmp_array[$j] = $tmp_array[$j+1];
            $tmp_array[$j+1] = $t;
          }
        }
      }
    }elseif($order_by == 'asc'){
      for ($i = 0; $i < count($tmp_array) - 1; $i++) {
        for ($j = 0; $j < count($tmp_array) - $i - 1; $j++){
          if ($tmp_array[$j]>$tmp_array[$j+1]) {
            $t = $tmp_array[$j];
            $tmp_array[$j] = $tmp_array[$j+1];
            $tmp_array[$j+1] = $t;
          }
        }
      }
    }
  }elseif($way == 'multisort'){
    //multisort 方法排序,相同值的顺序按顺序输出
    if($order_by == 'desc'){
      array_multisort(array_column($arr,$keys),SORT_DESC,$arr);
      $tmp_array = $arr;
    }elseif($order_by == 'asc'){
      array_multisort(array_column($arr,$keys),SORT_ASC,$arr);
      $tmp_array = $arr;
    }
  }

  reset($tmp_array);
  foreach($tmp_array as $k=>$v){
    if($key==TRUE){
      $new_array[$k] = $arr[$k];
    }else{
      $new_array[] = $arr[$k];
    }
  }
  return $new_array;
}

 

PHP 实现无限极分类生成分类树的方法

<?php

$data = array (
  array (
    'id' => 4,
    'category_name' => '要闻',
    'pid' => 3,
    'created_at' => '2018-06-21 17:33:55',
    'updated_at' => '2018-06-21 17:33:55',
  ),
  array (
    'id' => 3,
    'category_name' => '新闻',
    'pid' => 0,
    'created_at' => '2018-06-21 17:33:45',
    'updated_at' => '2018-06-21 17:33:45',
  ),
  array (
    'id' => 5,
    'category_name' => '企业服务',
    'pid' => 3,
    'created_at' => '2018-06-21 17:34:12',
    'updated_at' => '2018-06-21 17:34:12',
  ),
  array (
    'id' => 6,
    'category_name' => '大新闻',
    'pid' => 0,
    'created_at' => '2018-06-26 14:41:28',
    'updated_at' => '2018-06-26 14:41:28',
  ),
  array (
    'id' => 7,
    'category_name' => '优惠',
    'pid' => 6,
    'created_at' => '2018-06-26 14:41:45',
    'updated_at' => '2018-06-26 14:41:45',
  ),
);
echo "<pre>";
//var_export($data);



function getTree($list,$pid=0,$level=0) {
  static $tree = array();
  foreach($list as $row) {
    if($row['parentID']==$pid) {
      $row['level'] = $level;
      $tree[] = $row;
      getTree($list, $row['id'], $level + 1);
    }
  }
  return $tree;
}

function makeTree($arr){
  $refer = array();
  $tree = array();
  foreach($arr as $k => $v){
    $refer[$v['id']] = & $arr[$k]; //创建主键的数组引用
  }
  foreach($arr as $k => $v){
    $pid = $v['pid'];  //获取当前分类的父级id
    if($pid == 0){
      $tree[] = & $arr[$k];  //顶级栏目
    }else{
      if(isset($refer[$pid])){
        $refer[$pid]['subcat'][] = & $arr[$k]; //如果存在父级栏目,则添加进父级栏目的子栏目数组中
      }
    }
  }
  return $tree;
}


$a = makeTree($data);
print_r($a);

$b = getTree($data);
print_r($b);

输出:

Array
(
    [0] => Array
        (
            [id] => 3
            [category_name] => 新闻
            [pid] => 0
            [created_at] => 2018-06-21 17:33:45
            [updated_at] => 2018-06-21 17:33:45
            [subcat] => Array
                (
                    [0] => Array
                        (
                            [id] => 4
                            [category_name] => 要闻
                            [pid] => 3
                            [created_at] => 2018-06-21 17:33:55
                            [updated_at] => 2018-06-21 17:33:55
                        )

                    [1] => Array
                        (
                            [id] => 5
                            [category_name] => 企业服务
                            [pid] => 3
                            [created_at] => 2018-06-21 17:34:12
                            [updated_at] => 2018-06-21 17:34:12
                        )

                )

        )

    [1] => Array
        (
            [id] => 6
            [category_name] => 大新闻
            [pid] => 0
            [created_at] => 2018-06-26 14:41:28
            [updated_at] => 2018-06-26 14:41:28
            [subcat] => Array
                (
                    [0] => Array
                        (
                            [id] => 7
                            [category_name] => 优惠
                            [pid] => 6
                            [created_at] => 2018-06-26 14:41:45
                            [updated_at] => 2018-06-26 14:41:45
                        )

                )

        )

)
Array
(
    [0] => Array
        (
            [id] => 4
            [category_name] => 要闻
            [pid] => 3
            [created_at] => 2018-06-21 17:33:55
            [updated_at] => 2018-06-21 17:33:55
            [level] => 0
        )

    [1] => Array
        (
            [id] => 3
            [category_name] => 新闻
            [pid] => 0
            [created_at] => 2018-06-21 17:33:45
            [updated_at] => 2018-06-21 17:33:45
            [level] => 0
        )

    [2] => Array
        (
            [id] => 5
            [category_name] => 企业服务
            [pid] => 3
            [created_at] => 2018-06-21 17:34:12
            [updated_at] => 2018-06-21 17:34:12
            [level] => 0
        )

    [3] => Array
        (
            [id] => 6
            [category_name] => 大新闻
            [pid] => 0
            [created_at] => 2018-06-26 14:41:28
            [updated_at] => 2018-06-26 14:41:28
            [level] => 0
        )

    [4] => Array
        (
            [id] => 7
            [category_name] => 优惠
            [pid] => 6
            [created_at] => 2018-06-26 14:41:45
            [updated_at] => 2018-06-26 14:41:45
            [level] => 0
        )

)

 

微信小程序地图服务使用 百度坐标系经纬度 方法 百度坐标系转 GCJ02

微信小程序使用 百度地图提供的坐标进行定位的时候会造成位置偏移,究其原因是百度地图未使用常规的国测局坐标(火星坐标,GCJ02)、或WGS84坐标系 而使用了自己的坐标系 百度坐标系

会造成经纬度上的一公里左右的偏移。

但百度只提供 WGS84、GCJ02 坐标系转百度坐标系的接口,而未提供百度坐标系转 WGS84、GCJ02坐标系

互联网在线地图使用的坐标系:

火星坐标系:

  • iOS 地图(其实是高德)
  • Gogole地图
  • 搜搜、阿里云、高德地图

百度坐标系:

  • 当然只有百度地图

WGS84坐标系:

  • 国际标准,谷歌国外地图、osm地图等国外的地图一般都是这个

微信小程序使用百度坐标系经纬度的解决方式:

腾讯位置服务提供了 微信小程序 JavaScript SDK,可进行其他坐标系的逆向解析,包含以下坐标系转换至腾讯坐标系:

  • GPS坐标
  • sogou经纬度
  • baidu经纬度
  • mapbar经纬度
  • [默认]腾讯、google、高德坐标
  • sogou墨卡托

接口文档: http://lbs.qq.com/qqmap_wx_jssdk/method-reverseGeocoder.html

PHP 自定义函数 记录错误 / LOG日志到文件

public function log($res){
    $err_date = date("Ym", time());
    $address = '/error';
    if (!is_dir($address)) {
        mkdir($address, 0700, true);
    }
    $address = $address.'/'.$err_date . '_error.log';
    $error_date = date("Y-m-d H:i:s", time());
    if(!empty($_SERVER['HTTP_REFERER'])) {
        $file = $_SERVER['HTTP_REFERER'];
    } else {
        $file = $_SERVER['REQUEST_URI'];
    }
    if(is_array($res)) {
        $res_real = "$error_date\t$file\n";
        error_log($res_real, 3, $address);
        $res = var_export($res,true);
        $res = $res."\n";
        error_log($res, 3, $address);
    } else {
        $res_real = "$error_date\t$file\t$res\n";
        error_log($res_real, 3, $address);
    }
}

 

微信小程序支付完成后回调通知数据 记录

<xml><appid><![CDATA[wxf2e83f1160dfcxxx]]></appid><bank_type><![CDATA[ICBC_DEBIT]]></bank_type>/<cash_fee><![CDATA[1]]></cash_fee>/<fee_type><![CDATA[CNY]]></fee_type>/<is_subscribe><![CDATA[N]]></is_subscribe>/<mch_id><![CDATA[130xxx8601]]></mch_id>/<nonce_str><![CDATA[LhpVcEPpTNASOaQysNFNlYLrpMgyWDLa]]></nonce_str>/<openid><![CDATA[oC7xr5TZehbHbe__UUNPJzDapxxx]]></openid>/<out_trade_no><![CDATA[1528360591]]></out_trade_no>/<result_code><![CDATA[SUCCESS]]></result_code>/<return_code><![CDATA[SUCCESS]]></return_code>/<sign><![CDATA[766868113312ED3C141BF3D3487D1BDF]]></sign>/<time_end><![CDATA[20180607163654]]></time_end>/<total_fee>1</total_fee>/<trade_type><![CDATA[JSAPI]]></trade_type>/<transaction_id><![CDATA[4200000123201806075922186660]]></transaction_id>/</xml>

{"appid":"wxf2e83f1160dfcxxx","bank_type":"ICBC_DEBIT","cash_fee":"1","fee_type":"CNY","is_subscribe":"N","mch_id":"130xxx8601","nonce_str":"yHbHrfbyDnWvRuogoOLWffsuFEXhDBeT","openid":"oC7xr5TZehbHbe__UUNPJzDapxxx","out_trade_no":"1528361071","result_code":"SUCCESS","return_code":"SUCCESS","sign":"364C903E8668AE6B49A1EE2B7A217D97","time_end":"20180607164442","total_fee":"1","trade_type":"JSAPI","transaction_id":"4200000126201806078162413986"}

接收并处理

$data['postStr']=isset($GLOBALS['HTTP_RAW_POST_DATA']) ? $GLOBALS['HTTP_RAW_POST_DATA'] : file_get_contents("php://input");
$postdata = json_decode(json_encode(simplexml_load_string($data['postStr'], 'SimpleXMLElement', LIBXML_NOCDATA)), true);

JSON格式化

{
    "appid": "wxf2e83f1160dfcxxx",
    "bank_type": "ICBC_DEBIT",
    "cash_fee": "1",
    "fee_type": "CNY",
    "is_subscribe": "N",
    "mch_id": "130xxx8601",
    "nonce_str": "yHbHrfbyDnWvRuogoOLWffsuFEXhDBeT",
    "openid": "oC7xr5TZehbHbe__UUNPJzDapxxx",
    "out_trade_no": "1528361071",
    "result_code": "SUCCESS",
    "return_code": "SUCCESS",
    "sign": "364C903E8668AE6B49A1EE2B7A217D97",
    "time_end": "20180607164442",
    "total_fee": "1",
    "trade_type": "JSAPI",
    "transaction_id": "4200000126201806078162413986"
}

官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7&index=8