台式机安装黑苹果

公司目前使用的是台式机,而且不给带个人电脑- -。内部局域网,系统装的是ubuntu18.04桌面版,老实说,用可以用,也还算流畅额,就是软件生态太差,啥也没,qq,微信,ever note等,甚至需要打交流卡的钉钉也没有。用了1个月,实在是忍不了,怒装黑苹果解决需求问题


参考

安装配置

  • 主板:技嘉
  • cpu:Intel core i5-3470 4核心 4线程 3.2GHz
  • 集显:Intel 2500 hd(不支持黑苹果,未使用,具体详见下方免驱速查表)
  • 独显:NVIDIA gt 710 1g显存
  • 硬盘:500g机械硬盘(windows 系统盘),120g 固态硬盘(mac os 安装系统盘)
  • 内存:16g (金士顿8g*2)
  • 声卡:瑞昱
  • 网卡:intel 技嘉
  • 蓝牙:无

教程

准备

  • 8g+ u盘 usb2.0(16g+ usb3.0更佳)
  • macOS 10.14 mojave with clover 系统安装包
  • windows(或pe)下安装disk genius, balenaEtcher(推荐) 或 Transmac

step1-制作macOS系统安装盘

  • 在windows或pe环境下
  • 系统安装包下载 验证码 ekka
  • 使用balenaEtcher(管理员权限启动)将安装包导入u盘: 步骤

1,选择镜像

2,选择u盘

3,点flash

4,写入与验证预计30分钟(若u盘有重要资料请提前备份)

step2-设置bios

step3-设置开机u盘启动

  • 根据电脑主板型号自行百度u盘启动方法

del

f11

f12

或其他键位

step4-安装

  • 出现任何安装问题可以拉到最下面的 !!!常见问题说明!!!
  • 1,一般u盘启动后,会短暂的跑码,然后进入安装引导页(clover引导教程
  • 2,光标选择boot macos from xxx(开机或第二次安装时xxx代表安装盘名称/第一次安装时择选 install macOS Mojave)回车
  • 3,等待跑码
  • 4,一般最多4分钟,就会进入苹果logo加载页
  • 5,加载完后,会出现苹果系统安装界面
  • 6,选择磁盘工具,全部,格式化(抹除)需要安装系统的盘为APFS格式(ssd推荐)或macOS扩展日志格式(机械硬盘推荐),系统盘分区格式选择gpt(guid)
  • 7,退出磁盘工具,选择 安装macos 项(此时建议断网)
  • 8,同意,选择刚刚格式化的磁盘分区,安装
  • 9,如果不卡读条,可能会安装2次(第一次安装完会自动重启,然后从step4的步骤2再选择一次,继续安装)
  • 10,安装成功,进入系统(基本设置,如地区,输入法,开机密码,apple-id登陆等)
  • 11,注意,此时请勿拔出u盘!!!

step5-配置独立启动

  • 下载 ,启动 clover configurator(下面简称cc)
  • 2 选择左侧 挂载分区,挂载u盘,打开分区(cc挂载教程
  • 3 将u盘中的EFI文件夹下的所有文件拷贝到macos系统盘的EFI文件夹下(不再需要u盘了)
  • 4 重启,设置开机第一启动项为macOS系统盘

mac 系统设置

php开发环境搭建

  • ide(phpstorm,pycharm自行下载安装)
  • 命令行设置(百度)
  • git,gitlab设置(百度)
  • homebrew 安装(/bin/zsh -c “$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)”)
  • nginx(brew install nginx)
  • php-fpm(自带,需配置)
  • php扩展安装(pecl install redis; echo ‘path/to/extension/pecl/redis.so’>>path/to/php.ini;php -m|grep redis;重启fpm)

常见问题说明

其他

  • q:安装苹果系统可以升级么?a:可以,我从10.14.6 mojave 通过系统自带的升级工具成功升级带 10.15.7 catalina ,但是存在风险,可能出现无法开机,黑屏等不兼容情况
  • q:性能如何?a:显卡配置ok的情况下,同时开启20+chrome浏览器页面,phpstorm,pycharm,钉钉,qq,微信,wps,运行流畅,约还剩3g内存,cpu负载极低(约10%)
  • q:待定

常见后端开发规范(PHP)

今天主管要求我们每个人都上交一份代码开发规范,我百度了一下,很多说的都不是特别好,要么就太基础,不符合实际的开发过程,所以下面结合我这几年的开发感悟,写一点,如有错误,请指正,一定虚心接受:

代码:

  1. 变量定义:小写,采用蛇形命名法,简明达意,避开系统关键词
  2. 方法名:小写,采用蛇形命名法,简明达意,避开系统函数
  3. 类名:首字母大写,采用蛇形命名法(或命名空间),避开系统类名
  4. Oop编程,少堆无脑传参func, 多写注释,避免过度优化和冗余
  5. 编码基本规则遵循psr1~4即可
  6. 遵循基本设计模式,逻辑向上(历史)兼容性
  7. 工具类统一封装,如curl,excel,qrcode等,方便他人
  8. 数据库常量定义:区分类型(sql,nosql),主从,读写,缓存,使用类型等
  9. 尽量使用composer管理包文件
  10. Web请求禁止循环查询,禁止无法命中主要索引的大表关联查询,禁止使用sql处理主要代码逻辑
  11. 注意安全性问题,如注入,提权,流量攻击等
  12. 数据结构
    1. 对外接口
      1. 基本输出格式json:【‘data’,‘msg’,‘code’】
      2. 文档:定义必要请求字段,类型及说明,请求头header,请求方式post/get,返回字段,类型,说明
      3. 可能需要定义:版本号,加密方式(jwt),签名等
    2. 对内部数据提供
      1. 语言内,框架内:方法调用
      2. 跨语言/框架:rpc调用(如使用hprose)
      3. 所有请求走内网,禁止数据公网裸奔
  13. 命令行脚本查询需评估查询sql效率与资源占用,酌情考虑执行时间,单次查询命中数据过多需分页处理
  14. 注意缓存,异步,队列等中间件的使用,提高系统健壮性
  15. 使用git,切分支协作开发和版本管理
  16. 开发需注意上线时依次考虑: 合并分支,解决冲突,生产建表/增改字段,常量增/改,脚本执行,依赖安装,常驻服务(重新)启动,最后才能发布新代码
  17. 尽量保持一致的开发风格,让任何人都能快速接手,定位,处理其他人的代码

数据库设计:

  1. 库名:小写,项目名_db结尾,如shop_db
  2. 表名:小写,tb_表名(蛇形命名),如tb_user_guest
  3. 字段名:小写,尽量两个单词组合使用(蛇形命名),避开系统关键字,函数
  4. 除主键,添加/更新时间等常用字段外,其余字段必须设置注释(comment)
  5. 单表字段尽量不超过30个,并根据业务给予适当的类型和长度
  6. 唯一性高,常用查询字段(=)需设置索引(一般单表设置不超过5个索引),联合索引遵循最左原则
  7. 部分危险操作前需备份数据库/表(如脚本,sql批量刷新数据库/表内容)
  8. Nosql,空间换时间,搜索服务处理mysql无法处理的问题
  9. 隔离权限,禁止生产和测试环境数据服务器可互访问,避免产生脏数据

服务器:

  1. 主机名:遵循 功能-区域-编号 命名规则
    1. 功能:app-线上环境,dev-开发环境,qa-测试环境,beta-预发布环境,cache-缓存,bi-服务数据,cdn-内容分发,vpn-代理网关,db-数据,lb-负载均衡,dns-域名解析等
    2. 区域:上海-01,北京-02,杭州-03等
    3. 编号:一号机-001,二号机-002
    4. 示例:app-03-001代表:生产环境-杭州-一号机,vpn-02-005,代表:代理服务器-北京-五号机
  2. 域名、二级域名设计
    1. 简明达意,参考1-1如业务型shop.shuidi.cn,系统型bi.shuidi.cn
    2. 区分公/内网,如公网shop.shuidi.cn,内网shop.i.shuidi.cn 多了一个i,内部请求走内网域名
    3. 区分功能,如shop.dev.shuidi.cn, 同理qa-测试,beta-预发,生产环境一般不做特别声明
  3. 规范软件安装目录,版本,用户,权限(755,644或特别提出需要的权限足以,一般不给777和root)
  4. 谨慎处理服务器版本/软件版本升级,防止出现兼容性问题
  5. 开启服务器定期自动备份
  6. 定期清除非必要的垃圾日志,文件,缓存内容
  7. 开发需通过vpn才能访问服务器,设置复杂密码
  8. 公网端口按需开放,不需要的禁用
  9. 离职人员回收权限

Bug/log track:

  1. 规范服务器日志输出目录,日志结构,保存时长
  2. 规范业务日志的基本输出内容,如ip,from,keyword,type,content等
  3. Bug report 影响级别:b0,b1,b2 ,响应级别:p0,p1,p2
  4. 软件开发,测试,发布流程,版本和周期

记一次java和php使用aes加密/解密打通

对接了个第三方公司的服务,需要集成到公司的产品页,由于对方的技术栈是java,并且对接接口需要将数据加密传输,对方发来了java版的加解密方法,如下:

package kd.common.codec;

import java.security.MessageDigest;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

/**
 *  AES 128 加密,与Nodejs 保持一致
 * @author daiyang
 *
 */
public class AesUtil {
	
	private static final String secret = "pater";
	
	public static final String DEFAULT_CODING = "utf-8";

	/**
	 * 解密
	 * @param encrypted
	 * @return
	 */
	public static String decrypt(String encrypted){
		return decrypt(encrypted, secret);
	}
	/**
	 * 解密
	 * @param encrypted
	 * @param secret
	 * @return
	 * @throws Exception
	 */
	public static String decrypt(String encrypted, String secret){
		try{
			byte[] keyb = secret.getBytes(DEFAULT_CODING);
			MessageDigest md = MessageDigest.getInstance("MD5");
			byte[] thedigest = md.digest(keyb);
			SecretKeySpec skey = new SecretKeySpec(thedigest, "AES");
			Cipher dcipher = Cipher.getInstance("AES");
			dcipher.init(Cipher.DECRYPT_MODE, skey);

			byte[] clearbyte = dcipher.doFinal(toByte(encrypted));
			return new String(clearbyte);
		}catch(Exception e){
			e.printStackTrace();
			return "";
		}
		
	}

	/**
	 * 加密
	 * @param content
	 * @return
	 */
	public static String encrypt(String content)  {
		return encrypt(content, secret);
	}
	/**
	 * 加密
	 * @param content
	 * @param secret
	 * @return
	 * @throws Exception
	 */
	public static String encrypt(String content, String secret)  {
		try{
			byte[] input = content.getBytes(DEFAULT_CODING);

			MessageDigest md = MessageDigest.getInstance("MD5");
			byte[] thedigest = md.digest(secret.getBytes(DEFAULT_CODING));
			SecretKeySpec skc = new SecretKeySpec(thedigest, "AES");
			Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, skc);

			byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
			int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
			ctLength += cipher.doFinal(cipherText, ctLength);

			return parseByte2HexStr(cipherText);
		}catch(Exception e){
			e.printStackTrace();
			return "";
		}
	}

	/**
	 * 字符串转字节数组
	 * @param hexString
	 * @return
	 */
	private static byte[] toByte(String hexString) {
		int len = hexString.length() / 2;
		byte[] result = new byte[len];
		for (int i = 0; i < len; i++) {
			result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
		}
		return result;
	}

	/**
	 * 字节转16进制数组
	 * @param buf
	 * @return
	 */
	private static String parseByte2HexStr(byte buf[]) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < buf.length; i++) {
			String hex = Integer.toHexString(buf[i] & 0xFF);
			if (hex.length() == 1) {
				hex = '0' + hex;
			}
			sb.append(hex);
		}
		return sb.toString();
	}

}

然后我发现,这完全就是百度的一个加密方法- -,其中,有nodejs版的互通方法:

/**
 * aes加密
 * @param data
 * @param secretKey
 */
encryptUtils.aesEncrypt = function(data, secretKey) {
	var cipher = crypto.createCipher('aes-128-ecb',secretKey);
	return cipher.update(data,'utf8','hex') + cipher.final('hex');
}
 
/**
 * aes解密
 * @param data
 * @param secretKey
 * @returns {*}
 */
encryptUtils.aesDecrypt = function(data, secretKey) {
	var cipher = crypto.createDecipher('aes-128-ecb',secretKey);
	return cipher.update(data,'hex','utf8') + cipher.final('utf8');

下面,我提供php版的加/解密方法,如下

/**
* 加密
* @param $str-需要加密的字符串
* @param $key-密钥
* @return string
/
function getEncryptContent($str,$key)
{
    return bin2hex(openssl_encrypt($str,'aes-128-ecb', openssl_digest($key, 'md5', true), OPENSSL_RAW_DATA));
}

/**
* 获取解秘内容
* @param $decode_str-需要解密的字符串
* @param $key-密钥
* @return string
*/
function getDecryptContent($decode_str,$key)
{
    return openssl_decrypt(hex2bin($decode_str), 'aes-128-ecb', openssl_digest($key, 'md5', true), OPENSSL_RAW_DATA);
}

ImageMagick 文字写入图片时,变问号的解决方法

使用ImageMagick做海报时,如果需要写入用户微信昵称,比如 ‘张三👏’,图片内的文字会变成 ‘张三?’,因为本质上,emoji不是文字,在常规入Pingfang字体中,是不存在对应关系的。查遍24史(github和stackoverflow),都说ImageMagick并不支持emoji表情,php自带的gd库就更不支持了。

说明

首先,emoji对应的unicode码在不同平台解析出的样式不同。所以即使mysql使用字符集UTF8mb4格式将emoji存储起来,拿出来后,发给前端(andr,ios,浏览器),同一个unicode的图并不一样。

思路

所以,想让‘张三👏’完美的在海报上写出来。需要转换思考的方式,将‘张三👏’拆分成‘张三’+‘👏’,前者当成文字,后者当成图片。所以,能找到对应unicode对应的图片素材。就能使用ImageMagick的写入文字和合并图片的方法分治处理了。

emoji素材

https://www.unicode.org/emoji/charts/full-emojilist.html

以上链接为unicode对应的emoji在各大平台的图像映射关系

分析一下页面源代码,发现,除了绿框内的。其他的都是base64的格式发出的图片数据流,如下:

所以,直接control + s 保存该页面,重命名为emoji.html,同时mkdir 建立emojis文件夹,编写处理图片的php代码,如下:

<?php

$str = file_get_contents('./emoji.html');
$regx = '/<td class=\"code\">.*?<a href=.*?>(.*?)<\/a>.*?<img.*? class=\"imga\" src=\"(.*?)\">.*?<\/td>/is';
preg_match_all($regx, $str, $matches, PREG_PATTERN_ORDER);
$codes = $matches[1];
$stream = $matches[2];
unset($matches);
function get_img_type($str){
    $regx = '/^(data:\s*image\/(\w+);base64,)/';
    preg_match($regx, $str, $result);
    return $result;
}
foreach($codes as $k => $code){
    $code = str_replace(' ', '', $code);
    $code = str_replace('U+', '', $code);
    $info = get_img_type($stream[$k]);
    $mime = $info[2];
    $prefix = $info[1];
    $streamInfo = base64_decode(str_replace($prefix, '', $stream[$k]));
    file_put_contents('./emojis/'.$code.'.'.$mime, $streamInfo);
    unset($stream[$k]);
}

运行后,拿出所有图片,如下,素材已经取出来了

那么,如何找到‘?’对应的unicode码呢

如下php函数

function utf8ToUnicode($utf8) 
{
    $i = 0;
    $l = strlen($utf8);
    $out = '';
    while ($i < $l) {
        if ((ord($utf8[$i]) & 0x80) === 0x00) {
            $n = ord($utf8[$i++]);
        } elseif ((ord($utf8[$i]) & 0xE0) === 0xC0) {
            $n =
                ((ord($utf8[$i++]) & 0x1F) <<  6) |
                ((ord($utf8[$i++]) & 0x3F) <<  0);
        } elseif ((ord($utf8[$i]) & 0xF0) === 0xE0) {
            $n =
                ((ord($utf8[$i++]) & 0x0F) << 12) |
                ((ord($utf8[$i++]) & 0x3F) <<  6) |
                ((ord($utf8[$i++]) & 0x3F) <<  0)
            ;
        } elseif ((ord($utf8[$i]) & 0xF8) === 0xF0) {
            $n =
                ((ord($utf8[$i++]) & 0x07) << 18) |
                ((ord($utf8[$i++]) & 0x3F) << 12) |
                ((ord($utf8[$i++]) & 0x3F) <<  6) |
                ((ord($utf8[$i++]) & 0x3F) <<  0)
            ;
        } elseif ((ord($utf8[$i]) & 0xFC) === 0xF8) {
            $n =
                ((ord($utf8[$i++]) & 0x03) << 24) |
                ((ord($utf8[$i++]) & 0x3F) << 18) |
                ((ord($utf8[$i++]) & 0x3F) << 12) |
                ((ord($utf8[$i++]) & 0x3F) <<  6) |
                ((ord($utf8[$i++]) & 0x3F) <<  0);
        } elseif ((ord($utf8[$i]) & 0xFE) === 0xFC) {
            $n =
                ((ord($utf8[$i++]) & 0x01) << 30) |
                ((ord($utf8[$i++]) & 0x3F) << 24) |
                ((ord($utf8[$i++]) & 0x3F) << 18) |
                ((ord($utf8[$i++]) & 0x3F) << 12) |
                ((ord($utf8[$i++]) & 0x3F) <<  6) |
                ((ord($utf8[$i++]) & 0x3F) <<  0);
        } else {
            throw new \Exception('Invalid utf-8 code point');
        }
        $n = strtoupper(dechex($n));
        $pad = strlen($n) <= 4 ? strlen($n) + strlen($n) %2 : 0;
        $n = str_pad($n, $pad, "0", STR_PAD_LEFT);

        $out .= $n;
        //$out .= sprintf("\u%s", $n);

    }
    return $out;
}

echo utf8ToUnicode('👏');   //输出1F44F

从emojis文件夹中可以找到1F44F.png,就是对应的素材。

最后,怎么用ImageMagick插入图片到另一张图片上,这就不在此多做赘述了。

效果图如下:

ubuntu+php+imageMagick安装

前言

小程序无法分享到朋友圈,所以通常是通过生成海报的方式,让用户保存图片,然后发到朋友圈,php常用的图片处理扩展gd效率低下,代码复杂,不适合快速开发~

安装

安装ImageMagick

sudo apt-get install imagemagick libmagickwand-dev

安装imagick

sudo apt-get install php-imagick

使用 Intervention image

https://github.com/Intervention/image star9.8k

教程

教程1(EN):http://image.intervention.io/

教程2(CN):https://blog.csdn.net/beyond__devil/article/details/62230610