在PHP中创建配置文件


101

我想为我的PHP项目创建一个配置文件,但是我不确定执行此操作的最佳方法是什么。

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

1用途变量

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

2用const

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

3用途数据库

我将在类中使用config,因此我不确定哪种方法是最佳方法,或者是否有更好的方法。


12
4)使用ini文件。5)使用YAML文件。6)使用JSON文件。7)...有很多方法...定义一些标准至少可以判断,没有总体“最佳”。
deceze

@deceze是什么禁食方式?(记忆快速)
Ali Akbar Azizi 2013年

这应该是你一个有趣的阅读则:stackoverflow.com/questions/823352/...
eithed

1
我使用Laravel的方式(不使用Laravel时)。我创建了一个根据主机名加载特定配置文件的类。然后,我使用调用它Config::get('key');pastebin.com/4iTnjEuM
MisterBla 2015年

Answers:


217

一种简单而优雅的方法是创建一个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 '16

1
@NickGames,您必须将文件放在非公共文件夹中,否则您将面临严重的安全风险
Marcio Mazzucato

2
@NickGames,请查看parse_ini_file()文件中
R Picheta

19
我喜欢这种方法。温馨提示:将文件重命名为app.ini.php。然后添加到第一行;<?php die(); ?>。如果此文件意外出现在公共文件夹中,它将被视为PHP文件并在第一行消失。如果使用读取文件,则由于parse_ini_file,会将第一行视为注释;
andreas

1
注意:如果ini文件中的值包含任何非字母数字字符,则需要将其用双引号")引起来。例如,任何密码都包含非字母数字字符。
Key Shang

24

我使用@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(...);一种调用。


为什么要使其成为对象?
TheCrazyProfessor

4
将其作为对象使数据处理变得更加容易。例如,它允许app_info使用最少的代码行将所有参数作为JSON 获取到JavaScript。
BoDeX

从PHP 5开始,对象还具有通过引用传递的副作用。这可能不是好事。数组按值传递(但实现为COW),因此最好使用配置数组而不是配置对象。
Mikko Rantalainen

@BoDeX我一直喜欢这种方式,并且在大多数文章中似乎都是最受欢迎的方式,但是我将如何通过类访问它呢?我在安全性文章中读到,创建全局变量不是一个好主意,那么您有何建议?
Kevlwig

22

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

基于文件的机制

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

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

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

PHP代码

这为表示不同的数据结构提供了极大的灵活性,并且(假定通过包含或要求处理了它)解析后的代码将可从操作码缓存中获得,从而带来性能优势。

所述的include_path提供用于提取的文件的潜在位置,而不依赖于额外的代码的装置。

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

如果配置是通过工具创建的,则可以验证工具中的数据,但是没有标准函数可以像HTML,URL,MySQL语句,shell命令那样,将要嵌入PHP代码的数据转义。 。

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

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

由于可以序列化对象,因此确实可以通过读取配置文件(__wakeup magic方法)来调用代码。

结构化文件

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

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

数据库存储

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

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

执行环境

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

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

在客户端上

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

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

网络目录 存储配置信息的另一个有趣的地方是DNS / LDAP。这将适用于少量的小信息-但您无需遵循第一标准格式-例如SPF

基础架构支持缓存,复制和分发。因此,它非常适合大型基础架构。

版本控制系统

像代码这样的配置应该进行管理和版本控制-因此,直接从VC系统获取配置是可行的解决方案。但是通常这会带来很大的性能开销,因此建议使用缓存。


6

好吧-将您的数据库配置数据存储在数据库中有点困难-是吗?

但是,实际上,这是一个非常自以为是的问题,因为任何样式都确实有效,而这全都取决于偏好。就个人而言,我会选择配置变量而不是常量-通常是因为除非必要,否则我不喜欢全局空间中的事物。我的代码库中的所有功能都不能轻易访问我的数据库密码(数据库连接逻辑除外)-因此我会在那里使用它,然后可能会破坏它。

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


2

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


什么是执行php的最快方法?const还是var?
Ali Akbar Azizi

1
@CooPer定义常量比定义变量要慢得多。但是使用它们会更快一些。由于这些将在一个地方使用,因此变量总体上将提供更高的性能。
Colin M

“明显地”是个繁重的词,如果您以这种方式看待它,也许您应该联系php开发人员并要求他们删除持续的支持!
phpalix

@phpalix定义常数可能比定义具有相同值的变量慢10到20倍。我说那很重要。但是,如果您在整个应用程序中都大量使用该常数,则很可能会得到回报。但是不建议创建一个常量一次使用它。
Colin M,

2

如果您出于某种原因认为将使用1个以上的数据库,请使用该变量,因为您可以更改一个参数以切换到完全不同的数据库。即用于测试,自动备份等。


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



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
你好!你能举一个例子吗?谢谢
Nick
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.