我尝试使用DBI
和DBD::Pg
连接SSL客户端密钥。
use strict;
use warnings 'all';
use DBI;
my $dsn = "dbi:Pg:db=mydb;sslmode=require;host=localhost;"
."sslcert=C:\\path with\\spaces.crt;"
."sslkey=C:\\path with\\spaces.key";
my $dbh = DBI->connect( $dsn, 'username', '' );
我收到以下错误:
Can't connect to database: missing "=" after "with\spaces.crt" in connection info string!
我尝试在值周围使用单引号或双引号无效,我在文档中找不到任何内容。
单引号如下:
my $dsn = "dbi:Pg:db=mydb;sslmode=require;host=localhost;"
."sslcert='C:\\path with\\spaces.crt';"
."sslkey='C:\\path with\\spaces.key'";
我收到以下错误:
failed: FATAL: connection requires a valid client certificate
我知道这种配置有效,因为它适用于Python。
事实证明这有效:
my $dsn = "dbi:Pg:db=mydb;sslmode=require;host=localhost;"
."sslcert='C:\\\\path with\\\\spaces.crt';"
."sslkey='C:\\\\path with\\\\spaces.key'";
为什么我需要双重转义反斜杠?
答案 0 :(得分:3)
要在DSN中包含包含空格的属性,请使用单引号括起该值:
my $dsn = q{dbi:Pg:db=mydb;sslmode=require;host=localhost;}
. q{sslcert='C:\\\path with\\\spaces.crt';}
. q{sslkey='C:\\\path with\\\spaces.key'};
请注意,用于分隔连接属性的分号必须在单引号之外。另请注意,属性中的反斜杠和单引号必须使用反斜杠进行转义(因为Perl会在单引号字符串中将\\
转换为\
,所以必须使用上面的三个反斜杠。)
如果您的DSN用双引号括起来,则必须使用四个反斜杠,因为Perl在双引号字符串中插入了\n
之类的转义序列:
my $dsn = qq{dbi:Pg:db=mydb;sslmode=require;host=localhost;}
. qq{sslcert='C:\\\\path with\\\\spaces.crt';}
. qq{sslkey='C:\\\\path with\\\\spaces.key'};
至于文档,我没有在DBD :: Pg中看到这一点,但你可以看到它是通过查看源代码来支持的。处理DSN的代码位于DBD :: Pg发行版中的dbdimp.c:
/* DBD::Pg syntax: 'dbname=dbname;host=host;port=port', 'User', 'Pass' */
/* libpq syntax: 'dbname=dbname host=host port=port user=uid password=pwd' */
...
/* Change all semi-colons in dbname to a space, unless single-quoted */
dest = conn_str;
while (*dbname != '\0') {
if (';' == *dbname && !inquote)
*dest++ = ' ';
else {
if ('\'' == *dbname)
inquote = !inquote;
*dest++ = *dbname;
}
dbname++;
}
*dest = '\0';
这会将DBI样式的连接字符串转换为libpq-style connection string(libpq是Postgres C API,DBD :: Pg在后台使用它)。由于生成的DSN直接传递给libpq,因此需要遵循libpq documentation中描述的引用和转义规则。
DBD :: Pg的文档补丁肯定是有序的。
答案 1 :(得分:1)
问题在于空间。目前尚不清楚是否可以提供其中有空格的路径。如果是,它可能是特定于驱动程序的语法。您可能需要深入研究DBI和/或DBD :: Pg以确定语法是否受支持。有些人已经这样做,并在评论中提到您可以使用以下内容:
my $dsn = join(';',
"dbi:Pg:db=mydb",
"sslmode=require",
"sslcert='$ssl_cert_qfn'",
"sslkey='$ssl_key_qfn'",
);
或者您可以从另一个角度解决问题。 Windows具有向后兼容性系统,允许仅支持DOS样式路径的应用程序。值得注意的是DOS并没有允许路径中的空格。通过使用DOS样式的路径,您可以避免此问题。
use Win32 qw( );
my $dsn = join(';',
"dbi:Pg:db=mydb",
"sslmode=require",
"sslcert=".Win32::GetShortPathName($ssl_cert_qfn),
"sslkey=".Win32::GetShortPathName($ssl_key_qfn),
);
另一种解决方案是使用DBD::Pg's documentation中详述的配置文件。