CRCMS

高山仰止,景行行止,虽不能至,心向往之

大道至简


Laravel env 下特殊字符的坑

简述

今天在部署服务器时,线上数据库使用了特殊字符,结果导致mysql连接一直是出错的状态。
通过my-cli连接却是OK,于是想到是否是帐号密码错误,打印下envconfig,发现因为出现了#字符,后面被自动截断。

解决

第一反应是对于特殊字符如# \,应该加上"",测试下确实得到解决。

调试

首先想到肯定是在加载env,定位Bootstrap/LoadEnvironmentVariables

1
2
3
4
5
try {
$this->createDotenv($app)->safeLoad();
} catch (InvalidFileException $e) {
$this->writeErrorAndDie($e);
}

继续往下,定位safeLoad

1
2
3
4
5
6
7
8
9
public function safeLoad()
{
try {
return $this->loadData();
} catch (InvalidPathException $e) {
// suppressing exception
return [];
}
}

再通过loadData往下:

1
2
3
4
5
6
public function load()
{
return $this->loadDirect(
self::findAndRead($this->filePaths)
);
}

最终通过processEntries定位,找到处理value的核心方法

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
private static function parseValue($value)
{
if ($value === null || trim($value) === '') {
return $value;
}

return array_reduce(str_split($value), function ($data, $char) use ($value) {
switch ($data[1]) {
case self::INITIAL_STATE:
if ($char === '"' || $char === '\'') {
return [$data[0], self::QUOTED_STATE];
} elseif ($char === '#') {
return [$data[0], self::COMMENT_STATE];
} else {
return [$data[0].$char, self::UNQUOTED_STATE];
}
case self::UNQUOTED_STATE:
if ($char === '#') {
return [$data[0], self::COMMENT_STATE];
} elseif (ctype_space($char)) {
return [$data[0], self::WHITESPACE_STATE];
} else {
return [$data[0].$char, self::UNQUOTED_STATE];
}
case self::QUOTED_STATE:
if ($char === $value[0]) {
return [$data[0], self::WHITESPACE_STATE];
} elseif ($char === '\\') {
return [$data[0], self::ESCAPE_STATE];
} else {
return [$data[0].$char, self::QUOTED_STATE];
}
case self::ESCAPE_STATE:
if ($char === $value[0] || $char === '\\') {
return [$data[0].$char, self::QUOTED_STATE];
} else {
throw new InvalidFileException(
self::getErrorMessage('an unexpected escape sequence', $value)
);
}
case self::WHITESPACE_STATE:
if ($char === '#') {
return [$data[0], self::COMMENT_STATE];
} elseif (!ctype_space($char)) {
throw new InvalidFileException(
self::getErrorMessage('unexpected whitespace', $value)
);
} else {
return [$data[0], self::WHITESPACE_STATE];
}
case self::COMMENT_STATE:
return [$data[0], self::COMMENT_STATE];
}
}, ['', self::INITIAL_STATE])[0];
}

可以看到对于#\的处理。

关于array_reduce函数,请参考文档