115

我想为我的 PHP 项目创建一个配置文件,但我不确定最好的方法是什么。

到目前为止,我有 3 个想法。

1-使用变量

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

2-使用常量

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

3-使用数据库

我将在课堂上使用配置,所以我不确定哪种方式最好,或者是否有更好的方式。

4

13 回答 13

248

一种简单而优雅的方法是创建一个config.php只返回一个数组的文件(或任何你称之为的文件):

<?php

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

接着:

$configs = include('config.php');
于 2013-02-07T13:44:57.183 回答
93

使用 INI 文件是一种灵活而强大的解决方案!PHP 有一个本地函数来正确处理它。例如,可以像这样创建一个 INI 文件:

应用程序.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 文件必须位于非公用文件夹中

于 2015-12-07T14:03:01.863 回答
28

我使用了@hugo_leonardo解决方案的轻微演变:

<?php

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

?>

这允许您在包含 php 时使用对象语法:$configs->host而不是$configs['host'].

此外,如果您的应用程序具有客户端所需的配置(例如 Angular 应用程序),您可以让此config.php文件包含您的所有配置(集中在一个文件中,而不是一个用于 JavaScript 和一个用于 PHP)。然后,诀窍是拥有另一个echo仅包含客户端信息的 PHP 文件(以避免显示您不想显示的信息,例如数据库连接字符串)。打电话说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(...);调用类型。

于 2016-10-16T06:08:10.257 回答
25

我看到的具有相对优点/缺点的选项是:

基于文件的机制

这些要求您的代码在特定位置查找 ini 文件。这是一个难以解决的问题,并且总是出现在大型 PHP 应用程序中。但是,您可能需要解决问题才能找到在运行时合并/重用的 PHP 代码。

常见的方法是始终使用相对目录,或者从当前目录向上搜索以查找在应用程序的基本目录中专门命名的文件。

用于配置文件的常见文件格式是 PHP 代码、ini 格式文件、JSON、XML、YAML 和序列化 PHP

PHP 代码

这为表示不同的数据结构提供了极大的灵活性,并且(假设它是通过 include 或 require 处理的)解析的代码将从操作码缓存中获得——从而提高性能。

include_path提供了一种在不依赖额外代码的情况下抽象文件潜在位置的方法。

另一方面,将配置与代码分离的主要原因之一是分离职责。它提供了将附加代码注入运行时的路径。

如果配置是从工具创建的,则可以验证工具中的数据,但没有标准函数来转义数据以嵌入到 PHP 代码中,如 HTML、URL、MySQL 语句、shell 命令...... .

序列化数据 这对于少量配置(最多约 200 项)相对有效,并且允许使用任何 PHP 数据结构。它只需要很少的代码来创建/解析数据文件(因此您可以花费精力确保仅在适当授权的情况下编写文件)。

自动处理写入文件的内容的转义。

由于您可以序列化对象,它确实创造了一个通过读取配置文件(__wakeup 魔术方法)来调用代码的机会。

结构化文件

按照 Marcel 或 JSON 或 XML 的建议将其存储为 INI 文件还提供了一个简单的 api,用于将文件映射到 PHP 数据结构(除了 XML,用于转义数据并创建文件),同时消除代码调用使用序列化 PHP 数据的漏洞。

它将具有与序列化数据相似的性能特征。

数据库存储

在您有大量配置但对当前任务所需的内容有选择性的情况下,这是最好的考虑 - 我惊讶地发现在大约 150 个数据项中,从本地 MySQL 实例检索数据比从反序列化数据文件。

OTOH 它不是存储用于连接数据库的凭据的好地方!

执行环境

您可以在PHP 运行的执行环境中设置值。

这消除了 PHP 代码在特定位置查找配置的任何要求。OTOH 它不能很好地扩展到大量数据,并且难以在运行时进行普遍更改。

在客户端

我没有提到存储配置数据的一个地方是在客户端。再次,网络开销意味着这不能很好地扩展到大量配置。并且由于最终用户可以控制数据,因此必须以可检测到任何篡改的格式(即使用加密签名)存储数据,并且不应包含任何因泄露而受到损害的信息(即可逆加密)。

相反,这对于存储最终用户拥有的敏感信息有很多好处 - 如果您没有将其存储在服务器上,则无法从那里窃取。

网络目录 存储配置信息的另一个有趣的地方是 DNS / LDAP。这将适用于少量的小信息——但你不需要坚持第一范式——考虑一下,例如SPF

基础设施支持缓存、复制和分发。因此,它适用于非常大的基础设施。

版本控制系统

配置,比如代码应该被管理和版本控制——因此直接从你的 VC 系统获取配置是一个可行的解决方案。但这通常会带来显着的性能开销,因此缓存可能是可取的。

于 2017-07-13T16:57:43.240 回答
6

嗯 - 将数据库配置数据存储在数据库中会有点困难 - 你不觉得吗?

但实际上,这是一个非常固执己见的问题,因为任何风格都非常有效,而且这都是偏好问题。就个人而言,我会选择配置变量而不是常量——通常是因为除非必要,否则我不喜欢全局空间中的东西。我的代码库中的所有函数都不能轻松访问我的数据库密码(我的数据库连接逻辑除外)——所以我会在那里使用它,然后可能会销毁它。

编辑:回答您的评论-解析机制都不是最快的(ini、json等)-但它们也不是您真正需要关注优化的应用程序部分,因为速度差异会在这样的小文件上可以忽略不计。

于 2013-02-07T13:43:29.817 回答
4

您可以创建一个配置类巫婆静态属性

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 对象,并且始终获取相同的副本(感谢静态)。类的init()方法在构造函数中调用,保证只执行一次。Init() body 检查 config $dataSource 的值,并创建特定数据源类的新对象。现在我们的脚本可以获取对象并对其进行操作,甚至不知道实际存在哪个具体实现。

于 2017-10-18T11:31:03.017 回答
2

定义将使常量在您的类中的任何地方都可用,而无需使用全局,而变量在类中需要全局,我会使用定义。但同样,如果 db 参数在程序执行期间发生变化,您可能需要坚持使用变量。

于 2013-02-07T13:43:01.913 回答
2

如果您认为出于任何原因将使用超过 1 db,请使用该变量,因为您将能够更改一个参数以切换到完全不同的 db。即用于测试、自动备份等。

于 2013-02-07T13:44:04.773 回答
1

这是我的方式。

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

   ?>

有任何疑问请评论

于 2015-04-13T06:37:11.263 回答
0

我通常最终会创建一个包含我的数据库连接的 conn.php 文件。然后我将该文件包含在所有需要数据库查询的文件中。

于 2013-02-07T13:41:14.897 回答
0

You can use this simple one:

define('someprop', 0);

and

echo someprop; // output 0

于 2021-12-15T09:03:51.690 回答
0

这样的事情呢?

class Configuration
{

    private $config;

    
    public function __construct($configIniFilePath)
    {
        $this->config = parse_ini_file($configIniFilePath, true);
    }

    /**
     * Gets the value for the specified setting name.
     *
     * @param string $name the setting name
     * @param string $section optional, the name of the section containing the
     *     setting
     * @return string|null the value of the setting, or null if it doesn't exist
     */
    public function getConfiguration($name, $section = null)
    {
        $configValue = null;

        if ($section === null) {
            if (array_key_exists($name, $this->config)) {
                $configValue = $this->config[$name];
            }
        } else {
            if (array_key_exists($section, $this->config)) {
                $sectionSettings = $this->config[$section];
                if (array_key_exists($name, $sectionSettings)) {
                    $configValue = $sectionSettings[$name];
                }
            }
        }

        return $configValue;
    }
}
于 2021-01-09T14:56:30.200 回答
0

如果我有一个像 config.conf 这样的配置文件(可以是 http://example.com/config.conf)

user=cacom
version = 2021608
status= true

这是我的功能:

function readFileConfig($UrlOrFilePath){

    $lines = file($UrlOrFilePath);
    $config = array();
    
    foreach ($lines as $l) {
        preg_match("/^(?P<key>.*)=(\s+)?(?P<value>.*)/", $l, $matches);
        if (isset($matches['key'])) {
            $config[trim($matches['key'])] = trim($matches['value']);
        }
    }

    return $config;
}

我们可以用:

$urlRemote = 'http://example.com/default-config.conf';
$localConfigFile = "/home/domain/public_html/config.conf";
$localConfigFile2 = "config.conf";

print_r(readFileConfig($localConfigFile2));
print_r(readFileConfig($localConfigFile));
print_r(readFileConfig($urlRemote));
于 2021-06-08T05:46:36.870 回答