微信小程序 BASE64 encode 加密 decode 解密

utils/base64.js

var Base64 = {
  // private property
  _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  // public method for encoding
  encode: function(input) {
    var output = "";
    var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
    var i = 0;
    input = Base64._utf8_encode(input);

    while (i < input.length) {

      chr1 = input.charCodeAt(i++);
      chr2 = input.charCodeAt(i++);
      chr3 = input.charCodeAt(i++);

      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;

      if (isNaN(chr2)) {
        enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
        enc4 = 64;
      }

      output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

    }

    return output;
  },

  // public method for decoding
  decode: function(input) {
    var output = "";
    var chr1, chr2, chr3;
    var enc1, enc2, enc3, enc4;
    var i = 0;

    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

    while (i < input.length) {

      enc1 = this._keyStr.indexOf(input.charAt(i++));
      enc2 = this._keyStr.indexOf(input.charAt(i++));
      enc3 = this._keyStr.indexOf(input.charAt(i++));
      enc4 = this._keyStr.indexOf(input.charAt(i++));

      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;

      output = output + String.fromCharCode(chr1);

      if (enc3 != 64) {
        output = output + String.fromCharCode(chr2);
      }
      if (enc4 != 64) {
        output = output + String.fromCharCode(chr3);
      }

    }

    output = Base64._utf8_decode(output);

    return output;
  },

  // private method for UTF-8 encoding
  _utf8_encode: function(string) {
    string = string.replace(/\r\n/g, "\n");
    var utftext = "";

    for (var n = 0; n < string.length; n++) {

      var c = string.charCodeAt(n);

      if (c < 128) {
        utftext += String.fromCharCode(c);
      } else if ((c > 127) && (c < 2048)) {
        utftext += String.fromCharCode((c >> 6) | 192);
        utftext += String.fromCharCode((c & 63) | 128);
      } else {
        utftext += String.fromCharCode((c >> 12) | 224);
        utftext += String.fromCharCode(((c >> 6) & 63) | 128);
        utftext += String.fromCharCode((c & 63) | 128);
      }

    }

    return utftext;
  },

  // private method for UTF-8 decoding
  _utf8_decode: function(utftext) {
    var string = "";
    var i = 0;
    var c = 0;
    var c1 = 0;
    var c2 = 0;

    while (i < utftext.length) {

      c = utftext.charCodeAt(i);

      if (c < 128) {
        string += String.fromCharCode(c);
        i++;
      } else if ((c > 191) && (c < 224)) {
        c2 = utftext.charCodeAt(i + 1);
        string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
        i += 2;
      } else {
        c2 = utftext.charCodeAt(i + 1);
        c3 = utftext.charCodeAt(i + 2);
        string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
        i += 3;
      }

    }

    return string;
  }
}

module.exports = Base64

使用 引包

const base64 = require(‘base64.js’)

微信小程序 封装 httpPost 方法 发送 PHPSESSID 保持登录连接

utils/config.js

var config = {
  APPID:'wxe1af0e00000000f3',
  BASE_URL:'https://xx.xxx.xx/xx/',
}
module.exports = config

utils/util.js 文件

var config = require('config.js')
function Post(url, data, cb,header=null) {

  if(header = 'session'){
    var headerObj = {
      'content-type': 'application/x-www-form-urlencoded',
      'Cookie': 'PHPSESSID=' + wx.getStorageSync('sessionid')
    }
  }else{
    var headerObj = {
      'content-type': 'application/x-www-form-urlencoded'
    }
  }
  wx.request({
    method: 'POST',
    url: config.BASE_URL + url,
    data: data,
    header: headerObj,
    success: (res) => {
      console.log("post 请求:" + config.BASE_URL + url);
      console.log(res.data)
      typeof cb == "function" && cb(res.data, "");
    },
    fail: (err) => {
      typeof cb == "function" && cb(null, err.errMsg)
      console.log("post 请求:" + config.BASE_URL + url);
      console.log(err);
    }
  })
} 
module.exports = {
  httpPost: Post,
}

使用 如 /pages/index.js

const util = require('../../utils/util.js')
test: function() {
	util.httpPost('index.php?s=/sign/gettimeplan',{'userid':805},function(res){
		console.log(res.result[0])
	},'session')
}

Swoole 绑定域名 80 端口 (Nginx 监听转发)

启动 Swoole 的 http server,可以使用 IP + 端口 进行访问

创建 Nginx 虚拟域名

vim swotp.liuguofeng.com.conf
server
    {
        listen 80;
        server_name swotp.liuguofeng.com ;
        index index.html index.htm index.php default.html default.htm default.php;
        root  /home/wwwroot/swoole_thinkphp.liuguofeng.com;

        location / {
                if (!-e $request_filename) {
                proxy_pass http://127.0.0.1:8811;
                }
        }
    }

重启 Nginx,DNS 指向 IP 

微信小程序 使用自带 rich-text 组件进行 HTML 富文本解析

JS

Page({

  /**
   * 页面的初始数据
   */
  data: {
    html: '<div class="div_class" style="line-height: 60px; color: red;">Hello World!</div><img src="/resource/test/test.jpg" style="width:200px;height:200px;"/>',    
  },
})

WXML

<rich-text nodes="{{html}}" data-data="{{html}}" bindtap="tap"></rich-text>

开发文档:

https://developers.weixin.qq.com/miniprogram/dev/component/rich-text.html

微信小程序 使用 wxParse HTML 富文本解析

下载地址 https://github.com/icindy/wxParse

将 wxParse 拷贝到项目目录下,本人拷至 /utils下,见引用

JS

const WxParse = require('../../utils/wxParse/wxParse.js')
Page({

  /**
   * 页面的初始数据
   */
  data: {
    
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.htmlTest()    
  },
  htmlTest:function(){
    var article = "<div>我是HTML代码</div><img src='/resource/test/test.jpg'/>"
    var that = this
    WxParse.wxParse('article', 'html', article, that, 5)
  },
})

WXML

<import src='../../utils/wxParse/wxParse.wxml' />
<template is="wxParse" data="{{wxParseData:article.nodes}}" />

WXSS

@import "/utils/wxParse/wxParse.wxss";

Linux 下 ThinkPHP 与 Swoole 搭配 ThinkPHP 性能对比测试

ThinkPHP 5.0.21

Server Software:        nginx
Server Hostname:        127.0.0.1
Server Port:            8080

Document Path:          /
Document Length:        39 bytes

Concurrency Level:      10
Time taken for tests:   9.064 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      218000 bytes
HTML transferred:       39000 bytes
Requests per second:    110.33 [#/sec] (mean)
Time per request:       90.637 [ms] (mean)
Time per request:       9.064 [ms] (mean, across all concurrent requests)
Transfer rate:          23.49 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       1
Processing:    15   90  37.8     87     217
Waiting:       15   90  37.8     87     217
Total:         15   90  37.8     88     217

Swoole 搭配 ThinkPHP 5.0.21

Server Software:        swoole-http-server
Server Hostname:        127.0.0.1
Server Port:            9501

Document Path:          /
Document Length:        39 bytes

Concurrency Level:      10
Time taken for tests:   4.355 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      1870000 bytes
HTML transferred:       390000 bytes
Requests per second:    2296.38 [#/sec] (mean)
Time per request:       4.355 [ms] (mean)
Time per request:       0.435 [ms] (mean, across all concurrent requests)
Transfer rate:          419.36 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       6
Processing:     1    4   3.7      4     166
Waiting:        0    4   3.6      3     166
Total:          1    4   3.7      4     166

配置信息

安装 PHP memcache memcached

安装 memcached

yum install memcached

需要 libevent 库,如未装则运行如下

yum install libevent libevent-devel

安装 php memcache 扩展

PHP memcache

http://pecl.php.net/package/memcache

PHP memcached

http://pecl.php.net/package/memcached
wget http://pecl.php.net/get/memcache-3.0.8.tgz
tar zxvf memcache-3.0.8.tgz
cd memcache-3.0.8
/usr/local/php5/bin/phpize
./configure --with-php-config=/usr/local/php5/bin/php-config
make
make install

php.ini 中加入扩展 extension=memcache.so

vim /usr/local/php5/lib/php.ini

重启 php-fpm,查看 phpinfo 

开机启动 (更改端口号如 11811)(如果使用 yum 方式安装,默认自启动)

vim /etc/sysconfig/memcached
PORT="11811"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS=""

编译方式安装的,在 /etc/rc.d/rc.local 中加入 (先 which memcached)

/usr/local/bin/memcached -u www -d -p 11811 -P /tmp/memcached.pid

或者创建 /etc/init.d/memcached

#!/bin/sh 
# 
# memcached:    MemCached Daemon 
# 
# chkconfig:    - 90 25
# description:  MemCached Daemon 
# 
# Source function library.
. /etc/rc.d/init.d/functions 
. /etc/sysconfig/network 
#[ ${NETWORKING} = "no" ] && exit 0
#[ -r /etc/sysconfig/dund ] || exit 0
#. /etc/sysconfig/dund 
#[ -z "$DUNDARGS" ] && exit 0
MEMCACHED="/usr/bin/memcached"
SERVER_IP="127.0.0.1"
SERVER_PORT="11811"
[ -f $MEMCACHED ] || exit 1
start() 
{ 
        echo -n $"Starting memcached: "
        daemon $MEMCACHED -u daemon -d -m 2048 -l $SERVER_IP -p $SERVER_PORT -P /tmp/memcached.pid
        echo 
} 
stop() 
{ 
        echo -n $"Shutting down memcached: "
        killproc memcached 
        echo 
}
  
# See how we were called. 
case "$1" in 
  start) 
        start 
        ;; 
  stop) 
        stop 
        ;; 
  restart) 
        stop 
        sleep 3
        start 
        ;; 
    *) 
        echo $"Usage: $0 {start|stop|restart}"
        exit 1
esac 
exit 0
#  chmod 755 /etc/init.d/memcached
#  chkconfig --add memcached
#  chkconfig memcached on
#  service memcached start
#  chkconfig --list memcached  #查看是否设置成功

启动

memcached -u root -d -p 11811

微信小程序 写一个 多级通讯录

无限级通讯录

WXML

<view class='title-container'>
  <view class="title" wx:for="{{branchTitle}}" wx:key="key" wx:for-index="index" wx:for-item="item" bindtap='toPre' data-level="{{item.level}}">
    <block wx:if="{{index==0}}">
      <text>{{item.title}}</text>
    </block>
    <block wx:else>
      <image class='next-icon' mode='aspectFit' src='/resource/cal/next.png'></image>
      <text>{{item.title}}</text>
    </block>
  </view>
</view>
<view class='address-container'>
  <view class='address-list' wx:for="{{address}}" wx:key="keyL" wx:for-index="indexL" wx:for-item="itemL">
    <block wx:if="{{itemL.type == 'branch'}}">
      <view class='address-one' bindtap='toId' data-id="{{itemL.id}}">
        <view class='left' style='background-color:red'>
          <view>{{itemL.name_slice}}</view>
        </view>
        <view class='right'>
          <view class='name-container'>
            <text class='name'>{{itemL.name}}</text>
          </view>
        </view>
      </view>
    </block>
    <block wx:elif="{{itemL.type == 'people'}}">
      <view class='address-one'>
        <view class='left'>
          <view>{{itemL.name_slice}}</view>
        </view>
        <view class='right'>
          <view class='name-container'>
            <text class='name'>{{itemL.name}}</text>
            <text class='job'>{{itemL.job}}</text>
          </view>
          <view class='tel-container'>
            <text class='tel'>{{itemL.tel}}</text>
          </view>
        </view>
      </view>
    </block>
  </view>
</view>

JS

// pages/addressbook/addressbook.js
const util = require('../../utils/util.js')
Page({

  /**
   * 页面的初始数据
   */
  data: {
    address: [],
    branchTitle: [{
      'level': 0,
      'title': '总部'
    }],
    level: 0,
  },

  toId: function (e) {
    console.log(e)
    var id = e.currentTarget.dataset.id

    var address = this.id2Detail(id)
    var title = this.id2Title(id)

    var oldBranchTitle = this.data.branchTitle
    var length = oldBranchTitle.length

    var branchTitle = oldBranchTitle
    branchTitle = branchTitle.concat([{
      'level': length + 1,
      'title': title
    }])

    var obj = {
      'address': JSON.stringify(address),
      'branchTitle': JSON.stringify(branchTitle)
    }

    var str = util.obj2Query(obj)
    wx.navigateTo({
      url: '/pages/addressbook/addressbook?' + str,
    })
    console.log(address)
  },
  toPre: function (e) {
    var level = e.currentTarget.dataset.level
    var currentLevel = this.data.level
    console.log(currentLevel)
    console.log('currentLevel - level = ' + currentLevel + '-' + level + '=' + (currentLevel - level))
    if (currentLevel - level != 0) {
      wx.navigateBack({
        delta: currentLevel - level
      })
    }

  },
  addressFormat: function (address = []) {
    var i
    for (i in address) {
      if (address[i].type == 'branch') {
        address[i]['name_slice'] = address[i].name.substr(0, 2)
      } else if (address[i].type == 'people') {
        address[i]['name_slice'] = address[i].name.substr(address[i].name.length - 2, 2)
      }
    }
    return address
  },
  id2Title: function (id) {
    var address = this.data.address
    var i
    for (i in address) {
      if (address[i].id == id) {
        return address[i].name
      }
    }
  },

  id2Detail: function (id) {
    var address = this.data.address
    var i
    for (i in address) {
      if (address[i].id == id) {
        return address[i].subclass
      }
    }
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log('onLoad')
    console.log(options)
    if (options.hasOwnProperty('address')) {
      var address = JSON.parse(options.address)
      var branchTitle = JSON.parse(options.branchTitle)
      var level = branchTitle[branchTitle.length - 1].level
      address = this.addressFormat(address)
      this.setData({
        address: address,
        branchTitle: branchTitle,
        level: level
      })
    } else {
      this.init()
    }
  },
  init: function () {
    var address = [{
      'id': 1,
      'name': '总经办',
      'type': 'branch',
      'subclass': [{
        'id': 2,
        'type': 'people',
        'name': '张震岳',
        'job': '法务',
        'tel': '18888888888'
      },
      {
        'id': 3,
        'type': 'people',
        'name': '李宇春',
        'job': '法务',
        'tel': '18888888868'
      },
      ]
    },
    {
      'id': 4,
      'name': '人事行政部',
      'type': 'branch',
      'subclass': [{
        'id': 5,
        'type': 'people',
        'name': '佐助',
        'job': '人事总监',
        'tel': '1883333668'
      },
      {
        'id': 6,
        'type': 'people',
        'name': '鸣人',
        'job': '招聘主管',
        'tel': '1666688888'
      }
      ]
    },
    {
      'id': 8,
      'name': '运营部',
      'type': 'branch',
      'subclass': [{
        'id': 5,
        'type': 'people',
        'name': '易烊千玺',
        'job': '运营总监',
        'tel': '1883333668'
      },
      {
        'id': 6,
        'type': 'people',
        'name': '王源',
        'job': '总监助理',
        'tel': '1666688888'
      },
      {
        'id': 8,
        'name': '华北区',
        'type': 'branch',
        'subclass': [{
          'id': 8,
          'name': '北京芍药居',
          'type': 'branch',
          'subclass': [{
            'id': 5,
            'type': 'people',
            'name': '爱德华',
            'job': '人事总监',
            'tel': '1883333668'
          },
          {
            'id': 6,
            'type': 'people',
            'name': '阿尔冯思',
            'job': '招聘主管',
            'tel': '1666688888'
          }
          ]
        },
        {
          'id': 38,
          'name': '天津芥园道',
          'type': 'branch',
          'subclass': [{
            'id': 25,
            'type': 'people',
            'name': '若林源三',
            'job': '人事总监',
            'tel': '1883333668'
          },
          {
            'id': 6,
            'type': 'people',
            'name': '大空翼',
            'job': '招聘主管',
            'tel': '1666688888'
          }
          ]
        },
        {
          'id': 5,
          'type': 'people',
          'name': '郑少秋',
          'job': '华北区总监',
          'tel': '1883333668'
        },
        {
          'id': 6,
          'type': 'people',
          'name': '刘德华',
          'job': '华北区总监助理',
          'tel': '1666688888'
        }
        ]
      },
      {
        'id': 12,
        'name': '西南区',
        'type': 'branch',
        'subclass': [{
          'id': 18,
          'name': '昆明汇都店',
          'type': 'branch',
          'subclass': [{
            'id': 5,
            'type': 'people',
            'name': '邓紫棋',
            'job': '人事总监',
            'tel': '1883333668'
          },
          {
            'id': 6,
            'type': 'people',
            'name': '汪峰',
            'job': '招聘主管',
            'tel': '1666688888'
          }
          ]
        },
        {
          'id': 36,
          'name': '成都武侯祠',
          'type': 'branch',
          'subclass': [{
            'id': 5,
            'type': 'people',
            'name': '林俊杰',
            'job': '人事总监',
            'tel': '1883333668'
          },
          {
            'id': 6,
            'type': 'people',
            'name': '王菲',
            'job': '招聘主管',
            'tel': '1666688888'
          }
          ]
        },
        {
          'id': 5,
          'type': 'people',
          'name': '萨琳娜',
          'job': '人事总监',
          'tel': '1883333668'
        },
        {
          'id': 6,
          'type': 'people',
          'name': '田馥甄',
          'job': '招聘主管',
          'tel': '1666688888'
        }
        ]
      },
      ]
    },
    {
      'id': 7,
      'type': 'people',
      'name': '孙总',
      'job': '董事长',
      'tel': '16666666666'
    }
    ]
    address = this.addressFormat(address)
    this.setData({
      address: address
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    console.log('onshow')
    console.log(this.data.branchTitle)

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

WXSS

.title-container {
  padding: 30rpx 50rpx;
  font-size: 30rpx;
  background-color: #fefefe;
  box-shadow: 0 10rpx 10rpx #efefef;
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
}

.title {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
}

.next-icon {
  width: 20rpx;
  height: 20rpx;
  margin: 0 10rpx;
}

.address-container {
  margin-top: 20rpx;
  background-color: #fefefe;
}

.address-list {
  padding: 30rpx 50rpx;
}

.address-one {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  align-items: center;
}

.address-one .left {
  width: 90rpx;
  height: 90rpx;
  border-radius: 50%;
  background-color: #2396f2;
  color: #fff;
  font-size: 30rpx;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  margin-right: 20rpx;
}

.address-one .right {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-start;
  font-size: 30rpx;
}

.name {
  font-weight: 700;
  margin-right: 20rpx;
}

.job {
  color: #aaa;
  font-size: 26rpx;
}

.tel {
  color: #aaa;
  font-size: 26rpx;
}

.swiper-tab {
  width: 100%;
  border-bottom: 2rpx solid #ccc;
  text-align: center;
  height: 88rpx;
  line-height: 88rpx;
  font-weight: bold;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
}

.swiper-tab-item {
  display: inline-block;
  /* width: 33.33%; */
  width: inherit;
  color: red;
}

.active {
  color: aqua;
  border-bottom: 4rpx solid red;
}

util.js

const obj2Query = function (params = new Object()) {
  console.log('obj2Query 方法')
  var arr = Object.keys(params)
  if (arr.length == 0) {
    return ''
  }
  var str = ''
  for (var i in params) {
    str = str + '&' + i + '=' + params[i]
  }
  return str
}

module.exports = {
  obj2Query: obj2Query
}

MacOS 自带 PHP 执行 php-fpm 的问题及解决

MacOS 下执行 php-fpm 会报错

ERROR: failed to open configuration file '/private/etc/php-fpm.conf': No such file or directory (2)
ERROR: failed to load configuration file '/private/etc/php-fpm.conf'
ERROR: FPM initialization failed

不能打开配置文件,因为没有 php-fpm.conf 文件,复制 php-fpm.conf.default 文件,改名为 php-fpm.conf,然后再根据需要改动配置。

cp /private/etc/php-fpm.conf.default /private/etc/php-fpm.conf

在此执行 php-fpm

WARNING: Nothing matches the include pattern '/private/etc/php-fpm.d/*.conf' from /private/etc/php-fpm.conf at line 125.
ERROR: failed to open error_log (/usr/var/log/php-fpm.log): No such file or directory (2)
ERROR: failed to post process the configuration
ERROR: FPM initialization failed

WARNING 找不到配置文件夹

cd /private/etc/php-fpm.d 
sudo cp www.conf.default www.conf

ERROR 不能打开错误日志文件。因为没有这个目录,配置到 /usr/local/var/log 目录。

vim /private/etc/php-fpm.conf,将 error_log 配置为 /usr/local/var/log/php-fpm.log

再次执行 php-fpm 依然报错

NOTICE: [pool www] 'user' directive is ignored when FPM is not running as root
NOTICE: [pool www] 'group' directive is ignored when FPM is not running as root

sudo php-fpm,再次报错:

ERROR: unable to bind listening socket for address '127.0.0.1:9000': Address already in use (48)
ERROR: FPM initialization failed

编辑 www.conf,修改 listen 为 127.0.0.1:9999。

sudo vim /private/etc/php-fpm.d/www.conf

最后再次开启

开启php-fpm: sudo php-fpm -D

nginx 使用 php-fpm

nginx 配置文件

vim /usr/local/etc/nginx/nginx.conf
server {
    listen       8080;
    server_name  localhost;

    location / {
        root   /Users/guofeng/wwwroot/thinkphp/public;
        index  index.html index.htm index.php;
    }
    location ~ \.php$ {
        root /Users/guofeng/wwwroot/thinkphp/public;
        fastcgi_pass   127.0.0.1:9999;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
    }
}