У меня есть файл конфигурации CakePHP database.php, который я бы хотел использовать, чтобы открыть экземпляр клиента mysql
командной строки.
Целью было бы запустить сценарий оболочки, например ./db-login.sh
из корня проекта и получить данные базы данных (хост, порт, имя базы данных, имя пользователя, пароль) из файла конфигурации PHP и передать их в командной строке mysql
качестве аргументов. Это делается для того, чтобы не вводить подробные данные каждый раз.
Я понимаю, что можно создать псевдоним оболочки, который имеет значения, жестко закодированные: мне нужен переносимый скрипт, который может быть включен в любой из моих проектов Cake. Я также хотел бы сохранить задачу получения учетных данных БД в переменных bash отдельно от запуска клиента mysql
. Это откроет возможность повторного использования учетных данных БД в других сценариях оболочки (например, сценарий резервного копирования 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 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
переменных. Тьфу.my Pass
приведет к тому, что DB_PASS будет установлен на my
в db-login.sh
.db-cred.sh
строки в db-cred.sh
приводит к тому, "my
вместо этого "my
.PASS_CLAUSE
не эффективны: только пароли без пробелов/кавычек будут успешно входить в клиент mysql
.Хорошо, поэтому предложения @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 с одним уровнем экранирования, все еще на месте, первое соединение выходит из строя, но использование исходной переменной завершается успешно.
#!/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
. @Идея о том, как использовать CSV в качестве перехода, имеет потенциал, но в моих тестах это еще больше усложняет ситуацию, добавляя еще один уровень экранирования /unescaping, необходимый для получения переменных в bash.--defaults-extra-file=filename
и последующим удалением, может быть таким.db-login.sh
теперь представляет собой шаблон для выполнения командных строк с учетными данными базы данных и может быть легко изменен/расширен для других инструментов, таких как mysqldump
.Сценарий db-login.sh использует eval для вставки переменных. Тьфу.
Вместо
eval
вы можете использовать командуsource
:
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}"
.
Напоминаем, что вы также можете избежать кавычек в PHP с помощью addslashes()
.
source
. Это не работает, потому что скрипт на самом деле является PHP-кодом, а не оператором bash ( source
игнорирует #!). 2. Документы mysql объясняют, почему -p
вообще небезопасен. Это не вопрос неустановленного ВАРА, это открывающее к журналам, ps
и т.д. 4. Я думаю , что вы можете быть на правильном пути с addslashes
хотя escapeshellarg
может быть более подходящим. Я буду экспериментировать дальше.
db-login.sh
db_config('host', 'hostname')
могут работать на обоих языках.