Creating a "two way" configuration file - php

I am writing a PHP application targeted at non-geeks, non-programmers. I need to create an option page with a bunch of "options" and then store those options...somewhere. Using a database application (MySQL/PostgreSQL/SQLite) is out of the question because it will require more configuration than the user needs to do (I don't want the user to do any kind of configuration if he doesn't want to). So the only solution left is to write the configuration to a configuration file. On the other hand, I also want that configuration file to be human-readable in case the user is a geek and he wants to edit the config file directly (or if he wants to edit the file remotely via SSH or any kind of reason...)
Here are the couple of potential solutions I found:
Using a JSON file...
...Retrieve the data from the file, using json_decode to convert the data, output it into HTML, retrieve any changes, encode back using json_encode, etc. You get the picture. There are a couple things that I don't like about this method, the main one being that the encoded JSON data using PHP will no be well formatted and very hard to edit without being reformatted beforehand.
Using an XML file
I won't describe that solution because I don't really like it either...and I don't know how to use XSLT and don't really want to learn...and because it's a pretty heavyweight solution, at least compared to the JSON solution. Correct me if I'm wrong.
Using an INI file
I love INI files, really I love them! I think they're really the most readable, and it's hard to mess up (ie: syntax errors). The problem with that solution is that there is no native way to write/edit an ini file. I found a topic showing a custom method to write one...that might be the solution I will adopt if I don't find anything better...
Using two files
That last solution seems as reasonable as the INI solution. In fact, I could use an INI file as "input" (the file that the user would edit if he wants to) and an XML/JSON file as output (the file that will be edited by PHP every time the user changes options using the web front-end). At this point, the best solution would be to ask the user to reload the configuration manually if he edited the config file directly, so that the "output" file is always up to date.
I know none of the solutions above are perfect, and that's why I created this topic to ask for advice. What is the best solution? Maybe (probably) I missed yet another solution.
One last thing: YAML isn't a valid solution because it's a lot easier to mess up the syntax if you're not used to it. PHP is not a solution either because editing PHP with PHP is a pain. PHP is only a good solution if I want to retrieve some configuration but not edit it directly via a web front-end.

ini
I'd write ini files, myself. As you said, the syntax is very simple, and that's what you want in a config file. The ini format's "key+value" pairing is exactly what you'd get with a database—without the database.
Related SO you may have seen already: create ini file, write values in PHP
Plus you can use parse_ini_file() to read it.
XML
XML isn't all that bad. It may be more work to write it (and may not be as clear to the user as an ini file), but reading it is really easy.
Create it:
<?php
// Create file
$xml = new SimpleXMLElement( '<?xml version="1.0" ?><config></config>' );
// Add stuff to it
$xml->addChild( 'option1' );
$xml->option1->addAttribute( 'first_name', 'billy' );
$xml->option1->addAttribute( 'middle_name', 'bob' );
$xml->option1->addAttribute( 'last_name', 'thornton' );
$xml->addChild( 'option2' );
$xml->option2->addAttribute( 'fav_dessert', 'cookies' );
// Save
$xml->asXML( 'config.xml' );
?>
Read it:
<?php
// Load
$config = new SimpleXMLElement( file_get_contents( 'config.xml' ) );
// Grab parts of option1
foreach( $config->option1->attributes() as $var )
{
echo $var.' ';
}
// Grab option2
echo 'likes '.$config->option2['fav_dessert'];
?>
Which gives you:
billy bob thornton likes cookies
Documentation for SimpleXML
SimpleXML Docs index
Basic Examples
Details on addChild() and addAttribute(), showing how to generate various XML structures (nested tags vs. attributes, for example)

I'd go with the ini. They're really not that hard to write. I personally hate XML. It's so bloated... even if the file size doesn't matter, it still makes me cringe at it's wordiness and the amount of typing I have to do. Plus, people are dumb. They won't close their tags.

The standard way would be XML files. They don't create that much overhead and are easily extensible. However, JSON files are the easiest on the programming end.
I'd rank my preference:
XML
JSON
ini (last resort)

Unless you have 1000+ options, you really shouldn't worry about the XML file size. The goal here is to keep things easy for the user. This means that whichever method you choose (JSON shouldn't be one of them in my opinion), it should be heavily documented at each config line.
Your two file solution brings me back to the days of sendmail config and makes me shudder.
I would just go with XML, it's self documenting to a point <Email>hi#hi.hi</Email>

Well, you could use PHP's serialize(), and although it is human readable, it isn't the most human readable thing there is. It's on the same level as JSON to implement.

Related

php ini vs json and halt compiler hack

I am debating on using either a configuration.ini or config.json for my administration dashboard I am designing. I like that ini is more for configuration purposes but with todays interest in JSON it seems more logical for the configurations be designed with json in mind.
Question here is should I use json for sure? And secondly I have this hack currently on my configuration.ini file which prevents the file being seen publicly.
;<?php exit(); __halt_compiler();
; //to stop script execution if not used in our best interest!
; //remember this format
//ini stuff
;?>
I was wondering if I could use this with the json file as well? I haven't tested it just because I didn't want nothing strange completely screwing everything up.As well as a good description as to why this works, now I know this won't work specifically with JSON since the ; is ini based commenting so could it be transformed to // or /**/ for json?
For interest purposes this is currently my admin__autoload.php page
set_include_path(dirname($_SERVER["DOCUMENT_ROOT"]));
$ini = parse_ini_file("configurations.ini",true);
foreach($ini as $section=>$values) {
foreach($values as $key=>$value ) {
define("__".strtoupper($key)."__",$value);
}
}
spl_autoload_register(function($class) {
if(!file_exists(get_include_path(). DIRECTORY_SEPARATOR .__ADMIN__."classes/{$class}.php")) {
echo get_include_path(). DIRECTORY_SEPARATOR .__ADMIN__."classes/{$class}.php does not exist";
} else {
include_once get_include_path(). DIRECTORY_SEPARATOR .__ADMIN__."classes/{$class}.php";
}
});
__ADMIN__ was created with the foreach loop from my ini file.
I think you're asking two different questions here.
Which configuration format will best suite my needs
How do I prevent my configuration files from being accessed by the public
The answer to 2 is easy. Don't put your configuration files in your public document root.
As far as choosing between INI or JSON, it's rather subjective without understanding the use case very clearly.
INI is more expressive for the reader but harder to parse. JSON is quite portable as a serialization format, but harder to read as a human.
So if you're manually editing the configuration file a lot, it makes sense to go with INI as its slightly disambiguated than JSON. If you're doing the editing through an autonomous process or one that otherwise requires portability across disparate systems, JSON may be more convenient.
A third alternative is YAML, which is a good middle ground between the human-readable aspect of INI, and the portability of JSON.

writing a structured ini file from scratch via PhP

Im creating a picture viewer for a friend of mine but i am unable to use a database because his hosting doesn't allow one.
So im left trying to use ini files but i dont know how to write a structured ini file using php..i have successfully put together a script to read it via parse_ini_file() and break it down into it seperate categories and keys but i need to know how to write the acctuall structure if there isn't one already.
For example
[flowerpics]
picone = filelocation
pictwo = filelocation
[artpics]
picone = filelocation
this is how im basing my parse_ini_file() script for ...so what if he wants to add a whole new category to this file ..lets say he wants to add "Rockandrollpics" ...how can i go about adding that into an ini file?
If I were you, I would consider using some standard - like JSON, YAML, or even BJSON - it's almost as simple as INI files, but gives you more control about structuring the data. Your example with JSON:
"flowerpics"
{
"picone" : "filelocation";
"pictwo" : "filelocation";
}
"artpics"
{
"picone" : "filelocation";
}
If you don't use Mysql you can try to use SqlLite instead of.
You needn't anything except php extension sqllite.
Look at http://php.net/manual/en/book.sqlite.php for more info.

MultiLenguage XML for php integration

i have a web site, in where i want to show some strings that may change according to the user lenguage and other parameters. I was thinking in a xml file like:
<strings>
<EN>
<userop1>This is the option 1<userop2>
</EN>
<ES>
<userop1>Esta es la opcion 1<userop1>
</ES>
</strings>
Then, using php something like: echo("You select: ".$userop1);
I really dont know if this is the most inteligent way to strutture the xml, so im asking for suggestiona (please with an example reading script). Thanks for any help!
Why are you using XML, this is an OVER HEAD in performance.
you should use Constants or Arrays.
$lang['en']['title'] = "title";
or separate files for each constants set/language
file: tranlate.en.php
defile('TITLE' , 'title');
since PHP is stateless, every page hit in your app will cause the system to parse this string.
no need for that
I think you shouldn't have all languages in a single xml file - it may get too big, will be harder to maintain, and so. Instead, make a xml for each language.

PHP: Where should I store the text for info & warning messages

I have a question concerning the design of my project's Code.
In most cases, it is important to separate content from code (HTML mixed with PHP in bigger apps=No good idea, etc.) but how should I handle things like the text of error messages?
Assuming this one message will be only used in one case/PHP file:
MessageBox( 'Something gone wrong, probably your fault' );
or
MessageBox( Lang::error_usersfault );
(Where Lang is a class located in some config file, full of consts)
If you have any experiences (I think every PHP programmer will come across something like this) with things like in the example above - What are they? How do you solve it?
What is the better solution?
May be you'll find php extension gettext useful?
MessageBox(_("Have a nice day"));
PHP Manual of Gettext::gettext

Storing, Updating, Retrieving settings for a PHP Application without a Database

I need to be able to store data for a php application in a file. I need to be able to do this without any sort of external dependencies other than PHP itself.
Here are the requirements I have:
Settings will not be updated/added/removed very often. So updating of settings does not have to be very efficient. However, I do want to be able to do this all through a PHP script, not through editing of files.
Settings will be read constantly, so reading of settings must be very efficient.
Settings are in a unique format, if I had them in an array it might be something like $Settings["Database"]["AccessSettings"]["Username"]["myDBUsername"]; $Settings["Database"]["AccessSettings"]["Password"]["myDBPassword"];
I would prefer to not have settings stored in arrays like I mentioned above. Instead I would prefer some access methods: getConfig("Database","Accesssettings","Username") would return 'myDBUsername'. The reason for this is I want to limit the variables I am storing in the global scope.
What would the best way of getting/retrieving these be?
Do the the hierarchy I was thinking possibly an xml file, but I wasn't sure what PHP was like for accessing xml files (particularly the fact that I need to be able to add, edit, and remove). If it should be XML what sort of xml access should I look into.
If it is another format, I would like some pointers to the right direction for what to look into for how to use that format.
Brian, parse_ini_file is what you need.
Ah, I missed the requirement that you'd be editing this via PHP.
In that case there is nothing native to PHP that you can use for this purpose. You'd have to roll your own.
You could save yourself a ton of time by simply using Zend_Config_Ini though. I know you state that you don't want to use anything else, but Zend Framework is structured to allow you to use whatever pieces of it you need. Zend_Config can be used on it's own. You can certainly just add these few classes to your project and let them handle your INI file parsing.
Here is an example using your samples above:
[config]
Database.AccessSettings.Username = myDBUsername
Database.AccessSettings.Password = myDBPassword
You would load and access this as simply as:
$config = new Zend_Config_Ini('/path/to/ini', 'config');
echo $config->Datbase->AccessSettings->Username; // prints "myDBUsername"
echo $config->Datbase->AccessSettings->Password; // prints "myDBPassword"
To edit and save your config you would use the following:
$config->Database->AccessSettings->Password = "foobar";
$writer = new Zend_Config_Writer_Ini(array('config' => $config,
'filename' => 'config.ini'));
$writer->write();
Edit
Not really sure why people are voting this down based on vog's misguided comments. It is very simple to make this writable by multiple persons by using an exclusive lock. Zend_Config_Writer uses file_put_contents to do it's writing, which has always supported the the LOCK_EX flag, which exclusively locks a file for writing. When using this flag, you cannot have multiple writers attempting to update the file at the same time.
To use this flag with Zend_Config_Writer it's as simple as follows:
$writer = new Zend_Config_Writer_Ini(array('config' => $config,
'filename' => 'config.ini'));
$writer->setExclusiveLock(true);
$writer->write();
An alternate syntax:
$writer = new Zend_Config_Writer_Ini();
$writer->write('config.ini', $config, true); // 3rd parameter is $exclusiveLock
If you're not hand editing, use serialized data.
Writing config using serialize:
file_put_contents('myConfig.txt', serialize($Settings));
Reading config using unserialize:
$Settings = unserialize(file_get_contents('myConfig.txt'));
You could write a class for modifying and getting values for this data using PHP magic functions __get() and __set().
If you are willing to drop in a library, you could use Spyc and have your configuration in a YAML file.
You could also use PHP's support for SQLite which would mean your database is just a file so no need for a DB server.
DBM files may not be a bad idea. PHP has built in support for the various DBM-file varieties:
http://www.php.net/manual/en/book.dba.php

Categories