【问题标题】:Converting PHP variables into bash variables将 PHP 变量转换为 bash 变量
【发布时间】:2013-04-25 14:39:44
【问题描述】:

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

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

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

这是我目前所拥有的:

数据库.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 之类的密码将导致 DB_PASS 在db-login.sh 中设置为my
    • 引用db-cred.sh 中的字符串会生成"my
  • 同样,我引用PASS_CLAUSE 的尝试无效:只有不带空格/引号的密码才能成功登录mysql 客户端。

【问题讨论】:

  • 你能制作一个可以被 bash 和 PHP 评估的文件吗?像db_config('host', 'hostname') 这样的行可以在两种语言中工作。
  • 让你的 database.php 在逗号分隔的列表中回显变量,如果传递了一个像 ?echosh 之类的标志,那么你就不需要 db-cred.sh 你可以直接包含你的 database.php进入 db-login.sh 然后使用stackoverflow.com/questions/10586153/… 将返回的字符串拆分为一个数组,然后您可以直接访问您的数组元素。
  • Cake 的 database.php 配置文件的格式是固定的,这是整个事情的关键。确实,我可以在另一个文件中设置您建议的变量并将它们拉入 Cake 的配置文件,但我必须为我的所有 Cake 项目这样做。这否定了可移植性,并且并不比带有硬编码值的 shell 别名更好。
  • @Dave - 正如我所提到的,在这种情况下,database.php 不适合更改。需要有另一种方法将其内容桥接到 bash 变量中,以便它能够干净地工作。至于shebangs,请随意提出更好的选择。
  • 你可以很容易地编辑你的蛋糕database.php,并且只记得将来使用你的新的而不是他们的应用程序吗?或者正如您所说,更好的可移植性想法是将您的凭据存储在其他地方并将它们包含在蛋糕配置中。

标签: php mysql bash


【解决方案1】:

好的,@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 等其他工具修改/扩展。

【讨论】:

    【解决方案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 客户端。

    对于 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}" 中添加的引号。

    提醒一下,您还可以在 PHP 中使用 addslashes() 转义引号。

    【讨论】:

    • 1.我试过source。它不起作用,因为脚本实际上是 PHP 代码,而不是 bash 语句(source 忽略 #!)。 2.mysql docs 解释了为什么-p 通常是不安全的。这不是取消设置变量的问题,而是暴露于日志、ps 等。 4. 我认为您可能在addslashes 的正确轨道上,尽管escapeshellarg 可能更合适。我会进一步试验。
    • 为什么不直接调用 PHP 来执行脚本呢?然后你可以把结果拉到你的db-login.shscript
    • 我刚刚测试过,但似乎源无法进行 I/O 重定向。我认为由于它是一个内置的 shell,它完全需要一个文件名作为参数。
    猜你喜欢
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 2016-08-08
    相关资源
    最近更新 更多