Tạo một tệp cấu hình trong PHP


101

Tôi muốn tạo một tệp cấu hình cho dự án PHP của mình, nhưng tôi không chắc cách tốt nhất để thực hiện việc này là gì.

Tôi có 3 ý tưởng cho đến nay.

1-Sử dụng biến

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

2-Sử dụng Const

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

Cơ sở dữ liệu 3-Sử dụng

Tôi sẽ sử dụng cấu hình trong các lớp vì vậy tôi không chắc cách nào sẽ là tốt nhất hoặc nếu có cách nào tốt hơn.


12
4) Sử dụng tệp ini. 5) Sử dụng tệp YAML. 6) Sử dụng tệp JSON. 7) ... Có rất nhiều cách ... Xác định một số tiêu chí để đánh giá dựa trên ít nhất, không có "tốt nhất" tổng thể.
dối trá

@deceze cách fasted là gì? (bộ nhớ và nhanh)
Ali Akbar Azizi

Đây sẽ là một bài đọc thú vị đối với bạn sau đó: stackoverflow.com/questions/823352/…
bản vào

1
Tôi sử dụng cách Laravel thực hiện (khi không sử dụng Laravel đó là). Tôi tạo một lớp tải một tệp cấu hình cụ thể tùy thuộc vào tên máy chủ. Sau đó tôi gọi nó bằng cách sử dụng Config::get('key');. pastebin.com/4iTnjEuM
MisterBla,

Câu trả lời:


217

Một cách đơn giản nhưng thanh lịch là tạo một config.phptệp (hoặc bất cứ thứ gì bạn gọi) chỉ trả về một mảng:

<?php

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

Và sau đó:

$configs = include('config.php');

10
Tôi cũng thích phương pháp này - Tôi nghĩ nó rõ ràng hơn là chỉ khai báo một biến trong một tệp được bao gồm và giả sử nó sẽ ở đó trong tập lệnh của bạn
Colin M

Câu trả lời nằm ở đâu trong phương pháp tạo tệp cấu hình này? Đối với người mới làm quen với php như tôi?
Luka

@Luka Bạn có thể sử dụng hàm var_export .
Hasan Bayat

77

Sử dụng tệp INI là một giải pháp linh hoạt và mạnh mẽ! PHP có một hàm riêng để xử lý nó đúng cách. Ví dụ: có thể tạo tệp INI như sau:

app.ini

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

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

Vì vậy, điều duy nhất bạn cần làm là gọi:

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

Sau đó, bạn có thể truy cập các định nghĩa một cách dễ dàng bằng cách sử dụng $inimảng.

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

QUAN TRỌNG: Vì lý do bảo mật, tệp INI phải nằm trong thư mục không công khai


Điều này cũng an toàn để sử dụng? Nếu người dùng đoán đường dẫn đến tệp ini và truy cập vào đó trong trình duyệt của họ, họ có thấy những gì trong tệp không?
NickGames

1
@NickGames, Bạn phải đặt các tập tin trong một thư mục phi công, nếu không bạn sẽ phải chịu một nguy cơ bảo mật nghiêm trọng
Marcio Mazzucato

2
@NickGames, vui lòng xem 1 nhận xét trong Tài liệu của parse_ini_file ()
R Picheta,

19
Tôi thích cách tiếp cận này. Mẹo bổ sung: Đổi tên tệp thành app.ini.php. Sau đó thêm vào dòng đầu tiên ;<?php die(); ?>. Trong trường hợp tệp này vô tình xuất hiện trong một thư mục chung, nó sẽ được coi là tệp PHP và chết ở dòng đầu tiên. Nếu tệp được đọc với parse_ini_file, nó sẽ coi dòng đầu tiên là một nhận xét vì ;.
andreas

1
Lưu ý: Nếu một giá trị trong tệp ini chứa bất kỳ tự không phải chữ và số nào thì nó cần được đặt trong dấu ngoặc kép ( "). Ví dụ: bất kỳ mật khẩu nào chứa các ký tự không phải chữ và số.
Key Shang,

24

Tôi sử dụng một sự cải tiến nhỏ của giải pháp của @hugo_leonardo :

<?php

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

?>

Điều này cho phép bạn sử dụng cú pháp đối tượng khi bạn bao gồm php: $configs->hostthay vì $configs['host'].

Ngoài ra, nếu ứng dụng của bạn có các cấu hình bạn cần ở phía máy khách (như đối với ứng dụng Angular), bạn có thể có config.phptệp này chứa tất cả các cấu hình của mình (tập trung trong một tệp thay vì một tệp cho JavaScript và một tệp cho PHP). Sau đó, mẹo sẽ là có một tệp PHP khác echochỉ chứa thông tin phía máy khách (để tránh hiển thị thông tin bạn không muốn hiển thị như chuỗi kết nối cơ sở dữ liệu). Gọi nó nói get_app_info.php:

<?php

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

?>

Ở trên giả sử của bạn config.phpchứa một app_infotham số:

<?php

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

?>

Vì vậy, thông tin cơ sở dữ liệu của bạn vẫn ở phía máy chủ, nhưng thông tin ứng dụng của bạn có thể truy cập được từ JavaScript của bạn, ví dụ như một $http.get('get_app_info.php').then(...);loại lệnh gọi.


tại sao biến nó thành một đối tượng?
TheCrazyProfessor

4
Biến nó thành một đối tượng giúp cho việc xử lý dữ liệu dễ dàng hơn rất nhiều. Ví dụ, nó cho phép lấy tất cả các app_infotham số cho JavaScript dưới dạng JSON với các dòng mã tối thiểu.
BoDeX

Các đối tượng cũng có một tác dụng phụ là được chuyển qua tham chiếu kể từ PHP 5. Nó có thể là một điều tốt hoặc không. Mảng được truyền theo giá trị (nhưng được triển khai dưới dạng COW) vì vậy có thể tốt hơn nếu sử dụng mảng cấu hình thay vì đối tượng cấu hình.
Mikko Rantalainen

@BoDeX Tôi luôn thích cách này và có vẻ là cách tiếp cận được ưa chuộng trong hầu hết các bài báo, nhưng làm cách nào để truy cập cách này thông qua lớp? Tôi đọc trong bài báo bảo mật rằng tạo biến toàn cục không phải là một ý tưởng hay, vậy bạn đề xuất điều gì?
Kevlwig

22

Các tùy chọn tôi thấy có điểm tương đối / điểm yếu là:

Cơ chế dựa trên tệp

Những điều này yêu cầu mã của bạn phải tìm ở các vị trí cụ thể để tìm tệp ini. Đây là một vấn đề khó giải quyết và luôn xuất hiện trong các ứng dụng PHP lớn. Tuy nhiên, bạn có thể sẽ cần giải quyết vấn đề để tìm mã PHP được kết hợp / sử dụng lại trong thời gian chạy.

Các cách tiếp cận phổ biến cho điều này là luôn sử dụng các thư mục tương đối hoặc tìm kiếm từ thư mục hiện tại trở lên để tìm một tệp có tên riêng trong thư mục cơ sở của ứng dụng.

Các định dạng tệp phổ biến được sử dụng cho tệp cấu hình là mã PHP, tệp được định dạng ini, JSON, XML, YAML và PHP được tuần tự hóa

Mã PHP

Điều này cung cấp một lượng lớn tính linh hoạt để biểu diễn các cấu trúc dữ liệu khác nhau và (giả sử nó được xử lý thông qua bao gồm hoặc yêu cầu) mã được phân tích cú pháp sẽ có sẵn từ bộ nhớ cache opcode - mang lại lợi ích về hiệu suất.

Đường bao gồm cung cấp một phương tiện để trừu tượng hóa các địa điểm tiềm năng của tập tin mà không dựa vào mã bổ sung.

Mặt khác, một trong những lý do chính để tách cấu hình khỏi mã là phân tách trách nhiệm. Nó cung cấp một lộ trình để đưa mã bổ sung vào thời gian chạy.

Nếu cấu hình được tạo từ một công cụ, có thể xác thực dữ liệu trong công cụ, nhưng không có chức năng chuẩn nào để thoát dữ liệu để nhúng vào mã PHP như tồn tại đối với HTML, URL, câu lệnh MySQL, lệnh shell ... .

Dữ liệu được tuần tự hóa Điều này tương đối hiệu quả đối với lượng cấu hình nhỏ (lên đến khoảng 200 mục) và cho phép sử dụng bất kỳ cấu trúc dữ liệu PHP nào. Nó yêu cầu rất ít mã để tạo / phân tích cú pháp tệp dữ liệu (vì vậy, thay vào đó bạn có thể dành nỗ lực của mình để đảm bảo rằng tệp chỉ được viết với sự ủy quyền thích hợp).

Việc thoát nội dung được ghi vào tệp được xử lý tự động.

Vì bạn có thể tuần tự hóa các đối tượng, nó tạo cơ hội cho việc gọi mã chỉ đơn giản bằng cách đọc tệp cấu hình (phương thức phép thuật __wakeup).

Tệp có cấu trúc

Lưu trữ nó dưới dạng tệp INI theo đề xuất của Marcel hoặc JSON hoặc XML cũng cung cấp một api đơn giản để ánh xạ tệp vào cấu trúc dữ liệu PHP (và ngoại trừ XML, để thoát dữ liệu và tạo tệp) trong khi loại bỏ lệnh gọi mã lỗ hổng bảo mật bằng cách sử dụng dữ liệu PHP được tuần tự hóa.

Nó sẽ có các đặc điểm hiệu suất tương tự như dữ liệu được tuần tự hóa.

Lưu trữ cơ sở dữ liệu

Điều này được coi là tốt nhất khi bạn có một lượng lớn cấu hình nhưng phải chọn lọc những gì cần thiết cho tác vụ hiện tại - Tôi đã rất ngạc nhiên khi thấy rằng với khoảng 150 mục dữ liệu, việc truy xuất dữ liệu từ phiên bản MySQL cục bộ nhanh hơn là hủy số liệu hóa một tệp dữ liệu.

OTOH không phải là nơi tốt để lưu trữ thông tin xác thực bạn sử dụng để kết nối với cơ sở dữ liệu của mình!

Môi trường thực thi

Bạn có thể đặt giá trị trong môi trường thực thi mà PHP đang chạy.

Điều này loại bỏ bất kỳ yêu cầu nào đối với mã PHP để tìm kiếm ở một vị trí cụ thể cho cấu hình. OTOH nó không mở rộng quy mô tốt với lượng lớn dữ liệu và rất khó thay đổi trên toàn cầu trong thời gian chạy.

Trên khách hàng

Một nơi mà tôi chưa đề cập để lưu trữ dữ liệu cấu hình là ở máy khách. Một lần nữa, chi phí mạng có nghĩa là điều này không mở rộng tốt với số lượng lớn cấu hình. Và vì người dùng cuối có quyền kiểm soát dữ liệu, dữ liệu đó phải được lưu trữ ở định dạng mà mọi hành vi giả mạo đều có thể phát hiện được (tức là với chữ ký mật mã) và không được chứa bất kỳ thông tin nào bị xâm phạm bởi việc tiết lộ (tức là được mã hóa có thể đảo ngược).

Ngược lại, điều này có rất nhiều lợi ích cho việc lưu trữ thông tin nhạy cảm thuộc sở hữu của người dùng cuối - nếu bạn không lưu trữ thông tin này trên máy chủ, nó không thể bị đánh cắp từ đó.

Thư mục mạng Một nơi thú vị khác để lưu trữ thông tin cấu hình là trong DNS / LDAP. Điều này sẽ hiệu quả đối với một số lượng nhỏ thông tin - nhưng bạn không cần phải tuân theo dạng thông thường đầu tiên - hãy xem xét, ví dụ như SPF .

Cơ sở hạ tầng hỗ trợ bộ nhớ đệm, sao chép và phân phối. Do đó, nó hoạt động tốt cho các cơ sở hạ tầng rất lớn.

Hệ thống kiểm soát phiên bản

Cấu hình, như mã nên được quản lý và kiểm soát phiên bản - do đó, lấy cấu hình trực tiếp từ hệ thống VC của bạn là một giải pháp khả thi. Nhưng thường thì điều này đi kèm với chi phí hiệu suất đáng kể, do đó, bộ nhớ đệm có thể được khuyến khích.


6

Chà - sẽ rất khó để lưu trữ dữ liệu cấu hình cơ sở dữ liệu của bạn trong một cơ sở dữ liệu - bạn có nghĩ vậy không?

Nhưng thực sự, đây là một câu hỏi khá nhiều ý kiến ​​bởi vì bất kỳ phong cách nào cũng hoạt động thực sự và tất cả đều là vấn đề sở thích. Cá nhân tôi thích biến cấu hình hơn là hằng số - nói chung là vì tôi không thích những thứ trong không gian chung trừ khi cần thiết. Không có chức năng nào trong codebase của tôi có thể dễ dàng truy cập mật khẩu cơ sở dữ liệu của tôi (ngoại trừ logic kết nối cơ sở dữ liệu của tôi) - vì vậy tôi sẽ sử dụng nó ở đó và sau đó có thể sẽ phá hủy nó.

Chỉnh sửa : để trả lời nhận xét của bạn - không có cơ chế phân tích cú pháp nào là nhanh nhất (ini, json, v.v.) - nhưng chúng cũng không phải là phần ứng dụng của bạn mà bạn thực sự cần tập trung vào việc tối ưu hóa vì sự khác biệt về tốc độ sẽ không đáng kể trên các tệp nhỏ như vậy.


2

Định nghĩa sẽ làm cho hằng số có sẵn ở mọi nơi trong lớp của bạn mà không cần sử dụng toàn cục, trong khi biến yêu cầu toàn cục trong lớp, tôi sẽ sử dụng DEFINE. nhưng một lần nữa, nếu các tham số db thay đổi trong quá trình thực thi chương trình, bạn có thể muốn gắn bó với biến.


cách fastet để thực thi php là gì? const hoặc var?
Ali Akbar Azizi,

1
@CooPer Xác định hằng số chậm hơn đáng kể so với xác định biến. Nhưng sử dụng chúng sẽ nhanh hơn một chút. Vì chúng sẽ được sử dụng ở một nơi, các biến tổng thể sẽ mang lại hiệu suất cao hơn.
Colin M

"Đáng kể" là một từ hơi nặng nề cho điều đó, nếu bạn đang nhìn nó theo cách này, có lẽ bạn nên liên hệ với những người phát triển php và yêu cầu họ gỡ bỏ hỗ trợ liên tục!
phpalix

@phpalix Việc xác định một hằng số có thể chậm hơn từ 10-20 lần so với việc xác định một biến có cùng giá trị. Tôi muốn nói điều đó rất quan trọng. Tuy nhiên, nếu bạn sử dụng hằng số nhiều trong suốt ứng dụng của mình - nó có thể rất tốt. Nhưng việc tạo ra một hằng số để sử dụng nó một lần là điều không nên.
Colin M

2

Nếu bạn nghĩ rằng bạn sẽ sử dụng nhiều hơn 1 db vì bất kỳ lý do gì, hãy sử dụng biến vì bạn sẽ có thể thay đổi một tham số để chuyển sang một db hoàn toàn khác. Tức là để thử nghiệm, tự động sao lưu, v.v.


2

Bạn có thể tạo thuộc tính tĩnh phù thủy lớp cấu hình

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

thì bạn có thể đơn giản sử dụng nó:

Config::$dbHost  

Đôi khi trong các dự án của mình, tôi sử dụng mẫu thiết kế SINGLETON để truy cập dữ liệu cấu hình. Nó rất thoải mái khi sử dụng.

Tại sao?

Ví dụ, bạn có 2 nguồn dữ liệu trong dự án của mình. Và bạn có thể chọn phù thủy trong số họ được kích hoạt.

  • mysql
  • json

Ở đâu đó trong tệp cấu hình bạn chọn:

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

Khi bạn thay đổi nguồn toàn bộ ứng dụng, hãy chuyển sang nguồn dữ liệu mới, hoạt động tốt và không cần thay đổi mã.

Thí dụ:

Cấu hình:

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

Lớp 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;
    }
}

... và ở đâu đó trong mã của bạn (ví dụ: trong một số lớp dịch vụ):

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

Chúng ta có thể lấy một đối tượng AppConfig từ bất kỳ vị trí nào trong hệ thống và luôn nhận được cùng một bản sao (nhờ static). Phương thức init () của lớp được gọi là Trong phương thức khởi tạo, phương thức này chỉ đảm bảo một lần thực thi. Init () body kiểm tra giá trị của cấu hình $ dataSource và tạo đối tượng mới của lớp nguồn dữ liệu cụ thể. Bây giờ tập lệnh của chúng tôi có thể lấy đối tượng và hoạt động trên nó, thậm chí không biết triển khai cụ thể nào thực sự tồn tại.


1

Tôi thường kết thúc việc tạo một tệp conn.php duy nhất có các kết nối cơ sở dữ liệu của tôi. Sau đó, tôi đưa tệp đó vào tất cả các tệp yêu cầu truy vấn cơ sở dữ liệu.


1
tôi biết điều đó, nhưng làm thế nào bạn lưu tệp cơ sở dữ liệu của mình, với biến hoặc const? và tại sao?
Ali Akbar Azizi

0

Đây là cách của tôi.

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

?>

Mọi thắc mắc vui lòng comment


3
Xin chào! Bạn có thể vui lòng đặt một ví dụ về cách sử dụng? Cảm ơn bạn
Nick
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.