我有一个CakePHP database.php config file,我想利用它来打开命令行mysql
客户端实例。
目标是能够从项目根目录运行像./db-login.sh
这样的shell脚本,并从PHP配置文件中提取数据库详细信息(主机,端口,数据库名称,用户名,密码),将它们作为参数传递给mysql
命令行。这是为了避免每次都输入细节。
我理解可以创建一个具有硬编码值的shell别名:我想要一个可以包含在任何我的Cake项目中的可移植脚本。我还希望将启用mysql
客户端的数据库凭据与bash变量分开。这将打开在其他shell脚本中轻松重用DB凭据的能力(例如mysqldump
备份脚本。)
这是我到目前为止所拥有的:
为此问题的目的考虑此文件是不可变的。它必须完全按照您的意图存在。
<?php
class DATABASE_CONFIG {
public $default = array(
'host' => 'localhost',
'login' => 'cakephpuser',
'password' => 'c4k3 roxx!',
'database' => 'my_cakephp_project',
);
}
充当中间件,将PHP变量转换为bash(友好)变量。
#!/usr/bin/env php
<?php
include 'database.php';
$db = new DATABASE_CONFIG();
// Selectively wrap quotes. Has no real effect(?)
$p = (!empty($db->default['password']) ? "\"$db->default['password']\"" : '');
echo <<<EOD
DB_HOST="{$db->default['host']}"
DB_NAME="{$db->default['database']}"
DB_USER="{$db->default['login']}"
DB_PASS={$p}
EOD;
#!/usr/bin/env bash
# Uses Cake's database.php file to log into mysql on the
# command line with the correct arguments.
# Holy yuck, but nothing else works!
eval $( db-cred.sh )
# Try to set an appropriate password clause.
PATTERN=" |'"
if [ -n "$DB_PASS" ]; then
if [[ $DB_PASS =~ $PATTERN ]]; then
PASS_CLAUSE=" -p'${DB_PASS}'"
else
PASS_CLAUSE=" -p${DB_PASS}"
fi
else
PASS_CLAUSE=""
fi
# Get a rough look at what we're about to run.
echo mysql --host=${DB_HOST} --database=${DB_NAME} --user=${DB_USER}${PASS_CLAUSE}
# Call MySQL.
mysql --host=${DB_HOST} --database=${DB_NAME} --user=${DB_USER}${PASS_CLAUSE}
db-login.sh
脚本使用eval来吸收变量。呸。my Pass
之类的密码会导致my
中的DB_PASS设置为db-login.sh
。db-cred.sh
中引用字符串会生成"my
。PASS_CLAUSE
的尝试无效:只有没有空格/引号的密码才能成功登录mysql
客户端。答案 0 :(得分:2)
db-login.sh脚本使用eval来吸收变量。呸。
您可以使用
source
命令代替eval
:
source db-cred.sh
MySQL密码在命令行中泄露。这不是一个破坏者,但如果有一个干净/便携的方式来避免它,我会接受它。
您可以在使用后取消设置MySQL密码:
unset DB_PASS
但是,如果通过命令行向MySQL提供密码,则始终会出现此问题。您可以删除
-pPassword
子句并强制用户在MySQL提示时输入密码,但是从您的用例中看似不可行。
mysql密码中的空格和引号不会正确传递给bash。
对于3和4,我相信您需要做的就是正确引用您的变量值。
在PHP中:
echo <<<EOD
DB_HOST="{$db->default['host']}"
DB_NAME="{$db->default['database']}"
DB_USER="{$db->default['login']}"
DB_PASS="{$p}"
EOD;
请注意DB_PASS="{$p}"
中添加的引号。
提醒一下,您还可以使用addslashes()
转义PHP中的引号。
答案 1 :(得分:0)
好的,所以@ nickb的建议让我在正确的轨道上进行了足够的修改。
如果您尝试通过多个bash变量传递MySQL密码,则会出现问题。这是一个精简的例子:
#!/bin/bash
set -x
DB_PASS="pass with space and 'quote"
PASS_CLAUSE=" -p'$DB_PASS'"
# Doesn't work.
mysql $PASS_CLAUSE
# Works.
mysql -p"$DB_PASS"
请注意,使用set -x
,我们可以看到实际运行的命令。这是帮助我识别双重逃避的原因。 $ DB_PASS中的字符串在保存到$ PASS_CLAUSE时会重新转义。由于它仍然传递给MySQL,并且仍然存在一级转义,第一次连接失败,但使用原始变量成功。
#!/usr/bin/php
<?php
include 'database.php';
$db = new DATABASE_CONFIG();
echo <<<EOD
DB_HOST="{$db->default['host']}"
DB_NAME="{$db->default['database']}"
DB_USER="{$db->default['login']}"
DB_PASS="{$db->default['password']}"
EOD;
#!/bin/bash
# Holy yuck, but nothing else works!
eval $( db-cred.sh )
CMD="mysql --host=${DB_HOST} --database=${DB_NAME} --user=${DB_USER}"
PATTERN=" |'"
if [[ ${DB_PASS} =~ ${PATTERN} ]]; then
${CMD} -p"${DB_PASS}"
elif [ -n "${DB_PASS}" ]; then
${CMD} -p${DB_PASS}
else
${CMD}
fi
eval
的需求,仍然可以改进这一点。 @Dave关于使用CSV作为介于两者之间的想法具有潜力,但在我的测试中,它通过添加另一个必要的转义/转义来进一步复杂化,以便将变量干净利落地变为bash。--defaults-extra-file=filename
一起使用,然后删除它可能是一种解决方法。db-login.sh
现在表示使用数据库凭据执行命令行的模式,可以轻松修改/扩展其他工具,如mysqldump
。