Creando un archivo de configuración en PHP

101

Quiero crear un archivo de configuración para mi proyecto PHP, pero no estoy seguro de cuál es la mejor manera de hacerlo.

Tengo 3 ideas hasta ahora.

Variable de 1 uso

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

Const de 2 usos

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

Base de datos de 3 usos

Usaré la configuración en clases, así que no estoy seguro de cuál sería la mejor o si hay una mejor.

Ali Akbar Azizi
fuente
12
4) Utilice un archivo ini. 5) Utilice un archivo YAML. 6) Utilice un archivo JSON. 7) ... Hay tantas formas ... Defina algunos criterios para juzgar al menos, no hay "mejor" en general.
diciembre
@deceze ¿cuál es la vía de ayuno? (memoria y rapidez)
Ali Akbar Azizi
Esta debería ser una lectura interesante para usted entonces: stackoverflow.com/questions/823352/…
Fecha de publicación
1
Utilizo la forma en que lo hace Laravel (cuando no estoy usando Laravel). Creo una clase que carga un archivo de configuración específico según el nombre de host. Luego lo llamo usando Config::get('key');. pastebin.com/4iTnjEuM
MisterBla

Respuestas:

218

Una forma simple pero elegante es crear un config.phparchivo (o como lo llame) que solo devuelva una matriz:

<?php

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

Y entonces:

$configs = include('config.php');
Hugo Mota
fuente
10
También me gusta este método; creo que es más limpio que simplemente declarar una variable en un archivo incluido y asumir que estará allí en su script
Colin M
¿Dónde está este método de respuesta para crear un archivo de configuración? ¿Para principiantes de php como yo?
Luka
@Luka Puedes usar la función var_export .
Hasan Bayat
77

¡Usar un archivo INI es una solución flexible y poderosa! PHP tiene una función nativa para manejarlo correctamente. Por ejemplo, es posible crear un archivo INI como este:

app.ini

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

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

Entonces, lo único que debe hacer es llamar:

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

Luego, puede acceder a las definiciones fácilmente usando la $inimatriz.

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

IMPORTANTE: Por razones de seguridad, el archivo INI debe estar en una carpeta no pública.

Marcio Mazzucato
fuente
¿Esto también es seguro de usar? Si un usuario adivinara la ruta al archivo ini y va allí en su navegador, ¿vería lo que hay en el archivo?
NickGames
1
@NickGames, debe poner el archivo en una carpeta no pública, de lo contrario estará bajo un grave riesgo de seguridad
Marcio Mazzucato
2
@NickGames, mire el 1 comentario en Docs de parse_ini_file ()
R Picheta
19
Me gusta este enfoque. Consejo adicional: cambie el nombre del archivo a app.ini.php. Luego agregue a la primera línea ;<?php die(); ?>. En caso de que este archivo aparezca accidentalmente en una carpeta pública, se tratará como un archivo PHP y desaparecerá en la primera línea. Si el archivo se lee con parse_ini_file, tratará la primera línea como un comentario debido al ;.
andreas
1
Nota: Si un valor en el archivo ini contiene caracteres no alfanuméricos , debe incluirse entre comillas dobles ( "). Por ejemplo, cualquier contraseña contiene caracteres no alfanuméricos.
Key Shang
24

Yo uso una ligera evolución de @hugo_leonardo 's solución :

<?php

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

?>

Esto le permite usar la sintaxis del objeto cuando incluye php: en $configs->hostlugar de $configs['host'].

Además, si su aplicación tiene configuraciones que necesita en el lado del cliente (como para una aplicación Angular), puede hacer que este config.phparchivo contenga todas sus configuraciones (centralizadas en un archivo en lugar de uno para JavaScript y otro para PHP). El truco entonces sería tener otro archivo PHP que echosolo contenga la información del lado del cliente (para evitar mostrar información que no desea mostrar como la cadena de conexión de la base de datos). Llámalo decir get_app_info.php:

<?php

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

?>

Lo anterior asumiendo que config.phpcontiene un app_infoparámetro:

<?php

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

?>

Entonces, la información de su base de datos permanece en el lado del servidor, pero se puede acceder a la información de su aplicación desde su JavaScript, por ejemplo, con un $http.get('get_app_info.php').then(...);tipo de llamada.

BoDeX
fuente
¿Por qué convertirlo en un objeto?
TheCrazyProfessor
4
Convertirlo en un objeto facilita mucho el manejo de los datos. Permite, por ejemplo, obtener todos los app_infoparámetros del JavaScript como un JSON con un mínimo de líneas de código.
BoDeX
Los objetos también tienen el efecto secundario de pasar por referencia desde PHP 5. Puede que sea algo bueno o no. Las matrices se pasan por valor (pero se implementan como COW), por lo que sería mejor usar matrices de configuración en lugar de objetos de configuración.
Mikko Rantalainen
@BoDeX me gusta de esta manera siempre y parece ser el enfoque preferido en la mayoría de los artículos, pero ¿cómo puedo acceder a esto a través de la clase? Leí en un artículo de seguridad que la creación de variables globales no es una buena idea, entonces, ¿qué sugieres?
Kevlwig
22

Las opciones que veo con méritos / debilidades relativas son:

Mecanismos basados ​​en archivos

Estos requieren que su código busque en ubicaciones específicas para encontrar el archivo ini. Este es un problema difícil de resolver y que siempre surge en grandes aplicaciones PHP. Sin embargo, es probable que deba resolver el problema para encontrar el código PHP que se incorpora / reutiliza en tiempo de ejecución.

Los enfoques comunes para esto son siempre usar directorios relativos, o buscar desde el directorio actual hacia arriba para encontrar un archivo nombrado exclusivamente en el directorio base de la aplicación.

Los formatos de archivo comunes que se utilizan para los archivos de configuración son código PHP, archivos con formato ini, JSON, XML, YAML y PHP serializado

Código PHP

Esto proporciona una gran cantidad de flexibilidad para representar diferentes estructuras de datos y (asumiendo que se procesa mediante incluir o requerir) el código analizado estará disponible en la caché de código de operación, lo que brinda un beneficio de rendimiento.

El include_path proporciona un medio para abstraer los lugares potenciales del archivo sin depender de código adicional.

Por otro lado, una de las principales razones para separar la configuración del código es separar las responsabilidades. Proporciona una ruta para inyectar código adicional en el tiempo de ejecución.

Si la configuración se crea a partir de una herramienta, puede ser posible validar los datos en la herramienta, pero no existe una función estándar para escapar de los datos para incrustarlos en el código PHP como existe para HTML, URL, declaraciones MySQL, comandos de shell ... .

Datos serializados Esto es relativamente eficiente para pequeñas cantidades de configuración (hasta alrededor de 200 elementos) y permite el uso de cualquier estructura de datos PHP. Requiere muy poco código para crear / analizar el archivo de datos (por lo que puede dedicar sus esfuerzos a asegurarse de que el archivo solo se escriba con la autorización adecuada).

El escape del contenido escrito en el archivo se gestiona automáticamente.

Dado que puede serializar objetos, crea una oportunidad para invocar código simplemente leyendo el archivo de configuración (el método mágico __wakeup).

Archivo estructurado

Almacenarlo como un archivo INI como lo sugiere Marcel o JSON o XML también proporciona una API simple para mapear el archivo en una estructura de datos PHP (y con la excepción de XML, para escapar de los datos y crear el archivo) mientras se elimina la invocación del código. vulnerabilidad utilizando datos PHP serializados.

Tendrá características de rendimiento similares a los datos serializados.

Almacenamiento de base de datos

Esto se considera mejor cuando tiene una gran cantidad de configuración pero es selectivo en lo que se necesita para la tarea actual; me sorprendió encontrar que en alrededor de 150 elementos de datos, era más rápido recuperar los datos de una instancia local de MySQL que anular la serialización de un archivo de datos.

¡OTOH no es un buen lugar para almacenar las credenciales que usa para conectarse a su base de datos!

El entorno de ejecución

Puede establecer valores en el entorno de ejecución en el que se ejecuta PHP.

Esto elimina cualquier requisito para que el código PHP busque en un lugar específico para la configuración. OTOH no escala bien a grandes cantidades de datos y es difícil de cambiar universalmente en tiempo de ejecución.

En el cliente

Un lugar que no he mencionado para almacenar datos de configuración es el cliente. Una vez más, la sobrecarga de la red significa que esto no se adapta bien a grandes cantidades de configuración. Y dado que el usuario final tiene control sobre los datos, deben almacenarse en un formato en el que se pueda detectar cualquier manipulación (es decir, con una firma criptográfica) y no debe contener ninguna información que se vea comprometida por su divulgación (es decir, cifrada reversiblemente).

Por el contrario, esto tiene muchos beneficios para almacenar información confidencial que es propiedad del usuario final; si no la almacena en el servidor, no puede ser robada desde allí.

Directorios de red Otro lugar interesante para almacenar información de configuración es DNS / LDAP. Esto funcionará para una pequeña cantidad de pequeños fragmentos de información, pero no es necesario que se ciña a la primera forma normal; considere, por ejemplo, SPF .

La infraestructura admite el almacenamiento en caché, la replicación y la distribución. Por tanto, funciona bien para infraestructuras muy grandes.

Sistemas de control de versiones

La configuración, como el código, debe administrarse y controlarse la versión; por lo tanto, obtener la configuración directamente desde su sistema de VC es una solución viable. Pero a menudo esto viene con una sobrecarga de rendimiento significativa, por lo que el almacenamiento en caché puede ser aconsejable.

symcbean
fuente
6

Bueno, sería un poco difícil almacenar los datos de configuración de su base de datos en una base de datos, ¿no cree?

Pero en realidad, esta es una pregunta con muchas opiniones porque cualquier estilo funciona realmente y todo es cuestión de preferencias. Personalmente, optaría por una variable de configuración en lugar de constantes, generalmente porque no me gustan las cosas en el espacio global a menos que sea necesario. Ninguna de las funciones en mi base de código debería poder acceder fácilmente a la contraseña de mi base de datos (excepto la lógica de conexión de mi base de datos), por lo que la usaría allí y luego probablemente la destruiría.

Editar : para responder a su comentario, ninguno de los mecanismos de análisis sería el más rápido (ini, json, etc.), pero tampoco son las partes de su aplicación en las que realmente debería concentrarse en optimizar, ya que la diferencia de velocidad sería ser insignificante en archivos tan pequeños.

Colin M
fuente
2

Define hará que la constante esté disponible en todas partes de tu clase sin necesidad de usar global, mientras que la variable requiere global en la clase, yo usaría DEFINE. pero de nuevo, si los parámetros de db cambian durante la ejecución del programa, es posible que desee seguir con la variable.

phpalix
fuente
¿Cuál es la forma más rápida de ejecutar php? const o var?
Ali Akbar Azizi
1
@CooPer Definir constantes es significativamente más lento que definir variables. Pero usarlos es un poco más rápido. Dado que estos se utilizarán en un solo lugar, las variables ofrecerían en general un mayor rendimiento.
Colin M
"Significativamente" es una palabra un poco pesada para eso, si lo mira de esta manera, tal vez debería contactar a los desarrolladores de php y pedirles que eliminen el soporte constante.
phpalix
@phpalix Definir una constante puede ser entre 10 y 20 veces más lento que definir una variable con el mismo valor. Yo diría que eso es significativo. Sin embargo, si usa la constante en gran medida a lo largo de su aplicación, puede que valga la pena. Pero no se recomienda crear una constante para usarlo una vez.
Colin M
2

Si cree que va a utilizar más de 1 db por cualquier motivo, elija la variable porque podrá cambiar un parámetro para cambiar a un db completamente diferente. Es decir, para pruebas, copias de seguridad automáticas, etc.

trigun0x2
fuente
2

Puede crear una clase de configuración con propiedades estáticas

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

entonces puedes usarlo simplemente:

Config::$dbHost  

A veces en mis proyectos utilizo un patrón de diseño SINGLETON para acceder a los datos de configuración. Es muy cómodo de usar.

¿Por qué?

Por ejemplo, tiene 2 fuentes de datos en su proyecto. Y puede elegir si está habilitado.

  • mysql
  • json

En algún lugar del archivo de configuración que elija:

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

Cuando cambia la fuente, toda la aplicación debe cambiar a una nueva fuente de datos, funciona bien y no necesita cambiar el código.

Ejemplo:

Config:

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

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

... y en algún lugar de su código (por ejemplo, en alguna clase de servicio):

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

Podemos obtener un objeto AppConfig desde cualquier lugar del sistema y obtener siempre la misma copia (gracias a static). El método init () de la clase se llama En el constructor, lo que garantiza una sola ejecución. El cuerpo de Init () comprueba el valor de config $ dataSource y crea un nuevo objeto de una clase de fuente de datos específica. Ahora nuestro script puede obtener un objeto y operar en él, sin saber siquiera qué implementación específica existe realmente.

Sebastián Skurnóg
fuente
1

Normalmente termino creando un solo archivo conn.php que tiene mis conexiones de base de datos. Luego incluyo ese archivo en todos los archivos que requieren consultas a la base de datos.

Mihir Chhatre
fuente
1
Lo sé, pero ¿cómo guarda su archivo de base de datos, con variable o constante? ¿y por qué?
Ali Akbar Azizi
0

Este es mi camino.

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

?>

Cualquier duda comenta

Alok Rajasukumaran
fuente
3
¡Hola! ¿Podría poner un ejemplo del uso? Gracias
Nick