0%

homebrew

在centos上有yum,ubuntu上有apt,而mac则是brew。这个并不是内置的。需要在终端执行命令进行安装。命令如下:

1
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

安装之后就可以像是linux一样使用包管理了。包的列表可浏览 https://formulae.brew.sh/formula/

nginx

安装命令:

1
brew install nginx

启动nginx

1
brew services start nginx

重启nginx

1
brew services restart nginx

停止nginx

1
brew services stop nginx

PHP

安装

1
brew install php

启动php

1
brew services start php

重启php

1
brew services restart php

停止php

1
brew services stop php

MySQL

安装

1
brew install mysql

启动命令

1
brew services start mysql

重启命令

1
brew services restart mysql

停止命令

1
brew services stop mysql

设置密码

首先启动mysql服务器,然后执行

1
mysql_secure_installation

如果出现如下内容:

1
2
3
4
5
6
VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?

Press y|Y for Yes, any other key for No:

表示询问你是否需要安装密码验证插件,这里我输入y允许安装了。

接下来

1
2
3
4
5
6
7
There are three levels of password validation policy:

LOW Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG:

这里是要求制定密码强度,我这里选择是0,

接下来就是让我输入两边密码了,

因为我输入的密码比较简单,所以有了如下提示:

1
2
Estimated strength of the password: 50
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) :

提示说这个密码的强度不高,询问是否真的使用这类强度的密码呢?我选择使用。

1
Remove anonymous users? (Press y|Y for Yes, any other key for No) :

是否移除匿名用户?肯定要移除啊。

1
Disallow root login remotely? (Press y|Y for Yes, any other key for No) :

是否禁用root远程登录呢?肯定要禁用啊。

1
Remove test database and access to it? (Press y|Y for Yes, any other key for No) :

是否要移除test数据库(这是一个测试数据库)呢?肯定要移除。

1
Reload privilege tables now? (Press y|Y for Yes, any other key for No) :

是否要重载权限表。嗯,要重载。

然后设置就完成了。

接下来我们就可以使用如下命令登录mysql了。

1
mysql -uroot -p

登录验证插件

这里有个小问题,就是mysql的身份验证插件从之前的mysql_native_password更新为caching_sha2_password

目前的PHP并不支持更新后的插件,所以可以参考我如下的文章使用之前的身份验证插件创建用户密码。

具体可以参考我的这一篇文章《数据库升级》.

组合

安装完成后,其实nginx并不能直接和php进行通信。一般通信的方式有两种,一种是通过监听端口(默认9000),一种是监听socket。这里我们使用监听端口的方式。

因为php-fpm这边已经默认是监听127.0.0.1:9000端口了,所以这里只需要修改nginx配置即可。

首先打开/usr/local/etc/nginx/nginx.conf

修改后的配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# server 部分修改如下
server {
listen 80; # 修改端口为80
server_name localhost;

charset utf-8; # 设置默认字符集为utf-8

#access_log logs/host.access.log main;

root html;
index index.php index.html index.htm; # 新增index.php

location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; // 修改`/script`为`$document_root`,该值为root定义的路径
include fastcgi_params;
}
}

然后打开/usr/local/var/www目录,新增index.php文件,内容如下:

1
2
<?php
phpinfo();

使用如下命令重启nginx

1
brew services restart nginx

最后访问localhost就可以看到phpinfo正确显示的网页了。

参考

有时候,在登录到云服务器之后,可能需要在终端查询该服务器的ip。

之前我都是用的 ip.cn ,但是感觉不行了。

现在提供一些其他的可选择项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ curl ipinfo.io
{
"ip": "60.205.205.243",
"city": "",
"region": "",
"country": "CN",
"loc": "34.7725,113.7270",
"org": "AS37963 Hangzhou Alibaba Advertising Co.,Ltd."
}
$ curl cip.cc
IP : 60.205.205.243
地址 : 中国 北京
运营商 : 阿里云/电信/联通/移动/铁通/教育网

数据二 : 北京市 | 阿里云BGP服务器

数据三 : 中国北京北京市 | 阿里云

URL : http://www.cip.cc/60.205.205.243
$ curl myip.ipip.net
当前 IP:60.205.205.243 来自于:中国 北京 北京 阿里云/电信/联通/移动/铁通/教育网
# curl ifconfig.me
60.205.205.243
$ curl http://members.3322.org/dyndns/getip
60.205.205.243

相信还有这么多的URL。估计哪一个不行了,都能找到可替代的了。

在windows环境中,我们都是可以通过xshell实现证书登录的。

但是在mac中却没有相关的设置,那么如何使用mac进行证书登录呢。

首先,我们需要有一个私钥文件。

比如我的是aliyun.pem.

我将其存放在/home/baoguoxiao/aliyun.pem

登录的命令则是如下这条:

1
ssh -i /home/baoguoxiao/aliyun.pem root@ip

执行该命令的时候可能会提示如下错误:

1
Permissions 0755 for '/home/baoguoxiao/aliyun.pem' are too open.

这个表示我们给与这个文件的权限太大了,所以需要对其设置只读权限。

执行如下命令:

1
chmod 400 /home/baoguoxiao/aliyun.pem

然后再次使用如上的ssh命令,就可以顺利的登录阿里云服务器了。

这样真的好棒。妈妈再也不用担心我的学习。

参考

有时候我们可能需要向html中传递html代码。但是因为我们的后台框架使用了laravel。所以我们在赋值的时候就会变成:

1
{{$username}}

虽然我们使用自带的非转义的赋值方法:

1
{!! $username !!}

但是我的需求却是不能使用后面的这类方法。

通过谷歌,我了解到一种完美的办法,可以将转义后的代码再次转回来。

代码如下:

1
2
3
4
5
function htmlDecode(input){
var e = document.createElement('div');
e.innerHTML = input;
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}

我们只需要调用该方法就可以完美执行反转义了:

1
2
htmlDecode("&lt;img src='myimage.jpg'&gt;"); 
// returns "<img src='myimage.jpg'>"

参考

今天下午一直在跟安卓调试sentry适配问题。发现了两个问题。现在记录如下:

红米一直安装不上APP

在开发的时候,发现红米一直安装不上APP。经过百度查询,发现是在开发设置中打开了启用MIUI优化设置,将其关掉,然后重启,然后接着开启USB安装,之前因为一直没网,没有注意这个,导致一些隐性的bug没有展示出来,粗心啊。

安装页面没有DSN信息

一般在安装页面都会介绍DSN信息,但是安卓病没有提示,顿时不知道这个URL应该去哪找到了,在翻了好久之后,终于找到了位置。

路径为: Project details -> Settings -> Client Keys(DSN)

在这里面就可以拿到相关的DSN信息。

官网提供的SDK不可用

这个问题就非常坑了。官网提供的SDK根本不可用,最后我们各种谷歌之后,终于发现了问题,原来该SDK已经在2013年就不维护了,必须转而使用raven-java。

现在粘贴相关代码:

Gradle

1
compile 'com.getsentry.raven:raven-android:8.0.1' # 实测compile不可用,必须替换为 api

Permissions

1
2
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

实例化

1
2
3
4
import com.getsentry.raven.android.Raven;

Context ctx = this.getApplicationContext();
Raven.init(ctx, "YOUR-SENTRY-DSN");

捕获错误

1
2
3
4
5
6
try {
String json = "['a']";
JSONObject jsonObject = new JSONObject(json); // 示例错误
} catch (Exception e) {
Sentry.capture(e);
}

在测试过程中发现,接收到的错误信息有时候很及时,有时候就非常慢。推测可能是因为APP崩溃退出了,导致错误信息没有及时发出,所以会在下一次APP启动的时候,将相关的错误数据送出, 这样导致sentry接收到错误消息的时间较晚。

参考URL

在安装docker-compose之前必须先检查是否已经安装好了docker。具体安装教程可阅读 docker学习笔记之一 安装

运行此命令下载最新版本的docker-compose

1
sudo curl -L "https://github.com/docker/compose/releases/download/1.23.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

可以看到我们上面下载的版本是1.23.1。这个可能很快就过期了,这个时候可以查看Releases页面了解最新发布的版本,然后将最新发布的版本号替换上面命令中已知的版本号进行下载。

接下来我们对其设置执行权限

1
sudo chmod +x /usr/local/bin/docker-compose

好了,这样就安装完成了。是不是非常简单。

最后我们检查看版本。

1
2
$ docker-compose --version
docker-compose version 1.23.1, build b02f1306

end.

Linux 与客户端之间进行文件互传是一个非常常见的功能。办法有很多,很多都是借助第三方功能,但是如果要求不使用第三方工具,那么可选项就很少了。下面介绍两种办法:

lrzsz

其实我最钟意这个了。但是这个认终端。需要终端进行适配才可以。

该命令对文件大小有限制,最大不能超过 4GB。我想一般人碰到这么大的文件,早就去想其他办法了吧。

使用如下命令安装:

1
dnf install lrzsz
  • 使用方法:

上传文件:

1
rz

下载文件:

1
sz /path/file

scp

这个其实就比 lrzsz 比较通用了。但是问题是每次我都得查询一下命令是啥。一般想不起来。

下载文件从远程服务器到本地目录:

1
scp user@ip:/path/file /path

上传文件从本地目录到远程服务器:

1
scp /path/file user@ip:/path 

参考

简介

开源错误跟踪,帮助开发人员实时监控和修复崩溃。不断重复。提高效率。改善用户体验。

特性

  • 相同错误合并
  • 定制规则进行邮件通知
  • 支持导入sourcemap自动解析和还原代码
  • 多项目,多用户
  • 友好的Web界面
  • 支持主流的语言接口
  • 权限管理
  • 敏感信息过滤
  • 受影响用户统计
  • WEB可视化设置,功能强大

部署

使用docker-compose命令一键进行部署。减少部署的错误率。

具体部署程序可查看getsentry/onpremise

使用nginx接受请求并对其进行转发。并使用了ngx_http_realip_module模块转发真实请求IP。

流程

sentry分为客户端和服务端。客户端嵌入到App中,当应用发生异常的情况时,就会向服务器端发送异常通知,服务器端则将信息记录到数据库汇总,并提供web方式,方便对异常进行查看和分析,避免需要登录服务器后台查看生硬的log文件。

收集日志

  • 客户端运行错误日志
    • Android
    • IOS
    • HTML
  • 服务器端项目运行错误日志
    • PHP
  • Web环境错误日志
    • PHP-fPM错误日志
    • Nginx错误日志

目前的日志捕获,都有相应的SDK,非常方便,不同的是客户端因为有代码混淆,所以,需要在sentry中上传相应sourcemap文件。

目前的PHP-FPM和Nginx错误日志没有现成的代码,这里需要一些时间进行编写代码处理相关错误。

适配

目前sentry有很多的SDK包。目前已经覆盖咱们产品线的有:

  • Android
  • Swift
  • Objective-C
  • JavaScript
  • PHP
  • Laravel

组织架构

角色

行为[Action] 会员[Member] 管理员[Admin] 经理[Manager] 所有者[Owner ]
Can view and act on issues, such as assigning/resolving/etc. ✔️ ✔️ ✔️ ✔️
可以加入和离开团队[Can join and leave teams] ✔️ ✔️ ✔️ ✔️
可以修改项目设置[Can change Project Settings] ✔️ ✔️ ✔️
可以添加/删除项目[Can add/remove projects] ✔️ ✔️ ✔️
可以编辑全局集成[Can edit Global Integrations] ✔️ ✔️
可以添加/删除/修改成员[Can add/remove/change members] ✔️ ✔️
可以添加/删除团队[Can add/remove teams] ✔️ ✔️
可以添加仓库[Can add Repositories] ✔️ ✔️
可以改变组织设置[Can change Organization Settings] ✔️ ✔️
可以移除一个组织[Can remove an Organization] ✔️

归属关系

一个组织对应多个团队
一个团队对应多个项目
一个团队对应多个会员
一个会员属于多个团队
一个项目属于一个团队

邮件通知

默认情况下,一旦异常发生,5分钟内就会有一封邮件发送到你的邮箱。包含了异常的大致描述。

目前的默认规则是当出现一个新的规则时候,30分钟内发送一次邮件通知。

对于发送邮件的规则可以进行新增/编辑/移除。

限制

  • 不能作为日志的替代品。
    sentry主要是为让我们专注于系统和程序的异常信息,提高排查效率,日志事件的量达到一个限制值的时候可能还会丢弃一些内容。官方也提倡正确设置sentry接收的日志level的等级时,也能继续旧的日志备份。
  • 不是排查的万能工具
    sentry是带有问题聚合功能的分析工具,所以如果样本提供的内容不全面。日志记录的质量不高的情况,对于错误的快速排查,可能没有实质性的帮助。
  • 不能作为传统监控的替代品
    与传统监控系统相比,sentry更依赖发出的日志报告,而另外一些隐藏的逻辑问题或者业务问题可能不会得到反馈的。

sentry一个最大的好处就是可以使用邮件通知功能,如果没有邮件通知,那么我们自己上去看的话就非常麻烦了。

进行邮件推送需要我们提供邮件服务器。这里的话,我就用的是腾讯企业邮箱。

好了,下面说具体配置。

首先接上一篇文章 安装sentry,我们将代码拉取到的目录是/data/sentry

接下来我们就要里面这个文件夹里面的docker-compose.yml文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
x-defaults: &defaults
restart: unless-stopped
build: .
depends_on:
- redis
- postgres
- memcached
- smtp
env_file: .env
environment:
SENTRY_MEMCACHED_HOST: memcached
SENTRY_REDIS_HOST: redis
SENTRY_POSTGRES_HOST: postgres
# 从这里开始
SENTRY_EMAIL_HOST: smtp.exmail.qq.com
SENTRY_EMAIL_USER: example@mail.com
SENTRY_SERVER_EMAIL: example@mail.com
SENTRY_EMAIL_PASSWORD: password
SENTRY_EMAIL_USE_TLS: true
SENTRY_EMAIL_PORT: 587
# 这里结束
volumes:
- sentry-data:/var/lib/sentry/files

这里介绍一下每个配置项的作用:

配置项 作用 腾讯企业邮
SENTRY_EMAIL_HOST SMTP服务器地址 smtp.exmail.qq.com
SENTRY_EMAIL_USER 登录的邮箱账号 example@mail.com
SENTRY_EMAIL_PASSWORD 登录的邮箱密码 password
SENTRY_EMAIL_PORT 登录的端口 587
SENTRY_EMAIL_USE_TLS 是否使用ssl连接 true
SENTRY_SERVER_EMAIL 发送的账户,跟SENTRY_EMAIL_USER相同 example@mail.com

配置完成之后,需要重建服务。具体可以执行以下命令:

1
2
docker-compose down
docker-composer up -d

然后稍等一分钟就可以正常访问web页面了。

现在来测试一下。

进入页面,在左上角的你的昵称位置单击,选择Admin。

然后在左侧选择Mail,然后在最下面有一个测试设置。点击“向example@mail.com发送一封测试邮件”。如果收到的话,那么说明就配置成功了。

在配置问题中,如果有什么问题,可以过来跟我留言。

毕竟这个邮件通知我折腾了一下午才搞定。

哈哈

最近公司内部需要新增一个日志系统。目前可选择的就是sentry和阿里云日志系统。我通过两个对比之后,感觉sentry日志更加好用。所以在这里记录一下相关的笔记。首先这一篇就是安装系列了。

前置条件

  • docker
  • docker-compose
  • git

安装

接下来的安装命令就非常简单了。

首先我们先创建目录:

1
mkdir /data

然后拉取命令

1
git clone https://github.com/getsentry/onpremise sentry

然后进入目录

1
cd sentry

首先我们修改一下映射端口。因为默认绑定端口是9000,因为我这台电脑启动了php-fpm服务绑定了9000端口,所以我这里需要将9000改成10000。具体相关配置如下:

1
2
3
4
5
6
# docker-compose.yml

web:
<<: *defaults
ports:
- '10000:9000' # 修改位置

好了,接下来就是创建volumn。

1
docker volume create --name=sentry-data && docker volume create --name=sentry-postgres

生成配置文件

1
cp -n  .env.example .env

创建服务

1
docker-compose build

生成秘钥

1
docker-compose run --rm web config generate-secret-key

将生成的秘钥添加到.env中的SENTRY_SECRET_KEY项。

构建数据库

1
docker-compose run --rm web upgrade

启动所有服务

1
docker-compose up -d

好了,这样sentry就安装完成了。

Nginx转发

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name abc.example.com;

location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host-Real-IP $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-Pcol http;
proxy_pass http://localhost:10000;
}
}

这样我们就可以使用绑定的域名进行访问了。

端口安全

使用netstat命令查询端口状态:

1
2
# netstat -ntlp | grep 10000
tcp6 0 0 :::10000 :::* LISTEN 22354/docker-proxy

发现这个并没有绑定127.0.0.1。这里我并没有研究好如何绑定127.0.0.1。这里可以通过防火墙进行端口控制。比如阿里云的入网端口管理,或者centos的firewalld命令都可以进行控制。具体就不展开了。

PS:明天具体写如何配置邮件发送。

我在安装php-zip扩展的时候提示以下错误消息:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ sudo apt install php-zip
Reading package lists... Done
Building dependency tree
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
php-zip : Depends: php7.2-zip but it is not going to be installed
E: Unable to correct problems, you have held broken packages.

通过谷歌,发现解决错误的方式很简单。

首先打开vi /etc/apt/sources.list,然后修改里面的内容如下所示:

1
2
3
deb http://archive.ubuntu.com/ubuntu bionic main universe
deb http://archive.ubuntu.com/ubuntu bionic-security main universe
deb http://archive.ubuntu.com/ubuntu bionic-updates main universe

执行:

1
sudo apt update 

然后执行安装命令就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
$ sudo apt install php-zip
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
libzip4 php7.2-zip
The following NEW packages will be installed:
libzip4 php-zip php7.2-zip
0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
Need to get 63.9 kB of archives.
After this operation, 204 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://archive.ubuntu.com/ubuntu bionic/universe amd64 libzip4 amd64 1.1.2-1.1 [37.8 kB]
Get:2 http://ppa.launchpad.net/ondrej/php/ubuntu bionic/main amd64 php7.2-zip amd64 7.2.10-1+ubuntu18.04.1+deb.sury.org+1 [20.3 kB]
Get:3 http://ppa.launchpad.net/ondrej/php/ubuntu bionic/main amd64 php-zip all 1:7.2+62+ubuntu18.04.1+deb.sury.org+3 [5,840 B]
Fetched 63.9 kB in 2s (39.4 kB/s)
Selecting previously unselected package libzip4:amd64.
(Reading database ... 102709 files and directories currently installed.)
Preparing to unpack .../libzip4_1.1.2-1.1_amd64.deb ...
Unpacking libzip4:amd64 (1.1.2-1.1) ...
Selecting previously unselected package php7.2-zip.
Preparing to unpack .../php7.2-zip_7.2.10-1+ubuntu18.04.1+deb.sury.org+1_amd64.deb ...
Unpacking php7.2-zip (7.2.10-1+ubuntu18.04.1+deb.sury.org+1) ...
Selecting previously unselected package php-zip.
Preparing to unpack .../php-zip_1%3a7.2+62+ubuntu18.04.1+deb.sury.org+3_all.deb ...
Unpacking php-zip (1:7.2+62+ubuntu18.04.1+deb.sury.org+3) ...
Processing triggers for php7.2-fpm (7.2.10-1+ubuntu18.04.1+deb.sury.org+1) ...
Setting up libzip4:amd64 (1.1.2-1.1) ...
Processing triggers for libc-bin (2.27-3ubuntu1) ...
Setting up php7.2-zip (7.2.10-1+ubuntu18.04.1+deb.sury.org+1) ...

Creating config file /etc/php/7.2/mods-available/zip.ini with new version
Setting up php-zip (1:7.2+62+ubuntu18.04.1+deb.sury.org+3) ...
Processing triggers for php7.2-fpm (7.2.10-1+ubuntu18.04.1+deb.sury.org+1) ...

参考

对于程序员来说,有哪些书籍是必读的呢?Stack Overflow 上有一个问题,虽然被关闭了,但是这是设置一个热门的问题。我看到里面推荐的书都是英文的。所以对照着找了找国内的中文版。但是也是有一些翻译的名字我确实没有找到或者暂时还没有出中文版。所以在其中有什么错误的地方,请大家评论告诉我,我立即去更新。

图书目录

如果对多音字要求不高的话。可以使用如下方法:

1
2
3
4
5
$id = 'Any-Latin; NFD; [:Nonspacing Mark:] Remove; NFC; [:Punctuation:] Remove; Lower();';
$transliterator = Transliterator::create($id);

$string = "garçon-étudiant-où-L'école";
echo $transliterator->transliterate($string); // garconetudiantoulecole

使用的什么原理,我还不清楚,具体可以等以后再去了解。

参考地址

这两天一直在看react。今天正好想着安装 react-native ,看看传说中的用JS写APP能用嘛。

接下来就是介绍使用情况。首先就是搭建NodeJS和JAVA环境。

创建项目:

1
2
3
react-native init fiction
cd fiction
react-native run-android

当然中间第一次运行的时候会去谷歌下载一些包。这些就不表了。

接下来主要是表述一下中间遇到的坑。

unable to load script from assets ‘index.android.bundle’

其实解决的办法很简单:

首先在android/app/src/main创建assets文件夹,然后执行以下命令:

1
2
3
yarn add @babel/runtime --dev

react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res

执行完成后,再次执行react-native run-android就能看到美丽的开机页面了。

记录一下自己使用docker安装mysql的过程。

首先我找到两个:

我对比了一下。发现第一个是mysql官方推出的,而第二是docker自带library推出的。那么我肯定选择mysql官方推出的mysql了。

既然确定了要安装的包,那么就要开始拉取了。

  • MySQL Server 5.5 (tag: 5.5, 5.5.61, 5.5.61-1.1.7) (mysql-server/5.5/Dockerfile)
  • MySQL Server 5.6 (tag: 5.6, 5.6.41, 5.6.41-1.1.7) (mysql-server/5.6/Dockerfile)
  • MySQL Server 5.7 (tag: 5.7, 5.7.23, 5.7.23-1.1.7) (mysql-server/5.7/Dockerfile)
  • MySQL Server 8.0, the latest GA (tag: 8.0, 8.0.12, 8.0.12-1.1.7, latest) (mysql-server/8.0/Dockerfile)
  • MySQL Server 8.0 for AArch64 (ARM64) (tag: 8.0-aarch64, 8.0.12-aarch64)

上面是可以安装的版本。那么我肯定是安装latest的。

安装

那么执行代码如下:

1
docker pull mysql/mysql-server

如果想要安装5.7版本的,可以执行以下命令:

1
docker pull mysql/mysql-server:5.7

好了等待之后,就安装成功了,接下来,我们看看我们在本地存储的镜像。

1
2
3
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql/mysql-server latest 1fdf3806e715 5 weeks ago 309MB

接下来执行创建容器的命令。

1
docker run --name mysql1 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql/mysql-server:latest

在这里要注意的是最后的:latest,这个是可省略的。如果刚才安装的是指定版本,比如5.7,那么我们就需要执行以下命令了:

1
docker run --name mysql1 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql/mysql-server:5.7

好了,安装完成,就可以使用PHP进行连接测试了。

1
2
3
4
5
$pdo = new \PDO("mysql:host=127.0.0.1;dbname=mysql", "root", "123456");
$data = $pdo->query("select version()");
foreach($data as $item) {
var_dump($item);
}

会提示如下错误:

1
Host '172.17.0.1' is not allowed to connect to this MySQL server

那么我们只能登录mysql进行修改数据了,首先是登录mysql,密码就是我们设置的123456:

1
2
$ docker exec -it mysql1 mysql -uroot -p
Enter password:

然后执行如下命令:

1
2
3
use mysql;
update user set host = '%' where user = "root";
flush privileges;

我们继续测试PHP脚本,发现链接就正常了:

1
2
3
4
5
6
7
8
$ php ./demo.php
/Users/baoguoxiao/demo.php:5:
array(2) {
'version()' =>
string(6) "8.0.12"
[0] =>
string(6) "8.0.12"
}

查询日志

1
docker logs mysql1

登录shell

1
docker exec -it mysql1 bash

停止容器

1
docker stop mysql1

开启容器

1
docker start mysql1

重启容器

1
docker restart mysql1

删除容器

1
2
docker stop mysql1
docker rm mysql1

从另外的容器中连接mysql

暂无

Docker 环境变量

其实我们在创建container的时候就已经用了一个环境变量了,就是MYSQL_ROOT_PASSWORD,现在我们来介绍一些其他的环境变量

  • MYSQL_RANDOM_ROOT_PASSWD

    该值默认为ture(除非MYSQL_ROOT_PASSWORD设置了或者MYSQL_ALLOW_EMPTY_PASSWORD设置为true了),意思是在启动docker容器时随机生成root密码。密码打印到日志中。查看随机密码的方式如下:

    1
    2
    $ docker logs mysql1 2>&1 | grep GENERATED
    GENERATED ROOT PASSWORD: Axegh3kAJyDLaRuBemecis&EShOs
  • MYSQL_ONETIME_PASSWORD

    默认为ture(除非MYSQL_ROOT_PASSWORD设置了或者MYSQL_ALLOW_EMPTY_PASSWORD设置为true了)root用户的密码设置为expired,必须先修改密码才能使用。

  • MYSQL_DATABSE

    指定在容器创建时同时创建数据库的名称。如果启动参数也有MYSQL_USERMSQL_PASSWORD,则会创建用户并授予该数据库对应的用户权限。如果指定的数据库已经存在了,则该变量无效。

  • MYSQL_USER和MYSQL_PASSWORD

    该变量用户创建用户名和密码,并为该用户授予MYSQL_DATABASE变量指定的数据库的超级用户权限。如果两个变量没有设置,则其他会被忽略。如果两个变量都已设置但是没有设置MYSQL_DATABASE,则创建的用户没有任何权限。

  • MYSQL_ROOT_HOST

    默认情况下,MySQL会设置”root@localhost”账户,此账户只能从内部进行连接。要允许其他主机的根连接,就需要设置此变量了。例如,该值172.17.0.1(默认的docker网关IP)允许来自运行容器的主机的连接。但是该选项仅接受一条记录,但是允许使用通配符(例如,MYSQL_ROOT_HOST=172...*或MYSQL_ROOT_HOST=%)。

  • MYSQL_LOG_CONSOLE

    当变量为true时(MySQL8.0服务器容器的默认状态),MySQL服务器的错误日志被重定向到stderr,以便错误日志进入docker容器的日志,并且可以使用docker logs mysqld-container进行查看。

  • MYSQL_ROOT_PASSWORD

    此变量指定为MySQL root账户设置的密码。在命令行上设置MySQL root密码是不安全的,因为可以通过history查看命令历史从而获取创建的密码。所以最好是试用默认设置。

  • MYSQL_ALLOW_EMPTY_PASSWORD

    默认为false,如果将其设置为true,则表示允许root用户使用空密码启动。但是在非开发环境设置此变量为true是不安全的,因为他会让MySQL实例完全不受保护,从而允许任何人都可以获得弯针的超级用户访问权限。最好试用默认设置。

首先介绍一下环境。

数据库:RDS(阿里云)-5.6
PHP:PHP7.2 + Lumen
系统:Ubuntu

1
2
3
4
5
6
$time = date('Ymd');
$pdo = new PDO("dns", "user", "password");
$data = $pdo->query("select * from table where date_format(from_unixtime(addtime),'%Y%m%d') = '{$time}'");
foreach($data as $item) {
var_dump($data);
}

我们有一条上面的查询语句。在开发的时候没有任何问题,但是代码在上线后,突然爆出不能正确的查出相应的数据。但是数据确实存在。

当时我们处理这个问题是凌晨1点,并且是在家里。考虑可能是时区问题,但是因为太晚了,所以我们使用了另外一种方式去避免这个问题。并没有追查这个事情的具体原因。

正好白天有一点空闲,所以准备排查一下这个问题。

我的第一考虑就是时区的问题,但是我自己执行以下的查询语句,却是发现没有问题。

1
2
3
4
5
$pdo = new PDO("dns", "user", "password");
$data = $pdo->queru("select now()");
foreach($data as $item) {
var_dump($data);
}

所以我把目标转向了lumen这个框架,我通过查询源码,发现有这么一段源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// file_path: vendor/illuminate/database/Connectors/MySqlConnector.php
/**
* Set the timezone on the connection.
*
* @param \PDO $connection
* @param array $config
* @return void
*/
protected function configureTimezone($connection, array $config)
{
if (isset($config['timezone'])) {
$connection->prepare('set time_zone="'.$config['timezone'].'"')->execute();
}
}

然后我就去看我的数据配置,找到这里:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// file path: config/database.php
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', 3306),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => env('DB_PREFIX', ''),
'timezone' => env('DB_TIMEZONE', '+00:00'), // 注意看这里
'strict' => env('DB_STRICT_MODE', false),
],

然后再次修改自己的SQL进行尝试:

1
2
3
4
5
6
$time = date('Ymd');
$pdo = new PDO("dns", "user", "password");
$data = $pdo->query("set time_zone= '+00:00'; select * from table where date_format(from_unixtime(addtime),'%Y%m%d') = '{$time}'");
foreach($data as $item) {
var_dump($data);
}

发现时间就会变成CST时间了。

这样在该框架的路由中增加了该方法:

1
2
3
Route::get("/test", function() {
return \DB::select("select now()")->toArray();
});

发现返回的时间也是CST时间了。所以真相大白了。

我们上班的时间是白天十点以后,这样当天的时间减去八个小时候再去计算,最上面写的SQL中的where条件还是成立的,但是凌晨一点去计算的时候,却是查询的昨天的数据,所以where条件就不查询不到正确的数据了。

这个事情让我明白,要仔细了解一个框架,说不定一个小小的细节被遗漏,就会造成不可预料的后果。

问题

今天在进行Laravel开发的时候,发现了比较坑的一点。
按照默认情况来说,比如表单提交,如果我们提交了这个字段,但是这个字段为空字符串。在Laravel中会自动转义成Null。这个为什么呢?

原来Laravel有个全局中间件,代码如下图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

namespace Illuminate\Foundation\Http\Middleware;

class ConvertEmptyStringsToNull extends TransformsRequest
{
/**
* Transform the given value.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
protected function transform($key, $value)
{
return is_string($value) && $value === '' ? null : $value;
}
}

该中间件就会将空的参数值自动转为null。

那么对于这种问题应该如何解决呢?

方法1

我们再写一个中间件,替换之前的中间件,里面可以排除指定字段不转为null。里面的数组可以更改成你需要不转的字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// app/Http/Middleware/NinjaAuther.php 新增文件

namespace App\Http\Middleware;

class NinjaAuther extends TransformsRequest
{

/**
* Transform the given value.
*
* @param string $key
* @param mixed $value
* @return mixed
*/
protected function transform($key, $value)
{
if(is_string($value) && !in_array($key, ['abc'], true)) {
$value = $value === '' ? null : $value;
}

return $value;
}
}
1
2
3
4
5
6
7
8
9
10
// app/Http/Kernel.php 部分代码

protected $middleware = [
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
// \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, // 这一条注释掉
\app/Http/Middleware/NinjaAuther.class, // 新增的记录
\App\Http\Middleware\TrustProxies::class,
];

但是该中间件是全句性质的,所以我个人则更加倾向于第二种方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// app/Http/Controllers/StoreController.php

<?php

namespace App\Http\Controllers;

use App\Store;
use Illuminate\Http\Request;

class StoreController extends Controller
{
public function save(Request $request) {
$store = new Store();
$store->title = strval($request->input("title")); // 对获取的字段进行格式转换
$store->address = strval($request->input("address"));
$store->longitude = doubleval($request->input("longitude"));
$store->latitude = doubleval($request->input("latitude"));
$store->introduction = strval($request->input("introduction"));
$store->text = strval($request->input("text"));
$store->status = intval($request->input("status"));
$store->save();
}
}

如上面这样,对指定格式进行显示转换。写的多了,可能会显得繁琐一些。不过感觉比较看的明白。

上面这种方案如何解决,就看大家的喜好了。

参考

今天晚上去看服务器,发现数据库的版本是5.7的,看起来挺新的。但是MySQL已经出了8.0了,受不了心中的渴望,所以就直接把源切到8.0新版本了。中国有一些坑,在此记录一下。

升级之后wordpress不能连接,提示Error establishing a database connection

原因是mysql在更新之后,因为密码验证规则的修改,导致密码已经变成新版验证的密码了,但是PHP目前并不支持这个新版验证方式。所以解决办法就是使用指定的SQL进行修改密码。修改模式如下:

1
ALTER USER 'user'@'host' IDENTIFIED WITH mysql_native_password BY 'password';

这样就可以了,不过执行之后出现了另外一个错误。。。

执行设置密码SQL出现错误:ERROR 1146 (42S02): Table ‘mysql.role_edges’ doesn’t exist

原因就是升级数据库之后没有执行mysql_upgrade命令。

按照如下命令执行一下即可:

1
mysql_upgrade -uuser -p

执行完成之后,再次执行上面设置密码的命令,这样wordpress就可以正常访问了。

首先介绍一下我的环境。

我是在Windows10上进行开发。然后windows共享文件夹,ubuntu 18.04挂载共享文件夹。

环境:

  • Laravel 5.6
  • PHP 7.2.7
  • NodeJS 8.10.0
  • npm 3.5.2

还原场景:

在linux环境中执行npm install方法。会出现如下错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
npm WARN optional Skipping failed optional dependency /chokidar/fsevents:
npm WARN notsup Not compatible with your operating system or architecture: fsevents@1.2.4
npm WARN ajv-keywords@3.2.0 requires a peer of ajv@^6.0.0 but none was installed.
npm ERR! Linux 4.15.0-30-generic
npm ERR! argv "/usr/bin/node" "/usr/bin/npm" "install"
npm ERR! node v8.10.0
npm ERR! npm v3.5.2
npm ERR! path ../acorn/bin/acorn
npm ERR! code ENOTSUP
npm ERR! errno -95
npm ERR! syscall symlink

npm ERR! nospc ENOTSUP: operation not supported on socket, symlink '../acorn/bin/acorn' -> '/home/baoguoxiao/windows/food/node_modules/.bin/acorn'
npm ERR! nospc This is most likely not a problem with npm itself
npm ERR! nospc and is related to insufficient space on your system.

npm ERR! Please include the following file with any support request:
npm ERR! /home/baoguoxiao/windows/food/npm-debug.log

经过查询,发现是创建不能创建链接。经过查询,发现解决方法很简单。只要加上一个参数就好了。执行命令如下:

1
npm install -no-bin-links

错误很复杂,解决的办法却是很简单。

参考

昨天领导告诉我,要安装Horizon。但是我们使用的是lumen,官方的Horizon并不支持lumen。所以又去找第三方,结果发现已经八个月没有更新了。无奈尝试自己维护。发现一堆坑。根本填不完。今天早上想着去packagist去淘淘。还真让我发现了一个正在维护的:horizon-lumen

一切安装就按照README.md上面的步骤进行安装就好了。

再此说下,中间碰到的坑。

在执行如下命令:

1
php artisan vendor:publish --provider="Laravel\Horizon\HorizonServiceProvider"

出现如下错误:

1
2
3
In Facade.php line 218:

A facade root has not been set.

经过查询发现解决方案是在boorstrap/app.php中的注释:

1
$app->withFacades(); // 去掉这一行的注释

我发现这一行已经开启了,但是还是出现这个错误。然后我发现这一块的代码几乎放在了该文件的最后,所以我将其提到了文件的最前面,如下所示:

1
2
3
4
5
6
7
8
$app->withEloquent(); // 这一行的下面

$app->withFacades(true,[
'Tymon\JWTAuth\Facades\JWTAuth' => 'JWTAuth',
'Tymon\JWTAuth\Facades\JWTFactory' => 'JWTFactory',
'ZanySoft\Zip\ZipFacade' => 'Zip',
App\Providers\RongCloudServiceProvider::class => 'RongCloud',
]);

这样就能正常安装上了。

还有一个问题是在访问仪表盘的时候,结果html代码是以文本来显示的。并没有使用html的方式展示内容。

经过分析,发现返回的header中没有Content-type选项。

所以写了一个中间件。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
/**
* file path: app/Http/Middleware/HtmlMiddleware.php
*/
namespace App\Http\Middleware;
use Closure;

class HtmlMiddleware
{
/**
* 运行请求过滤器
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
if (is_null($response->headers->get("Content-Type"))) { // 当为空的时候才会添加header
$response->header("Content-Type", "text/html; charset=UTF-8");
}

return $response;
}
}

因为我这边使用了dingo,所以加上如上判断。

最后修改bootstrap/app.php中的一处:

1
2
3
$app->middleware([
\App\Http\Middleware\HtmlMiddleware::class,
]);

一切大功告成。

后记:

在分享给同事使用的时候,同事说出现这么一个错误:

1
The Mix manifest does not exist

在我本地是正常啊,为啥同事就是不行呢。研究了半天。发现原因了。

因为在public文件夹里面有vendor文件夹。但是正好.gitignore中有一条规则将vendor/给忽略了。所以需要执行以下命令:

1
git add public/vendor -f # 强制加入git版本追踪

提交之后,让同事拉取代码,再去执行就可以了。