Создание файла конфигурации на PHP

101

Я хочу создать файл конфигурации для своего проекта PHP, но не уверен, как это сделать лучше всего.

У меня пока есть 3 идеи.

1-использовать переменную

$config['hostname'] = "localhost";
$config['dbuser'] = "dbuser";
$config['dbpassword'] = "dbpassword";
$config['dbname'] = "dbname";
$config['sitetitle'] = "sitetitle";

2-Use Const

define('DB_NAME', 'test');
define('DB_USER', 'root');
define('DB_PASSWORD', '');
define('DB_HOST', 'localhost');
define('TITLE', 'sitetitle');

3-использование базы данных

Я буду использовать конфигурацию в классах, поэтому я не уверен, какой путь будет лучшим или есть ли лучший.

Али Акбар Азизи
источник
12
4) Используйте ini-файл. 5) Используйте файл YAML. 6) Используйте файл JSON. 7) ... Есть так много способов ... Определите несколько критериев, по которым можно судить, по крайней мере, не существует общего "лучшего".
deceze
@deceze какой способ поста? (на память и быстро)
Али Акбар Азизи
Тогда это должно быть для вас интересным
чтивом
1
Я использую способ, которым это делает Laravel (когда не использую Laravel). Я создаю класс, который загружает определенный файл конфигурации в зависимости от имени хоста. Затем я вызываю его с помощью Config::get('key');. pastebin.com/4iTnjEuM
MisterBla

Ответы:

220

Один простой, но элегантный способ - создать config.phpфайл (или как вы его называете), который просто возвращает массив:

<?php

return array(
    'host' => 'localhost',
    'username' => 'root',
);

А потом:

$configs = include('config.php');
Хьюго Мота
источник
10
Мне также нравится этот метод - я думаю, что он чище, чем просто объявление переменной во включенном файле и предположение, что она будет там в вашем скрипте
Колин М.
Где в этом ответе метод создания файла конфигурации? Для начинающих PHP, как я?
Лука
@Luka Вы можете использовать функцию var_export .
Хасан Баят,
77

Использование файла INI - гибкое и мощное решение! PHP имеет встроенную функцию для правильной обработки. Например, можно создать файл INI следующим образом:

app.ini

[database]
db_name     = mydatabase
db_user     = myuser
db_password = mypassword

[application]
app_email = mailer@myapp.com
app_url   = myapp.com

Итак, единственное, что вам нужно сделать, это позвонить:

$ini = parse_ini_file('app.ini');

Затем вы можете легко получить доступ к определениям с помощью $iniмассива.

echo $ini['db_name'];     // mydatabase
echo $ini['db_user'];     // myuser
echo $ini['db_password']; // mypassword
echo $ini['app_email'];   // mailer@myapp.com

ВАЖНО: по соображениям безопасности файл INI должен находиться в непубличной папке.

Марсио Маццукато
источник
Это тоже безопасно? Если бы пользователь угадал путь к ini-файлу и перешел туда в своем браузере, увидели бы они, что находится в файле?
NickGames
1
@NickGames, вы должны поместить файл в не общедоступную папку, иначе вы подвергнетесь серьезной угрозе безопасности,
Марсио Маццукато,
2
@NickGames, пожалуйста, посмотрите 1 комментарий в документации к parse_ini_file ()
R Picheta
20
Мне нравится такой подход. Бонусный совет: переименуйте файл в app.ini.php. Затем добавьте в первую строку ;<?php die(); ?>. Если этот файл случайно появится в общей папке, он будет обработан как файл PHP и умрет в первой строке. Если файл читается с помощью parse_ini_file, первая строка будет рассматриваться как комментарий из-за наличия ;.
andreas
1
Примечание. Если значение в ini-файле содержит какие - либо не буквенно-цифровые символы, его необходимо заключить в двойные кавычки ( "). Например, любой пароль содержит не буквенно-цифровые символы.
Key Shang
25

Я использую небольшую эволюцию @hugo_leonardo «s решения :

<?php

return (object) array(
    'host' => 'localhost',
    'username' => 'root',
    'pass' => 'password',
    'database' => 'db'
);

?>

Это позволяет вам использовать синтаксис объекта, когда вы включаете php: $configs->hostвместо $configs['host'].

Кроме того, если у вашего приложения есть необходимые вам конфигурации на стороне клиента (например, для приложения Angular), вы можете иметь этот config.phpфайл, содержащий все ваши конфигурации (централизованно в одном файле вместо одного для JavaScript и одного для PHP). Тогда уловка будет заключаться в том, чтобы иметь другой файл PHP, который будет содержать echoтолько информацию на стороне клиента (чтобы избежать отображения информации, которую вы не хотите отображать, например строки подключения к базе данных). Назовите это, скажите get_app_info.php:

<?php

    $configs = include('config.php');
    echo json_encode($configs->app_info);

?>

Приведенное выше, если у вас config.phpесть app_infoпараметр:

<?php

return (object) array(
    'host' => 'localhost',
    'username' => 'root',
    'pass' => 'password',
    'database' => 'db',
    'app_info' => array(
        'appName'=>"App Name",
        'appURL'=> "http://yourURL/#/"
    )
);

?>

Таким образом, информация вашей базы данных остается на стороне сервера, но информация вашего приложения доступна из вашего JavaScript, например, с помощью $http.get('get_app_info.php').then(...);типа вызова.

BoDeX
источник
зачем делать из него объект?
TheCrazyProfessor 09
4
Превращение его в объект значительно упрощает обработку данных. Это позволяет, например, получить все app_infoпараметры в JavaScript как JSON с минимумом строк кода.
BoDeX
У объектов также есть побочный эффект - они передаются по ссылке, начиная с PHP 5. Это может быть хорошо, а может и нет. Массивы передаются по значению (но реализованы как COW), поэтому может быть лучше использовать массивы конфигурации вместо объектов конфигурации.
Микко Ранталайнен
@BoDeX Мне всегда нравится этот способ, и он, кажется, является предпочтительным в большинстве статей, но как мне получить к нему доступ через класс? Я читал в статье по безопасности, что создание глобальных переменных - не лучшая идея, что вы предлагаете?
Кевлвиг
22

Варианты, которые я вижу с относительными достоинствами / недостатками, следующие:

Файловые механизмы

Это требует, чтобы ваш код просматривал определенные места, чтобы найти ini-файл. Это сложная для решения проблема, которая всегда возникает в больших PHP-приложениях. Однако вам, вероятно, потребуется решить проблему, чтобы найти код PHP, который будет включен / повторно использован во время выполнения.

Обычные подходы к этому - всегда использовать относительные каталоги или выполнять поиск из текущего каталога вверх, чтобы найти файл, названный исключительно в базовом каталоге приложения.

Общие форматы файлов, используемые для файлов конфигурации, - это код PHP, файлы в формате ini, JSON, XML, YAML и сериализованный PHP.

Код PHP

Это обеспечивает огромную гибкость для представления различных структур данных, и (при условии, что он обрабатывается с помощью include или require) проанализированный код будет доступен из кеша кодов операций, что дает преимущество в производительности.

Include_path предоставляет средства для абстрагирования потенциальных местоположений файла , не полагаясь на дополнительном коде.

С другой стороны, одна из основных причин отделения конфигурации от кода - разделение ответственности. Он обеспечивает путь для внедрения дополнительного кода в среду выполнения.

Если конфигурация создается с помощью инструмента, можно проверить данные в инструменте, но нет стандартной функции для экранирования данных для встраивания в код PHP, которая существует для HTML, URL-адресов, операторов MySQL, команд оболочки ... .

Сериализованные данные Это относительно эффективно для небольших объемов конфигурации (примерно до 200 элементов) и позволяет использовать любую структуру данных PHP. Для создания / анализа файла данных требуется очень мало кода (так что вместо этого вы можете приложить усилия для того, чтобы файл был записан только с соответствующей авторизацией).

Экранирование содержимого, записанного в файл, выполняется автоматически.

Поскольку вы можете сериализовать объекты, это создает возможность для вызова кода, просто читая файл конфигурации (магический метод __wakeup).

Структурированный файл

Сохранение его в виде файла INI, как было предложено Марселем, или JSON, или XML, также предоставляет простой API для сопоставления файла со структурой данных PHP (и, за исключением XML, для экранирования данных и создания файла), при этом исключая вызов кода. уязвимость, использующая сериализованные данные PHP.

Он будет иметь характеристики производительности, аналогичные сериализованным данным.

Хранилище базы данных

Это лучше всего рассматривать, когда у вас есть огромное количество настроек, но вы избирательно выбираете то, что необходимо для текущей задачи - я был удивлен, обнаружив, что примерно со 150 элементами данных было быстрее получить данные из локального экземпляра MySQL, чем из десериализовать файл данных.

OTOH - не лучшее место для хранения учетных данных, которые вы используете для подключения к базе данных!

Среда исполнения

Вы можете установить значения в среде выполнения, в которой работает PHP.

Это устраняет любые требования к PHP-коду искать конфигурацию в определенном месте. OTOH плохо масштабируется для больших объемов данных и его трудно повсеместно изменить во время выполнения.

На клиенте

Одно место, которое я не упомянул для хранения данных конфигурации, - это клиент. Опять же, накладные расходы сети означают, что это плохо масштабируется для больших объемов конфигурации. И поскольку конечный пользователь имеет контроль над данными, они должны храниться в формате, в котором любое вмешательство может быть обнаружено (например, с помощью криптографической подписи), и не должен содержать никакой информации, которая подвергается риску в результате ее раскрытия (например, с обратимым шифрованием).

И наоборот, это дает много преимуществ для хранения конфиденциальной информации, которая принадлежит конечному пользователю - если вы не храните ее на сервере, ее невозможно украсть оттуда.

Сетевые каталоги Еще одно интересное место для хранения информации о конфигурации - это DNS / LDAP. Это будет работать для небольшого количества небольших фрагментов информации, но вам не нужно придерживаться 1-й нормальной формы - рассмотрите, например, SPF .

Инфраструктура поддерживает кэширование, репликацию и распространение. Следовательно, он хорошо работает для очень больших инфраструктур.

Системы контроля версий

Конфигурация, как и код, должна управляться, а версия должна контролироваться - следовательно, получение конфигурации непосредственно из вашей системы VC является жизнеспособным решением. Но часто это приводит к значительным накладным расходам, поэтому рекомендуется кэширование.

symcbean
источник
6

Ну, было бы сложно хранить данные конфигурации вашей базы данных в базе данных - не так ли?

Но на самом деле это довольно самоуверенный вопрос, потому что любой стиль действительно работает, и все дело в предпочтениях. Лично я бы выбрал переменную конфигурации, а не константы - обычно потому, что мне не нравятся вещи в глобальном пространстве, если это не необходимо. Ни одна из функций в моей кодовой базе не должна иметь возможность легко получить доступ к моему паролю базы данных (кроме логики подключения к базе данных), поэтому я бы использовал его здесь, а затем, вероятно, уничтожил бы его.

Изменить : чтобы ответить на ваш комментарий - ни один из механизмов синтаксического анализа не будет самым быстрым (ini, json и т.д.), но они также не являются частями вашего приложения, которые вам действительно нужно сосредоточить на оптимизации, поскольку разница в скорости будет быть незначительным для таких маленьких файлов.

Колин М
источник
2

Define сделает константу доступной везде в вашем классе без необходимости использования global, в то время как переменная требует global в классе, я бы использовал DEFINE. но опять же, если параметры db должны измениться во время выполнения программы, вы можете придерживаться переменной.

phpalix
источник
каков самый быстрый способ выполнить PHP? константа или вар?
Али Акбар Азизи
1
@CooPer Определение констант происходит значительно медленнее, чем определение переменных. Но пользоваться ими немного быстрее. Поскольку они будут использоваться в одном месте, переменные в целом будут обеспечивать более высокую производительность.
Colin M
"Значительно" - это немного тяжелое слово для этого, если вы посмотрите на это с этой точки зрения, возможно, вам стоит связаться с ребятами из php-разработчиков и попросить их удалить постоянную поддержку!
phpalix
@phpalix Определение константы может быть в 10-20 раз медленнее, чем определение переменной с тем же значением. Я бы сказал, это важно. Однако, если вы часто используете константу в своем приложении, это может окупиться. Но не рекомендуется создавать константу для ее однократного использования.
Colin M
2

Если вы думаете, что по какой-либо причине вы будете использовать более 1 дБ, используйте переменную, потому что вы сможете изменить один параметр, чтобы переключиться на совершенно другой db. Т.е. для тестирования, автобэкапа и т.д.

тригун0x2
источник
2

Вы можете создать статические свойства класса конфигурации

class Config 
{
    static $dbHost = 'localhost';
    static $dbUsername = 'user';
    static $dbPassword  = 'pass';
}

тогда вы можете просто использовать его:

Config::$dbHost  

Иногда в своих проектах я использую шаблон проектирования SINGLETON для доступа к данным конфигурации. Очень удобно в использовании.

Зачем?

Например, в вашем проекте есть 2 источника данных. И вы можете выбрать, какая из них включена.

  • mysql
  • json

Где-то в файле конфигурации вы выбираете:

$dataSource = 'mysql' // or 'json'

Когда вы меняете исходный код, все приложение переключается на новый источник данных, работает нормально и не требует изменений в коде.

Пример:

Конфиг:

class Config 
{
  // ....
  static $dataSource = 'mysql';
  / .....
}

Синглтон-класс:

class AppConfig
{
    private static $instance;
    private $dataSource;

    private function __construct()
    {
        $this->init();
    }

    private function init()
    {
        switch (Config::$dataSource)
        {
            case 'mysql':
                $this->dataSource = new StorageMysql();
                break;
            case 'json':
                $this->dataSource = new StorageJson();
                break;
            default:
                $this->dataSource = new StorageMysql();
        }
    }

    public static function getInstance()
    {
        if (empty(self::$instance)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function getDataSource()
    {
        return $this->dataSource;
    }
}

... и где-то в вашем коде (например, в каком-то классе обслуживания):

$container->getItemsLoader(AppConfig::getInstance()->getDataSource()) // getItemsLoader need Object of specific data source class by dependency injection

Мы можем получить объект AppConfig из любого места в системе и всегда получать одну и ту же копию (благодаря static). В конструкторе вызывается метод init () класса, который гарантирует только одно выполнение. Тело Init () проверяет значение config $ dataSource и создает новый объект определенного класса источника данных. Теперь наш скрипт может получить объект и работать с ним, даже не зная, какая конкретная реализация существует на самом деле.

Себастьян Скурног
источник
1

Обычно я создаю один файл conn.php, содержащий подключения к моей базе данных. Затем я включаю этот файл во все файлы, требующие запросов к базе данных.

Михир Чхатре
источник
1
я знаю это, но как вы сохраняете файл базы данных с переменной или константой? и почему?
Али Акбар Азизи
0

Вот мой путь.

<?php

define('DEBUG',0);

define('PRODUCTION',1);



#development_mode : DEBUG / PRODUCTION

$development_mode = PRODUCTION;



#Website root path for links

$app_path = 'http://192.168.0.234/dealer/';



#User interface files path

$ui_path = 'ui/';

#Image gallery path

$gallery_path = 'ui/gallery/';


$mysqlserver = "localhost";
$mysqluser = "root";
$mysqlpass = "";
$mysqldb = "dealer_plus";

?>

Любые сомнения, пожалуйста, прокомментируйте

Алок Раджасукумаран
источник
3
Здравствуйте! Не могли бы вы привести пример использования? Спасибо
Ник