laravel在vagrant环境中nginx的权限问题

由于有很多遗留项目,所以在引入laravel时候就没有使用homestead,而是直接使用已有的vagrant环境。

部署后发现有各种权限问题,在网上也没有发现靠谱的方法。后来还是找到了相对复杂一些,但一劳永逸的方法。

首先vagrant会自动将我们映射的文件夹所有的文件权限设置为 vagrant:vagrant,即使我在vagrant中如何将文件夹内的所有内容chmod 777或775,都无济于事。

很自然地,既然无法修改文件的用户组,就考虑将fpm的用户组修改为vagrant:

sudo vi /etc/php/7.2/fpm/pool.d/www.conf

将原来的:

user = www-data

group = www-data

修改为:

user = vagrant

group = vagrant

即可。

另一种方法原理相同,修改Vagrantfile文件:

config.vm.synced_folder “.”, “/vagrant/”,owner: “www-data”, group: “www-data”

也就是直接修改同步文件夹的owner和group为www-data。

注意:第二种方法由于改变了工作目录的默认用户组(vagrant -> www-data),在执行composer相关命令时会出现问题,由于vagrant默认的登录用户是vagrant,此时执行composer的也是vagrant用户,同样会出现permission denied的问题。这么看来还是第一种办法更好一些。

PS. 如果修改了/etc/php/7.2/fpm/pool.d/www.conf 中的 listen.owner = vagrant  listen.group = vagrant,那么需要/etc/nginx/nginx.conf中的user为vagrant,否则nginx默认的用户www-data会没有权限连接fpm。并且,由于我的error.log和access.log配置在项目文件夹内,而这个文件是nginx创建的,所以也要配置nginx.conf的user为vagrant。

PS. 有的人也建议在vagrant环境中将vagrant用户加入www-data组,试了一下貌似也不行。至少还需要将文件夹内容设置为665以上。

增长七武器 – 券

总结一下常用的增长工具,原本想的是很多“虚”的、方法论的东西,但是貌似这种东西写出来大家都不感兴趣。尝试一下用具体的工具来“说教”一番。

定义

什么是券?当我们想要穷尽券的本质时,发现不得不限定它的范围。否则真是无从说起。我将券的定义追溯为“凭证”,所以,在我的系统里,券叫voucher。

所谓“凭证”,就是:你可以有偿或者无偿地获得它,当你拥有它的时候,可以将它换成其他的东西。这句话貌似是“废话”。

从增长的角度来说,券可以在获客(新客送券)、激活(随机发券、短信发券)、留存(生日券、特权券)方面发挥重要作用,而且很重要的一点,券是“可控”的,总数量、每人可获取的数量、一段时间可以使用的数量、过期时间。这些东西都是已经每个用户都很清楚的事情,不需要额外的用户学习成本。

类型

打折券、立减券 – 很好理解,在结账(场景)时,将它变成相应的折扣金额。

抵用券 – 类似的,在结账时,将它变成账单中的某N件商品的金额

实物领取券 – 需要到店领取的礼品或者商品

团购券 – 这里主要是限定了场景和条件 – 团购,只是流程不太一样,需要先付款,然后根据成团情况决定订单是否能够确认。在使用时和打折、立减、抵用类似,只是有一个时间差来判断是否成团。不过在实际中,大多数情况下都是容易成团的,团购只是个噱头。

充值券 – 有一个开卡(自助核销)的动作,之后根据券的规则给账户充一笔钱。

生命周期

核销 <- 获取 -> 过期

获取,可以免费领取、购买

核销,即券从一个号码变成另一个东西的那个动作

过期,建议所有用户的券、积分都要设置过期时间

财务核算

大多数单店都其实不需要考虑财务问题。但是多店或者有不同财务结构的情况时就需要考虑财务归属的问题了。

发券本质是一种营销行为,就会产生成本。有了营销成本,就要考虑是谁来承担以及承担多少的问题。

这也是为什么有时候没办法做充值返金额的原因,因为在A店的充值、返的金额可能是无法在B店消费的。因为A、B可能是财务独立的加盟店。有一种是简单的操作是一种独立的账户来挂营销费用,然后所有店均摊,但同样存在复杂的情况和不均的情况,比如A店送的100块钱,用户在B店消费了10块,在C店消费了50块,账户里还有40块没消费。就会很麻烦。最保险的方法就是将A送出的100元挂账,然后定期从A的收入中扣除掉,然后相应的分给B或者C,剩余的一直挂着。

这时候用券就方便多了,限定使用场景、甚至门店类型、次数(发送多张)。并且券的使用是方便统计的

关于微信开发时候的UnionId问题

什么是unionId?

微信为了将同一个公司/实体的不同应用里的同一个用户关联起来。(好绕)

为什么要有unionId这个东西?

定义的很清楚,因为账户系统需要知道从公司的各个微信应用中(小程序、网页、APP)进来的用户是同一个。便于账号管理,否则可能会出现同一个人由于使用不同的应用造成多个账号的问题。对用户来说,最好是无感的。

实际情况中,很常见的一种情况:先有公众号,网页开发,一段时间,然后上线小程序或者APP。这时候就必须将原有的网页授权信息补充unionid,因为原来可能是没有的。可以通过微信API批量地获取「已关注公众号」用户的unionId并更新到系统里。

但是,之前的授权信息可能是单次授权,用户并没有关注公众号,那么对于这部分用户,是无法通过微信的API获得unionId的。

这时候,就需要在系统逻辑中兼容这种情况,即下次这些用户登录时候,如果unionId没有,就要顺便将unionId更新上。但是,如果这些人通过小程序或者APP进来呢?因为之前的账户信息没有unionId,所以小程序登录后无法通过unionId关联到之前的账号(而之前的账号有可能是有资产的,比如余额、积分、券)。

一种解决办法是:检查所有没有unionId,也没有关注公众号的用户,将信息删除掉。这样下次这部分用户直接就有unionId,重建账号。缺点是:如果用户账号里有资产,这样就不合适了。:-p

另一种解决办法:账号体系强制关联手机号码(前提是从系统建立之初就是这个规则),这样就可能通过手机号进行一次关联,如果关联到,则将新的小程序或者APP指向手机号码指向的用户。缺点:前提可能并不存在 – 毕竟没有必要强制做手机号码关联这件事。

没有其他解决办法了。

这种问题的产生原因就非常蛋疼。

微信和Java

今天偶发奇想,觉得微信其实和Java很像。

遥想当年SUN一边推出Java语言,一边打着“network is computer”的口号。而当时Java最火的概念除了基于JVM的跨平台 – “一次编译,随处运行”以外,还有一个Applet的东东。从字面上理解,这个东西就是“小程序”(就像pigglet,ducklet,chicklet…),基于浏览器的“小程序”,也就是给不同的浏览器提供相应的JRE,然后Applet也是“一次编译,随处运行”了。

而最终呢?这个Applet并没有“火”起来,部分原因还是生不逢时吧,当时的浏览器实在是太弱了,而且Flash又看起来更酷炫一些,再到后来连Flash也退出了历史舞台了。

微信和Java的“关联”就是我今天想到了applet这个词。

我觉得微信小程序的命运应该是“applet”差不多,还真不是“生不逢时”的原因,应该说,微信小程序这3年的火爆,完全是微信本身的强势造血。因为小程序的天性是“封闭、隔绝”的,而“开放”才是永恒的趋势。

貌似我们一直在解决“跨平台”的问题

为了解决不同操作系统中运行软件的问题,我们发明了Java来实现“一次编译,随处运行”。貌似很多时候我们都尝试不依赖于所谓的平台。

但最终我们发现,所谓的平台、版本本身的这种“反跨平台”的设计,是有存在的意义的。–至少对创造这些平台的人来说。

人类社会无时无刻不是在解决这些纠结,只是在不同的领域罢了。制造分歧(可能是因为审美、或者仅仅凭借运气),消除分歧(可能并不是所标榜的那么伟大),然后制造新的分歧。

Java解决了软件在桌面操作系统层面的跨平台问题,但是现在的iOS和Android又产生了有待解决的问题。

然后现在很多人在倡导React Native、Uniapp、Ionic这些框架,思路依然是“一次编译,随处运行”。

微信支付的使用场景总结

关于微信支付的库和文章很多,但似乎都没有很好地说清楚各个接口的使用场景。这里结合之前的经验对微信支付文档做个补充。微信的文档在这里:https://pay.weixin.qq.com/wiki/doc/api/index.html

MICRO – 付款码支付

所谓的通过扫码设备扫描用户出示的付款码,类似POS的操作,只是POS机换成了扫码设备,银行卡磁条换成二维码。扫码设备在x宝就有的卖,100左右(可能更便宜),其实就是一个输入设备,付款码就是一段字符串。这个扫码设备只是做一个二维码到字符串的转换而已,所以可以支持微信、支付宝、银联或者你自己开发的支付码。

使用这个方案需要注意,有时候用户不是扫码后马上同步完成的,而是需要输入密码或者余额不足换卡(微信和支付宝都有可能产生这种情况),或者最终取消交易的。所以在扫码页面最好进行后台的轮询检查支付结果。

JSAPI – 公众号支付

其实更准确地说,是微信浏览器内支付(有别于H5支付是在用户移动设备上的浏览器)。在微信里,体验是最好。但是通常需要根据用户浏览器UA进行切换,如果是微信浏览器就用JSAPI,如果是在不在微信里,但是在手机浏览器里,就切到MWEB。

MWEB – H5支付

主要是用户在手机浏览器里支付,此时会打开用户手机里微信进行支付。

如果用户没有安装微信呢?

NATIVE – 扫码支付

商户端生成订单,然后生成对应的付款二维码,来让用户进行扫码支付。和MICRO是最常用的线下支付场景,和MICRO相比稍微麻烦一些,因为需要输入密码。但是好处是可以获得用户的授权,然后获取用户的openid或者unionid,而MICRO是不能拿到这个信息的。如果你需要根据openid追踪到系统内的用户时,这算是NATIVE的一个好处。

APP – APP支付

流程上其实和JSAPI很类似,都是获得预支付ID(prepayID)然后在APP内完成。在服务端接收付款通知,最好在APP里再进行一下确认。

WEAPP – 小程序支付

和JSAPI一样,只是支付参数(package)放的地方不同,一个是网页,一个是小程序内。

解决微信小程序sdk在升级到php7.1后的一个问题

升级php7.1以后,来自微信官方的小程序解密代码会提示:

mcrypt_module_close deprecated

意思就是php7.1-mcrypt已经即将废弃了,不推荐使用了。

解决的办法:

1. 使用替代库:composer require phpseclib/mcrypt_compat

2. 同时删除原来的php7.1-mcrypt:apt remove php7.1-mcrypt,不删除会继续报错。

复杂度其实是降维

突发奇想(可能也没啥新奇的,也许就是无知而已)

其实代码中控制复杂度的过程就是降维,或者说把一个复杂的结构用多项式来标识,每个项就是一个类(对象),然后把他们加起来。

如果做不到这一点,那么代码的复杂度将不可控,整个系统也就越来越不可控,最终烂掉。

貌似,代码也有它的生命周期,很少有代码能够“活到”足够长的时间,而变得不可控。

想象,一个函数,里面是一大堆的ifelse语句,每个if就是一个分支,每个分支就是一个乘法,每多一个乘法就是一个新的维度。所以我们常常将函数拆分成若干个对象的组合(通常是加法)。

不能忽视懒B的勤奋程度

在微信提供的PHPSDK开发代码里发现有一段代码,为了转换字符串,而把对象放到数组里再拿出来。

怎么能想出来的~ 用常规的方法不好吗?

能琢磨出这种办法的人,微信应该fire掉吧。话说回来,看来是完全没有code review啊。

有感。

给数据穿上裤子

最近华住又被拖库了,5亿的个人数据就这么泄漏了。感觉好卑微,原来每个人不过是一条数据。

怎么解决这个问题呢?

被“拖库”泄漏数据的原因是:敏感信息在数据库中明文存储。那么很自然的想法是:给数据“穿上裤子”,也就是进行加密。

比如:

电话号码:18633334444 变成 186aaaabbbb ,这里示范的是最简单的字符替换,这种算法也叫凯撒密码。

通过在加密中添加salt来避免太容易的解码,但貌似无济于事。

普通的凯撒加密可以容易地推算出来,即便是更加复杂的加密方式,人家已经获取到数据了,大不了费点事而已,毕竟是对称加密的。

话说回来,如果代码都已经被拖走了,貌似也没什么救了。

但是,对敏感数据进行部分加密还是有意义的,比如,不会容易被“撞库”。

另外,对于数据的提取,毕竟有时候会需要用户的联系方式进行短信营销,以前的做法(也说明了我们对用户的隐私是多么无视)是:直接从数据库里把数据导出来,然后交给短信发送供应商或者程序员通过短信发送接口进行批量发送。这么人的操作很难避免数据不外露,尤其是不靠谱的短信供应商。

所以,从运营的角度来说,也要通过流程来避免人为的数据泄漏。可以通过开发专用的“数据提取”功能来根据权限来获取敏感数据,同时记录下获取历史记录。就算追查追究法律责任时也是有据可查,光是这个“可追溯”也可以很大情况下避免人为泄漏。

顺道发现了一个很不错的关于数据加密的网站:https://www.dcode.fr/