Tworzenie pliku konfiguracyjnego w PHP

101

Chcę utworzyć plik konfiguracyjny dla mojego projektu PHP, ale nie jestem pewien, jaki jest najlepszy sposób, aby to zrobić.

Na razie mam 3 pomysły.

Zmienna 1-Use

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

2-używać Konst

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

Baza danych 3 zastosowań

Będę używał konfiguracji na zajęciach, więc nie jestem pewien, który sposób byłby najlepszy lub czy istnieje lepszy sposób.

Ali Akbar Azizi
źródło
12
4) Użyj pliku ini. 5) Użyj pliku YAML. 6) Użyj pliku JSON. 7) ... Jest tak wiele sposobów ... Zdefiniuj przynajmniej niektóre kryteria, na podstawie których można oceniać, nie ma ogólnego „najlepszego”.
deceze
@deceze jaki jest sposób na czczo? (pamięć i szybko)
Ali Akbar Azizi
To powinna być dla Ciebie interesująca lektura: stackoverflow.com/questions/823352/ ...
eithed
1
Używam sposobu, w jaki robi to Laravel (to znaczy bez Laravel). Tworzę klasę, która ładuje określony plik konfiguracyjny w zależności od nazwy hosta. Następnie nazywam to używając Config::get('key');. pastebin.com/4iTnjEuM
MisterBla

Odpowiedzi:

220

Jednym prostym, ale eleganckim sposobem jest utworzenie config.phppliku (lub jakkolwiek to nazwiesz), który po prostu zwraca tablicę:

<?php

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

I wtedy:

$configs = include('config.php');
Hugo Mota
źródło
10
Podoba mi się również ta metoda - myślę, że jest czystsza niż zwykłe zadeklarowanie zmiennej w dołączonym pliku i założenie, że będzie tam w twoim skrypcie
Colin M,
Gdzie jest w tej odpowiedzi metoda tworzenia pliku konfiguracyjnego? Dla początkujących php takich jak ja?
Luka
@Luka Możesz użyć funkcji var_export .
Hasan Bayat
77

Użyj pliku INI to elastyczne i wydajne rozwiązanie! PHP ma natywną funkcję do poprawnej obsługi. Na przykład możliwe jest utworzenie takiego pliku INI:

app.ini

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

[application]
app_email = [email protected]
app_url   = myapp.com

Więc jedyne co musisz zrobić to zadzwonić:

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

Następnie możesz łatwo uzyskać dostęp do definicji za pomocą $initablicy.

echo $ini['db_name'];     // mydatabase
echo $ini['db_user'];     // myuser
echo $ini['db_password']; // mypassword
echo $ini['app_email'];   // [email protected]

WAŻNE: Ze względów bezpieczeństwa plik INI musi znajdować się w folderze niepublicznym

Marcio Mazzucato
źródło
Czy jest to również bezpieczne w użyciu? Jeśli użytkownik odgadnie ścieżkę do pliku ini i przejdzie tam w przeglądarce, czy zobaczy, co jest w pliku?
NickGames
1
@NickGames, musisz umieścić plik w folderze niepublicznym, w przeciwnym razie będziesz narażony na poważne zagrożenie bezpieczeństwa
Marcio Mazzucato
2
@NickGames, spójrz na 1 komentarz w Docs of parse_ini_file ()
R Picheta
20
Podoba mi się to podejście. Dodatkowa wskazówka: Zmień nazwę pliku na app.ini.php. Następnie dodaj do pierwszej linii ;<?php die(); ?>. W przypadku, gdy ten plik przypadkowo pojawi się w folderze publicznym, zostanie potraktowany jako plik PHP i umrze w pierwszej linii. Jeśli plik jest czytany parse_ini_file, traktuje pierwszą linię jako komentarz z powodu rozszerzenia ;.
Andreas
1
Uwaga: jeśli wartość w pliku ini zawiera jakiekolwiek znaki inne niż alfanumeryczne , należy ją ująć w podwójne cudzysłowy ( "). Na przykład każde hasło zawiera znaki inne niż alfanumeryczne.
Key Shang
25

Używam niewielki ewolucję @hugo_leonardo „s rozwiązania :

<?php

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

?>

Pozwala to na użycie składni obiektu, gdy dołączasz php: $configs->hostzamiast $configs['host'].

Ponadto, jeśli Twoja aplikacja ma konfiguracje, których potrzebujesz po stronie klienta (jak w przypadku aplikacji Angular), możesz mieć ten config.phpplik zawierający wszystkie konfiguracje (scentralizowane w jednym pliku zamiast jednego dla JavaScript i jednego dla PHP). Sztuczka polegałaby wtedy na echoutworzeniu innego pliku PHP, który zawierałby tylko informacje po stronie klienta (aby uniknąć wyświetlania informacji, których nie chcesz wyświetlać, takich jak ciąg połączenia z bazą danych). Nazwij to powiedz get_app_info.php:

<?php

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

?>

Powyższe zakładając, że twój config.phpzawiera app_infoparametr:

<?php

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

?>

Tak więc informacje z bazy danych pozostają po stronie serwera, ale informacje o aplikacji są dostępne z poziomu JavaScript, na przykład z $http.get('get_app_info.php').then(...);rodzajem wywołania.

BoDeX
źródło
po co robić z tego przedmiot?
TheCrazyProfessor
4
Uczynienie z niego obiektu znacznie ułatwia obsługę danych. Pozwala na przykład pobrać wszystkie app_infoparametry do JavaScript w postaci JSON z minimalną liczbą wierszy kodu.
BoDeX
Obiekty mają również efekt uboczny przekazywania przez referencje od PHP 5. Może to być lub nie być dobrą rzeczą. Tablice są przekazywane przez wartość (ale zaimplementowane jako COW), więc lepiej byłoby użyć tablic konfiguracyjnych zamiast obiektów konfiguracyjnych.
Mikko Rantalainen
@BoDeX Zawsze lubię ten sposób i wydaje się, że jest to preferowane podejście w większości artykułów, ale jak uzyskać do niego dostęp za pośrednictwem zajęć? W artykule dotyczącym bezpieczeństwa przeczytałem, że tworzenie zmiennych globalnych nie jest dobrym pomysłem, więc co sugerujesz?
Kevlwig
22

Opcje, które widzę ze względnymi zaletami / słabościami, to:

Mechanizmy oparte na plikach

Wymagają one, aby kod przeszukiwał określone lokalizacje, aby znaleźć plik ini. Jest to trudny do rozwiązania problem, który zawsze pojawia się w dużych aplikacjach PHP. Jednak prawdopodobnie będziesz musiał rozwiązać problem, aby znaleźć kod PHP, który zostanie włączony / ponownie użyty w czasie wykonywania.

Typowe podejście to zawsze używanie katalogów względnych lub przeszukiwanie od bieżącego katalogu w górę w celu znalezienia pliku o nazwie wyłącznie w katalogu podstawowym aplikacji.

Typowe formaty plików używane w plikach konfiguracyjnych to kod PHP, pliki w formacie ini, JSON, XML, YAML i serializowane PHP

Kod PHP

Zapewnia to ogromną elastyczność w reprezentowaniu różnych struktur danych, a (zakładając, że jest przetwarzany za pomocą dołączania lub wymagania), przeanalizowany kod będzie dostępny z pamięci podręcznej kodu operacji - dając korzyść wydajności.

Metoda include_path umożliwia wyodrębnienie potencjalnych lokalizacji pliku bez polegania na dodatkowym kodzie.

Z drugiej strony jednym z głównych powodów oddzielenia konfiguracji od kodu jest oddzielenie obowiązków. Zapewnia trasę do wstrzykiwania dodatkowego kodu do środowiska wykonawczego.

Jeśli konfiguracja jest tworzona za pomocą narzędzia, może być możliwe sprawdzenie danych w narzędziu, ale nie ma standardowej funkcji ucieczki danych do osadzenia w kodzie PHP, jak ma to miejsce w przypadku HTML, adresów URL, instrukcji MySQL, poleceń powłoki ... .

Dane serializowane Jest to stosunkowo wydajne w przypadku niewielkich ilości konfiguracji (do około 200 pozycji) i pozwala na użycie dowolnej struktury danych PHP. Tworzenie / analizowanie pliku danych wymaga bardzo niewielkiej ilości kodu (więc zamiast tego możesz poświęcić swoje wysiłki na upewnienie się, że plik jest zapisywany tylko z odpowiednią autoryzacją).

Ucieczka zawartości zapisanej do pliku jest obsługiwana automatycznie.

Ponieważ można serializować obiekty, stwarza to możliwość wywołania kodu po prostu przez odczytanie pliku konfiguracyjnego (magiczna metoda __wakeup).

Plik strukturalny

Przechowywanie go jako pliku INI, zgodnie z sugestią Marcela lub JSON lub XML, zapewnia również prosty interfejs API do mapowania pliku na strukturę danych PHP (z wyjątkiem XML, do ucieczki danych i tworzenia pliku), eliminując jednocześnie wywoływanie kodu podatność na zserializowane dane PHP.

Będzie miał podobną charakterystykę wydajności do serializowanych danych.

Przechowywanie bazy danych

Najlepiej jest to rozważyć, gdy masz dużą liczbę konfiguracji, ale jesteś selektywny w zakresie tego, co jest potrzebne do bieżącego zadania - byłem zaskoczony, gdy okazało się, że przy około 150 elementach danych szybsze było pobranie danych z lokalnej instancji MySQL niż odserializować plik danych.

OTOH to nie jest dobre miejsce do przechowywania danych logowania, których używasz do łączenia się z bazą danych!

Środowisko wykonawcze

Możesz ustawić wartości w środowisku wykonawczym, w którym działa PHP.

Eliminuje to wszelkie wymagania, aby kod PHP szukał w określonym miejscu konfiguracji. OTOH nie skaluje się dobrze do dużych ilości danych i trudno jest go uniwersalnie zmienić w czasie wykonywania.

Na kliencie

Jedno miejsce, o którym nie wspomniałem do przechowywania danych konfiguracyjnych, znajduje się u klienta. Ponownie narzut sieci oznacza, że ​​nie jest to dobrze skalowalne do dużych ilości konfiguracji. A ponieważ użytkownik końcowy ma kontrolę nad danymi, muszą one być przechowywane w formacie, w którym można wykryć wszelkie manipulacje (tj. Za pomocą podpisu kryptograficznego) i nie powinny zawierać żadnych informacji, które zostałyby naruszone w wyniku ich ujawnienia (tj. Odwracalnie zaszyfrowane).

Z drugiej strony ma to wiele zalet w przypadku przechowywania poufnych informacji, które są własnością użytkownika końcowego - jeśli nie przechowujesz ich na serwerze, nie można ich stamtąd ukraść.

Katalogi sieciowe Innym interesującym miejscem do przechowywania informacji konfiguracyjnych jest DNS / LDAP. To zadziała w przypadku niewielkiej liczby małych informacji - ale nie musisz trzymać się pierwszej normalnej formy - weź pod uwagę na przykład SPF .

Infrastruktura obsługuje buforowanie, replikację i dystrybucję. Dlatego sprawdza się dobrze w bardzo dużych infrastrukturach.

Systemy kontroli wersji

Konfiguracja, podobnie jak kod, powinna być zarządzana i kontrolowana wersjami - stąd uzyskanie konfiguracji bezpośrednio z systemu VC jest realnym rozwiązaniem. Ale często wiąże się to ze znacznym narzutem wydajności, dlatego buforowanie może być zalecane.

symcbean
źródło
6

Cóż - przechowywanie danych konfiguracyjnych bazy danych w bazie danych byłoby trochę trudne - nie sądzisz?

Ale tak naprawdę jest to dość mocno uparte pytanie, ponieważ każdy styl naprawdę działa i wszystko zależy od preferencji. Osobiście wolałbym raczej zmienną konfiguracyjną niż stałe - generalnie dlatego, że nie lubię rzeczy w globalnej przestrzeni, chyba że jest to konieczne. Żadna z funkcji w mojej bazie kodu nie powinna mieć łatwego dostępu do mojego hasła do bazy danych (z wyjątkiem logiki połączenia z bazą danych) - więc użyłbym go tam, a następnie prawdopodobnie je zniszczył.

Edycja : aby odpowiedzieć na Twój komentarz - żaden z mechanizmów parsowania nie byłby najszybszy (ini, json itp.) - ale nie są to również części aplikacji, na których naprawdę musisz się skupić na optymalizacji, ponieważ różnica prędkości byłaby być pomijalne w przypadku takich małych plików.

Colin M.
źródło
2

Define sprawi, że stała będzie dostępna wszędzie w twojej klasie bez konieczności używania global, podczas gdy zmienna wymaga global w klasie, użyłbym DEFINE. ale znowu, jeśli parametry db powinny się zmienić podczas wykonywania programu, możesz chcieć trzymać się zmiennej.

phpalix
źródło
jaki jest najszybszy sposób wykonania php? const czy var?
Ali Akbar Azizi
1
@CooPer Definiowanie stałych jest znacznie wolniejsze niż definiowanie zmiennych. Ale korzystanie z nich jest nieco szybsze. Ponieważ będą one używane w jednym miejscu, zmienne będą ogólnie oferować wyższą wydajność.
Colin M,
„Znacząco” to trochę ciężkie słowo na to określenie, jeśli spojrzysz na to w ten sposób, może powinieneś skontaktować się z gośćmi php dev i poprosić ich o usunięcie stałego wsparcia!
phpalix,
@phpalix Definiowanie stałej może być od 10 do 20 razy wolniejsze niż definiowanie zmiennej o tej samej wartości. Powiedziałbym, że to ważne. Jeśli jednak intensywnie używasz tej stałej przez całą aplikację - może to się bardzo opłacić. Nie zaleca się jednak tworzenia stałej do jednorazowego użycia.
Colin M
2

Jeśli myślisz, że z jakiegokolwiek powodu będziesz używać więcej niż 1 db, skorzystaj ze zmiennej, ponieważ będziesz w stanie zmienić jeden parametr, aby przełączyć się na zupełnie inną bazę danych. To znaczy do testowania, automatycznej kopii zapasowej itp.

trigun0x2
źródło
2

Możesz utworzyć klasę konfiguracji ze statycznymi właściwościami

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

możesz go po prostu użyć:

Config::$dbHost  

Czasami w moich projektach używam wzorca projektowego SINGLETON, aby uzyskać dostęp do danych konfiguracyjnych. Jest bardzo wygodny w użytkowaniu.

Czemu?

Na przykład masz 2 źródła danych w swoim projekcie. I możesz wybrać, która z nich jest włączona.

  • mysql
  • json

Gdzieś w wybranym pliku konfiguracyjnym:

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

Po zmianie źródła cała aplikacja powinna przełączyć się na nowe źródło danych, działa dobrze i nie wymaga zmiany kodu.

Przykład:

Konfiguracja:

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

Klasa singleton:

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;
    }
}

... i gdzieś w swoim kodzie (np. w jakiejś klasie usług):

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

Obiekt AppConfig możemy pozyskać z dowolnego miejsca w systemie i zawsze uzyskać tę samą kopię (dzięki statyce). W konstruktorze wywoływana jest metoda init () klasy, co gwarantuje tylko jedno wykonanie. Sprawdzenie treści Init () Wartość config $ dataSource i utwórz nowy obiekt określonej klasy źródła danych. Teraz nasz skrypt może pobrać obiekt i operować na nim, nie wiedząc nawet, która konkretna implementacja faktycznie istnieje.

Sebastian Skurnóg
źródło
1

Zwykle tworzę pojedynczy plik conn.php, który ma połączenia z bazą danych. Następnie dołączam ten plik do wszystkich zbiorów, które wymagają zapytań do bazy danych.

Mihir Chhatre
źródło
1
Wiem o tym, ale jak zapisujesz plik bazy danych, ze zmienną lub stałą? i dlaczego?
Ali Akbar Azizi
0

Oto moja droga.

<?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";

?>

Wszelkie wątpliwości prosimy o komentarz

Alok Rajasukumaran
źródło
3
Cześć! Czy mógłbyś podać przykład użycia? Dziękuję
Nick