Преобразование переменных PHP в переменные bash

1

У меня есть файл конфигурации CakePHP database.php, который я бы хотел использовать, чтобы открыть экземпляр клиента mysql командной строки.

Целью было бы запустить сценарий оболочки, например ./db-login.sh из корня проекта и получить данные базы данных (хост, порт, имя базы данных, имя пользователя, пароль) из файла конфигурации PHP и передать их в командной строке mysql качестве аргументов. Это делается для того, чтобы не вводить подробные данные каждый раз.

Я понимаю, что можно создать псевдоним оболочки, который имеет значения, жестко закодированные: мне нужен переносимый скрипт, который может быть включен в любой из моих проектов Cake. Я также хотел бы сохранить задачу получения учетных данных БД в переменных bash отдельно от запуска клиента mysql. Это откроет возможность повторного использования учетных данных БД в других сценариях оболочки (например, сценарий резервного копирования 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 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 для db-login.sh переменных. Тьфу.
  • Пароль MySQL просочился в командной строке. Это не разбойник, но если есть чистый/переносной способ избежать этого, я открыт для него.
  • Пробелы и кавычки в mysql-пароле не передаются в bash правильно.
    • Пароль, такой как my Pass приведет к тому, что DB_PASS будет установлен на my в db-login.sh.
    • db-cred.sh строки в db-cred.sh приводит к тому, "my вместо этого "my.
  • Аналогично, мои попытки цитирования PASS_CLAUSE не эффективны: только пароли без пробелов/кавычек будут успешно входить в клиент mysql.
  • 0
    Не могли бы вы сделать файл, который может быть оценен как bash, так и PHP? Такие строки, как db_config('host', 'hostname') могут работать на обоих языках.
  • 0
    пусть ваш database.php выводит переменные в списке через запятую, если передан флаг типа? echosh или что-то еще, тогда вам не понадобится db-cred.sh, вы можете включить ваш database.php непосредственно в db-login.sh, а затем используйте stackoverflow.com/questions/10586153/… чтобы разбить возвращенную строку на массив, и тогда вы сможете получить доступ к элементам массива напрямую.
Показать ещё 8 комментариев
Теги:

2 ответа

0
Лучший ответ

Хорошо, поэтому предложения @nickb привели меня к правильному пути с достаточными изменениями.

объяснение

Проблемы возникают, если вы пытаетесь передать пароль MySQL через несколько переменных bash. Здесь приведенный пример:

#!/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. @Идея о том, как использовать CSV в качестве перехода, имеет потенциал, но в моих тестах это еще больше усложняет ситуацию, добавляя еще один уровень экранирования /unescaping, необходимый для получения переменных в bash.
  • Пароль MySQL по-прежнему используется в командной строке. Написание файла конфигурации mysql, используя его с --defaults-extra-file=filename и последующим удалением, может быть таким.
  • db-login.sh теперь представляет собой шаблон для выполнения командных строк с учетными данными базы данных и может быть легко изменен/расширен для других инструментов, таких как mysqldump.
  • 0
    Рад видеть, что ваши проблемы решены!
2
  1. Сценарий db-login.sh использует eval для вставки переменных. Тьфу.

    Вместо eval вы можете использовать команду source:

    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().

  • 0
    1. Я попробовал source . Это не работает, потому что скрипт на самом деле является PHP-кодом, а не оператором bash ( source игнорирует #!). 2. Документы mysql объясняют, почему -p вообще небезопасен. Это не вопрос неустановленного ВАРА, это открывающее к журналам, ps и т.д. 4. Я думаю , что вы можете быть на правильном пути с addslashes хотя escapeshellarg может быть более подходящим. Я буду экспериментировать дальше.
  • 0
    Почему бы вам просто не вызвать PHP, чтобы выполнить скрипт? Затем вы можете получить результат этого в свой скрипт db-login.sh
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню