将PHP变量转换为bash变量

时间:2013-05-01 15:13:28

标签: php mysql bash

我有一个CakePHP database.php config file,我想利用它来打开命令行mysql客户端实例。

目标是能够从项目根目录运行像./db-login.sh这样的shell脚本,并从PHP配置文件中提取数据库详细信息(主机,端口,数据库名称,用户名,密码),将它们作为参数传递给mysql命令行。这是为了避免每次都输入细节。

我理解可以创建一个具有硬编码值的shell别名:我想要一个可以包含在任何我的Cake项目中的可移植脚本。我还希望将启用mysql客户端的数据库凭据与bash变量分开。这将打开在其他shell脚本中轻松重用DB凭据的能力(例如mysqldump备份脚本。)

这是我到目前为止所拥有的:

database.php中

为此问题的目的考虑此文件是不可变的。它必须完全按照您的意图存在。

<?php
class DATABASE_CONFIG {
    public $default = array(
        'host'        => 'localhost',
        'login'       => 'cakephpuser',
        'password'    => 'c4k3 roxx!',
        'database'    => 'my_cakephp_project',
    );
}

db-cred.sh

充当中间件,将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;

db-login.sh

#!/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来吸收变量。呸。
  • MySQL密码在命令行中泄露。这不是一个破坏者,但如果有一个干净/可移植的方式来避免它,我会接受它。
  • mysql密码中的空格和引号不会正确传递给bash。
    • my Pass之类的密码会导致my中的DB_PASS设置为db-login.sh
    • db-cred.sh中引用字符串会生成"my
  • 同样,我引用PASS_CLAUSE的尝试无效:只有没有空格/引号的密码才能成功登录mysql客户端。

2 个答案:

答案 0 :(得分:2)

  1. db-login.sh脚本使用eval来吸收变量。呸。

      

    您可以使用source命令代替eval

    source db-cred.sh
    
  2. MySQL密码在命令行中泄露。这不是一个破坏者,但如果有一个干净/便携的方式来避免它,我会接受它。

      

    您可以在使用后取消设置MySQL密码:

    unset DB_PASS
    
      

    但是,如果通过命令行向MySQL提供密码,则始终会出现此问题。您可以删除-pPassword子句并强制用户在MySQL提示时输入密码,但是从您的用例中看似不可行。

  3. mysql密码中的空格和引号不会正确传递给bash。

  4. 同样,我引用PASS_CLAUSE的尝试无效:只有没有空格/引号的密码才会成功登录到mysql客户端。
  5. 对于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,并且仍然存在一级转义,第一次连接失败,但使用原始变量成功。

最终脚本

db-cred.sh

#!/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;

db-login.sh

#!/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。
  • MySQL密码仍在命令行中使用。写a mysql config file,将其与--defaults-extra-file=filename一起使用,然后删除它可能是一种解决方法。
  • db-login.sh现在表示使用数据库凭据执行命令行的模式,可以轻松修改/扩展其他工具,如mysqldump