Write the Code. Change the World.

分类目录
1月 09

laravel 好用, ant design pro 不仅好用还好看。那么,laravel + ant design pro 做出来的项目也会很好用,很好看。

创建初始化 laravel 项目以及 ant design pro 项目

先创建 laravel 项目

# 创建 最新版本的 laravel 项目,并且指定项目文件名为 lreact.com
composer create-project laravel/laravel=6.* --prefer-dist lreact.com

# 删除原本的 readme
rm -rf README.md

# 使用新的 readme,简洁
echo '### Laravel 6.* initialize' >> Readme.md

# 初始化 git 仓库
git init
git add .
git commit -m 'Laravel 6.* initialize'

再创建 ant design pro 项目

在 `laravel` 的 `resources` 目录下,新建文件夹 `antdesign`
cd resources

mkdir antdesign

npm create umi
# 依次选择 ant design pro -> javascript

# 当前版本 v4

git add .

git commit -m 'ant design pro v4 initialize'

npm install

安装完成后,需要稍微修改,并打包

部署请参考 https://pro.ant.design/docs/deploy-cn

# 修改输出目录(antdesign 目录下)
vim config/config.js

# 添加指定目录 base 以及 publicPath

export default {
  base: '/dashboard/',
  publicPath: '/dashboard/',
  plugins,
  hash: false,

# 编译
npm run build

# 将打包好的文件复制到 laravel 的 public 目录
mv dist ../../public/dashboard

# 访问站点
https://www.lrect.com/dashboard

能正常访问,但是授权登录错误。先到这来。

如果你不想每次都移来移去,可以在 config/config.js 里追加配置 outputPath
参考

于是,配置为

export default {
  base: '/dashboard/',
  publicPath: '/dashboard/',
  outputPath: '../../public/dashboard',
  plugins,
  hash: false,

再打包。文件就会打包到 laravel 项目下的 public 下的 dashboard 目录下。

修改 request

ant design pro 的请求都放在 services 下。在这里你可以定义和修改请求。但,这里的请求用的是 umi-request, 而这里对 umi-request 的引用放在 utils/request.js 中。这里你可以添加 header,加入拦截器等等。请看 umi-request 文档。

https://github.com/umijs/umi-request/blob/master/README_zh-CN.md

这里添加空的拦截器(request,response),还有添加请求前缀。完整的 request.js 如下。后边,会对拦截器进一步完善。

/**
 * request 网络请求工具
 * 更详细的 api 文档: https://github.com/umijs/umi-request
 */
import { extend } from 'umi-request';
import { notification } from 'antd';
const codeMessage = {
  200: '服务器成功返回请求的数据。',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队(异步任务)。',
  204: '删除数据成功。',
  400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
  401: '用户没有权限(令牌、用户名、密码错误)。',
  403: '用户得到授权,但是访问是被禁止的。',
  404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
  406: '请求的格式不可得。',
  410: '请求的资源被永久删除,且不会再得到的。',
  422: '当创建一个对象时,发生一个验证错误。',
  500: '服务器发生错误,请检查服务器。',
  502: '网关错误。',
  503: '服务不可用,服务器暂时过载或维护。',
  504: '网关超时。',
};
/**
 * 异常处理程序
 */

const errorHandler = error => {
  const { response } = error;

  if (response && response.status) {
    const errorText = codeMessage[response.status] || response.statusText;
    const { status, url } = response;
    notification.error({
      message: `请求错误 ${status}: ${url}`,
      description: errorText,
    });
  } else if (!response) {
    notification.error({
      description: '您的网络发生异常,无法连接服务器',
      message: '网络异常',
    });
  }

  return response;
};

/**
 * 配置request请求时的默认参数
 */
const request = extend({
  prefix: '/dashboard',
  errorHandler,
  // 默认错误处理
  credentials: 'include', // 默认请求是否带上cookie
});

// request拦截器, 改变url 或 options.
request.interceptors.request.use(async (url, options) => {
  const headers = {
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  };

  return (
    {
      url: url,
      options: { ...options, headers: headers },
    }
  );
})

// response拦截器, 处理response
request.interceptors.response.use((response, options) => {
  return response;
});

export default request;

到目前为止,输出目录,接口前缀,都是手动写的。分别写在了三个地方。如果想修改,必须得每个地方改一次。如果定义一个常量,直接使用常量不就好了么。下边进行常量定义。不过,定义了常量,那就必须保证你的需求里这三个地方的值是一样的。

定义常量,方便输出以及接口调用

在 config/config.js 中,定义常量 BASE , 设置好值。

const BASE = '/dashboard';

然后在 define 中进行注册该值。只有注册了,其他 js 才能访问的到,并且不需要加 window,请看这里文档。
https://pro.ant.design/docs/environment-variables-cn#%E5%A4%84%E7%90%86%E5%9C%A8-lint-%E4%B8%AD%E7%9A%84%E6%8A%A5%E9%94%99

于是 config/config.js 是这样

const BASE = '/dashboard';
…
export default {
  base: BASE,
  publicPath: `${BASE}/`,
  outputPath: `../../public/${BASE}/`,
  plugins,
  hash: false,
  targets: {
    ie: 11,
  },

…

utils/request.js 是这样

const request = extend({
  prefix: BASE,
  errorHandler,
  // 默认错误处理
  credentials: 'include', // 默认请求是否带上cookie
});

好了,提交 git 暂时先到这一步。

git add .

git commit -m '定义BASE作为项的输出路径和Api前缀'

最后又多一句,还是可以使用 npm start 进行奔跑的。

可参考

https://pro.ant.design/docs/getting-started-cn

https://www.yuque.com/yuxuanbeishui/zog1rm

https://learnku.com/articles/32218

https://umijs.org/zh/config/#uglifyjsoptions

https://www.codercto.com/a/26106.html

12月 20

虽然 homestead 用的很习惯,还是想尝试新东西 docker 。也不是新东西了,出来有些年了。既然用 laravel ,那么就用 laradock

熟悉 virtualBox + vagrant + homestead 的朋友,对于 laradock 上手也会很快。当初,装 homestead 需要安装 virtualBox(也可以是vm等) 和 vagrant,然后是使用 homestead 来实现环境的配置安装。对于 docker 可以这样理解,docker 就是 virtualBox + vagrant,或是 vagrant。 我们只需要安装一个 docker 就可以了。然后下载 laradock 即可以开始安装了。

步骤

安装使用,一步到位,初观全局

laradock: https://github.com/laradock/laradock

这里以 win 为例子:

# 先选定一个磁盘位置,用来存放 laradock 并且相邻文件夹做为 www 目录(当然也可以其他位置)
cd /e/
mkdir service
cd service

git clone https://github.com/laradock/laradock.git

cd laradock

# 准备配置文件
cp env-example .env

# 修改配置文件
vim .env
# 修改 APP_CODE_PATH_HOST = '../www'

# 创建并启动
docker-compose up -d nginx php-fpm mysql redis workspace

# 重启
docker-compose restart

# 进入服务器
winpty docker-compose exec workspace bash

# 退出 
exec 

上边的过程,可能有些长久。先创建 laravel 项目。

# 默认安装最新版本。当前版本 6.8
composer create-project laravel/laravel --prefer-dist docker.cn

再配置 nginx,创建默认 laravel 项目

cd service/laradock/nginx/sites

# 复制一份配置出来。命名一定要以 .conf 作为后缀
cp app.conf.example docker.cn.conf 

# 修改 docker.cn.conf
vim docker.cn.conf

# 通常会修改 server 下的 server_name 和 root。将 server_name 修改为你想要指定的域名。比如 docker.cn。 root修改为映射的文件目录。比如 /var/www/study/docker.cn/public 。保存退出。

# 每个对象都是一个容器
# 比如 修改了 nginx 只需要单独启动 nginx 即可
docker-compose up -d nginx

然后再执行 winpty docker-compose exec workspace bash 。如果发现还是访问不了。可以 docker-compose restart 再执行 winpty docker-compose exec workspace bash 

配置 host

# 修改 host 文件,再末尾加入 
vim hosts
GG
127.0.0.1 docker.cn

###
https://xueyuanjun.com/post/9608

https://www.cnblogs.com/itfenqing/p/10972603.html

https://blog.csdn.net/lfm940624/article/details/86678698

12月 16

做聊天项目的时候,通常会用到关键词过滤。对于一些敏感信息,可能还会进行内容加密。这里从两个不同的功能点,总结下过程。也是在别人的基础上,跑了一遍而已。照着做,可以一步到位。

环境
1. php
2. js
3. laravel

敏感词过滤

https://github.com/FireLustre/php-dfa-sensitive

composer require lustre/php-dfa-sensitive

# 项目中
use DfaFilter\SensitiveHelper;

# 添加词库,使用文件
$path = storage_path('sensitive/words.txt');
$handle = SensitiveHelper::init()->setTreeByFile($wordFilePath);

# 添加词库,单个添加
$data = [
    '哎呦我的天',
    '太阳',
    '太阳块融化我的脸'
];

$handle = SensitiveHelper::init()->setTree($data);

# 替换,检测
$islegal = $handle->islegal($content);

$content = '啥啥啥,哎呦我的天呀,太阳快融化我的脸';

$content = $handle->replace($content, '*', true);

上边这些,github 上都有,照着做就可以了。

https://www.zkii.net/tech/php/1115.html

数据加密解密

这里数据加密使用 aes。数据加密解密的对象是字符串。无论哪 js 还是 php,都可以互相转换。不过这里可能存在一种文体,js 加密的 js 可以解密,但 php 不能解密。反之亦然。出现这种情况,往往是加密解密模式没有配对上。

** js 加密解密 **

参考: https://blog.csdn.net/yingbaoyu/article/details/95761177

如果不是 node 环境,可以下载 https://pan.baidu.com/s/1Mvg8vhlD56wvS4b6yjUoaA 提取码:57gd

例子:


const aseKey = 'YjKp7COQ9QZN2EgMJdiI8tzBsJarvQAr'; const aseIv = 'zmtuC5UyMfK3r1QYXKa1lYmNNy8F5jiP'; //将秘钥转换成Utf8字节数组 const key = CryptoJS.enc.Utf8.parse(aseKey); const iv = CryptoJS.enc.Utf8.parse(aseIv); let data = { name: 'vini', gender: 1 } data = JSON.stringify(data); let encoded = CryptoJS.AES.encrypt(data, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }).toString(); console.log(encoded); let uncoded = CryptoJS.AES.decrypt(encoded, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }).toString(CryptoJS.enc.Utf8); console.log(uncoded); # 这个时候, data 应该等于 uncoded

key 的长度决定了 CBC 模式的不同。

# php 加密解密

<?php

namespace App\Helper;

class Aes
{
    static public function encrypt($data)
    {
        $method = 'AES-256-CBC';
        $key = 'YjKp7COQ9QZN2EgMJdiI8tzBsJarvQAr';
        $iv = 'zmtuC5UyMfK3r1QY';
        return openssl_encrypt($data, $method, $key, 0, $iv);
    }

    static public function decrypt($data)
    {
        $method = 'AES-256-CBC';
        $key = 'YjKp7COQ9QZN2EgMJdiI8tzBsJarvQAr';
        $iv = 'zmtuC5UyMfK3r1QY';
        return openssl_decrypt($data, $method, $key, 0, $iv);
    }
}

这里为了方便,把 method key iv 都写死了。项目里边不会这样做。比如,可以定义一个类:

<?php
namespace App\Utils;

class Aes
{
    protected $aesSecret = 'YjKp7COQ9QZN2EgMJdiI8tzBsJarvQAr', $aesIv = '00000000000000000000000000000000';

    /**
     * 进制转换
     * @param string $hex
     * @return string
     */
    protected function aesHexIv($hex = '')
    {
        $string = '';
        $hex = $hex != '' ? $hex : $this->aesIv;
        for ($i = 0; $i < strlen($hex) - 1; $i += 2) {
            $string .= chr(hexdec($hex[$i] . $hex[$i + 1]));
        }
        return $string;
    }

    /**
     * AES加密
     * @param string $content
     * @param string $key
     * @param string $hex
     * @return string
     */
    public function aesEncrypt($content = '', $key = '', $hex = '')
    {
        $hash = hash('sha256', $key ?: $this->aesSecret, true);
        $enCrypt = openssl_encrypt($content, 'AES-256-CBC', $hash, PKCS7_TEXT, $this->aesHexIv($hex));
        return base64_encode($enCrypt);
    }


    /**
     * AES解密
     * @param string $content
     * @param string $key
     * @param string $hex
     * @return string
     */
    public function aesDecrypt($content = '', $key = '', $hex = '')
    {
        $content = base64_decode(str_replace(' ', '+', $content));
        $hash = hash('sha256', $key ?: $this->aesSecret, true);
        return openssl_decrypt($content, 'AES-256-CBC', $hash, PKCS7_TEXT, $this->aesHexIv($hex));
    }
}

https://www.php.net/manual/zh/openssl.pkcs7.flags.php

更多信息

https://baike.baidu.com/item/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86/468774?fromtitle=aes&fromid=5903&fr=aladdin

https://www.keylala.cn/aes

https://blog.csdn.net/GlatChen/article/details/79978875

https://suijimimashengcheng.51240.com/

进一步了解 aes 加密解密

在多端配合的情况下,不是 keyiv 都对,就可以解密出加密的数据的。 秘钥位数,加密模式,填充方式也得一一对应上。

aes 参数

  1. key length(密钥位数,密码长度)
  2. key (密钥,密码)
  3. IV (向量)
  4. mode (加密模式)
  5. padding (填充方式)
11月 11

laravel 使用 npm

使用 yarn 来管理

npm config set registry=https://registry.npm.taobao.org

yarn config set registry https://registry.npm.taobao.org

yarn install

npm run watch-poll

假如使用 bootstrap

composer require laravel/ui --dev

php artisan ui bootstrap
9月 25

商户操作:

  1. 安装操作证书 。 使用 mac chrome 安装完成控件后,发现 控件启动不了。这个时候可以这么操作。
  • 浏览器输入 chrome://flags 回车
  • 搜索 Native Client 将状态改成 enable
  • 重启 chrome 即可。
  1. api 安全相关。
# 生成 32 位秘钥
# http://code.php.net.cn 在线编辑

// 创建随机字符串
function createNoncestr($length = 16)
{
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    $str = "";
    for($i = 0; $i < $length; $i ++)
    {
        $str .= substr ( $chars, mt_rand ( 0, strlen ( $chars ) - 1 ), 1 );
    }
    return $str;
}

$str = createNoncestr(32);

echo $str;
  1. api 证书

https://kf.qq.com/faq/180824JvUZ3i180824YvMNJj.html

  • 点击更换证书,下载证书只做工具。
  • 设置好路径,下一步生成即可。粘贴进网站上商户输入框。
  • 再网站下一步,生成证书粘贴到工具中。下一步即可。然后打开之前设置的路径。就可以看到 zip文件了。

api 证书不影响支付,对提现等功能才有用。

9月 12

这里的关键点:
1. redis 异步队列。
2. 多项目。

面对上边这种情况,怎么处理呢。如果不处理又会出现什么现象呢。

因为我们使用 supervisord 进行常驻队列侦听。如果不指定对应的 queue,多项目就会出现串的情况。这个是就可以用 queue 来处理该问题了。

处理

  1. 修改 supervisord 的配置文件。在 command 中指定一个 queue 。如
command=/alidata/service/php/bin/php /alidata/www/www.mlxiu.com/artisan queue:work redis --queue=test --sleep=3 --tries=3
  1. 在项目中,指定 queue。因为使用的是 laravel 框架。 队列继承 ShouldQueue。 可以在构造函数中指定 queue 即可。
public function __construct($id)
{
     $queueName = config('queue.name');
     if ($queueName) {
         $this->onQueue($queueName);
     }
}

queue.name 是自己额外在 queue.config 中添加的变量。

参考

https://www.cnblogs.com/zgxblog/p/10996112.html