Using define() when mass building, Pros? Cons? - php

I mass produce very similar sites, meaning they all use the same basic components, pages and are all single industry specific. These are my low end deeply discounted site designs. None of these sites ever get more than 20-30 visitors a day, so any extra load on the server isn't an issue.
In the interest of time, being that they all use the same components, though they may be in different locations or in a different order I would like to write one definition file that can be included with every site, so I can just call the defined constant instead of writing out the code a couple hundred times every year on every site I build. Also for editing later purposes this would make my life MUCH easier.
the definition file would look similar to the following:
define('UPCONTACT','<h1>Contact Us</h1>');
define('ULCONTACT','Contact Us');
define('UPABOUTUS','<h1>About Us</h1>');
define('ULABOUTUS','About Us');
Obviously this is a very basic example but I think you get the idea.
So the question is what are the pros and cons of using define() in this manner?

It's pretty much ok. The disadvantage is that, given you are using constants, you can't override them for a single page or site.
Use an array instead:
config.php
return array(
'aboutus' => '<h1>About Us</h1>',
'contactus' => 'Contact Us'
);
include it like this in your site:
$config = include('config.php');
Then you can print it very easily
<?php echo $config['aboutus'] ?>
You can also change a value when you need it:
$config = include('config.php');
$config['aboutus'] = '<h1>About My Company</h1>';
This is probably your best option.

It has upsides and downsides.
The upsides involve that such way is quicker than loading settings from a database (and creating a database; and creating an abstraction layer, ...).
The downsides involve that such way is not customizable by the client. If they need a change, ensure beforehand the website is static and you will charge them by every change.
IMHO it is better to have some stuff as customizable by the client, and other stuff not. But there's no technical issue at all by using define() in that way (except perhaps allowed datatypes).

A better way to use a ini file or something like that.
(and easily editable from a smartphone if it's a recursive task for you :)
Look for a builtin php function, can make simplify your life
http://php.net/manual/fr/function.parse-ini-file.php
or if you would a more stronger and flexible system,
go for templating (looking for smarty, or self made regex templating)
Looking for my first regex function (loong years ago)
Quitting Smarty to do it manually
Note:
Using Constant does not provide you to dynamically modifying them
inline code, and are poor supported type (you cannot store an array without serialize for example)

I would suggest cascaded ini files:
$conf_dir = dirname(__FILE__);
$config = array_merge_recursive(
parse_ini_file($conf_dir.'base.ini'),
parse_ini_file($conf_dir.'client.ini')
);
The benefits are readability, inability of execution (I like to lock things down that can be), and you can track the base ini in git (or whatever you use) and not the client one. There are some downsides, but such is life. The just feel cleaner, but they are not faster than .php, to be sure.
And if you wanted to eliminate any redundant execution (listen, any "performance benefit" still has "benefit" in it), serialization:
<?php
define('CACHE_DIR', '/tmp/');
// where 'http' is a path part that directly follows the app root, and will always
// be below where this file is called from.
$ini_cache = CACHE_DIR.'config.ser';
if(!file_exists($ini_cache)) {
// Build your config in any way you wish.
$conf_dir = dirname(__FILE__);
$config = array_merge_recursive(
parse_ini_file($conf_dir.'base.ini'),
parse_ini_file($conf_dir.'client.ini')
);
// Store it serialized
file_put_contents($ini_cache, serialize($config));
} else {
$config = deserialize(file_get_contents($ini_cache));
}
You can get more creative with this, but essentially, this allows you to store/generate your configuration in any way you wish. If you wanted to not have to delete the serialized cache on every change, you could add an atime check:
<?php
define('CACHE_DIR', '/tmp/');
// where 'http' is a path part that directly follows the app root, and will always
// be below where this file is called from.
$ini_cache = CACHE_DIR.'config.ser';
$conf_dir = dirname(__FILE__);
$config = array();
if(file_exists($ini_cache)) {
$client_stat = stat($conf_dir.'client.ini');
$cache_stat = stat($ini_cache);
if($client_stat['atime'] < $cache_stat['atime']) {
$config = deserialize(file_get_contents($ini_cache));
}
}
if(empty($config)) {
// Build your config in any way you wish.
$config = array_merge_recursive(
parse_ini_file($conf_dir.'base.ini'),
parse_ini_file($conf_dir.'client.ini')
);
// Store it serialized
file_put_contents($ini_cache, serialize($config));
}
With either serialization method, you can use what ever $config generation scheme you prefer, and if you use PHP, you can even get real creative/complicated with it, and the cached hit to the page will be negligible.

Related

glob() to build array of files, or hardcode array? Speed is key, but automation is nice

Sorry for the undescriptive title, wasn't to sure what to title this :-)
I have written an API that loads required javascript libraries from a directory on my server. The directories have a specific format, the only thing that can differ is the file name format within each libraries' directory.
The Directory Format
_js/_source/_library_name_here/file_name_here.js
e.g.
/_js/_source/_fancybox/jQuery.lightbox-0.5.js
The array (currently hardcoded)
At the moment I have the separate libraries stored in an array (hardcoded) like so:
$js_libraries = array(
'fancybox' => '/_js/_source/_fancybox/jQuery.lightbox-0.5.js',
'something_else' => '/_js/_source/_something_else/jQuery.something.js'
);
Potential Alternative
This API would be a lot more dynamic if the $js_libraries array was built automatically from scanning the '_source' directory and populating the array like that. I would do this with something like (not tested, just an example!):
function gather_files($directory){
$files_and_folders = scandir($directory);
foreach($files_and_folders as $value){
if($value != '.' && $value != '..'){
if(is_dir($directory.'/'.$value)){
listFolderFiles($dir.'/'.$ff);
}
}
}
}
$js_libraries = gather_files(dirname(__FILE__));
The above is not completed, just wanted to demonstrate what I mean by building the array automatically based on the contents of the directory
My Question
Quite simply, the key of this API is speed as it is returning packed/minified (by PHP on the fly) javascript files to an HTML page and therefore cannot have any lag as this will delay the initiation of the page. What I would like to know, is, will the automatic method be noticable slower when there are a lot of libraries in this directory? Should I just stick with the hardcoded array?
Always benchmark
For actual speed, listing deep filesystem hierarchies are probably more IO bound than anything else, but please don't believe me, or don't believe your own intuition, always benchmark.
As for optimization: Speed is not the only option, you could go for low memory usage, and use the GlobIterator class or combine the other RecursiveDirectoryIterator, a custom subclass of FilterIterator and RecursiveIteratorIterator to get an object that can be used in foreach and returns the desired files, one at the time.

How to change header and footer dynamically?

Good morning,
I'm creating my own framework to use in my PHP projects, and I was thinking of some way that I could add .CSS files in the header part of the page, and .JS files and scripts in the footer (keeping HTML clean and valid), but - all this dynamically.
I mean, for example, imagine I have the following structure:
index.php
components
component1
component1.php
component1.js
component1.css
I would like to include each file I need dynamically in index.php for example, keeping the code clean.
And for example, imagine that I insert JS directly in component1.php, is it possible to dynamically add it to component1.js (without human job, to save time in future)
Thanks.
One possible way of doing it would be to represent your entire template/view/whatever-you-want-to-call-it as an object:
class View {
// ...
}
The index.php file could determine which component(s) to use, create them, and then poll them for any required CSS/JS files:
$view = new View();
foreach ($components as $component) {
$cmp = new $component();
$view->addCss($cmp->getCss());
$view->addJs($cmp->getJs());
}
Once everything has been included and such, then index.php can just render the entire thing:
$view->render();
Obviously this is just an example, and your syntax will vary, but hopefully you get the idea.
Edit: You could also make the logic a little more brief by simply adding components to the view directly, and have the view's internal logic handle polling/adding the CSS/JS, rather than index.php. Of course, it really depends on what a "component" is supposed to be in your framework, so I'll leave that up to you to decide.
A very simple example of how to include your js and css assets at the top, before you start outputting anything:
// somewhere in the beginning, before html output
$js = array();
$css = array();
$css[] = 'all_pages.css';
$js[] = 'all_pages.js';
if (some_condition_based_on_page)
{
$css[] = 'some_page_specific.css';
$js[] = 'some_page_specific.js';
}
...
// in your view where you build the head section
foreach ($css as $item)
{
echo "<link rel='stylesheet' href='{$item}' type='text/css'>";
}
...
// in your view where you build the footer
foreach ($js as $item)
{
echo "<link src='{$item}' type='text/javascript'>";
}
The simplest and more portable way would be to include all files matching a certain pattern, e.g., /components/component1/header.css
This would present two complications. One is performance (you need to check all the directories of all your components). The other is isolation of components, i.e., what happens if you need a given CSS to be included before or after another which might or might not be there?
You might try to solve both problems by including a "manifest" in each component, which could specify, at first, the location of any files and where they should be included. Then your processing is reduced to examining the "components" directory and decoding all manifests, and "compiling" this in a series of directive vectors (e.g. $CSSToBeIncludedInThisOrder[] ). You might also serialize the compiled object to a cached file. Of course, any alterations to components should include removal of the compiled meta-manifest.
Later on, you might include in the manifest instruction such as conditional priorities.
All this should be done BEFORE anything is sent to the client's browser (what if component ZZZ wishes to alter the ob_ state, or maybe the encoding, or is a download override component and wants to send a Content-Type of application/octet-stream?), but the "compilation" should allow to keep perceptual latency low.
So let me clarify:
1. index.php checks whether a metamanifest.cache file exists.
2. If it does, it runs something like
$__META = unserialize(file_get_contents($METACACHE));
and goes on to #4.
3. If it does not, opendirs/readdirs the components directory,
looks what files are there, decides (but does not do yet) what to do with them,
placing those decisions in $__META, e.g. $__META['HeaderJS'][].
4. Now HTML generation begins: the __META array is walked and everything that
needs doing gets done (headers, inclusion of JS in heads, etc.).
Phase #3 might even perform some duplicate checks or versioning, say you have two components that both need "jQuery.js" to be included; instead of blindly appending "/components/comp1/js/jQuery.js" and "/components/comp2/js/jQuery.js" to a __Meta['HeaderJS'], the system could declare a conflict or decide it is solved by including only one of them, thereby further reducing processing time.

Context-aware AJAX call in a modular site

Edit: I thought about a possible solution, but I made another question as it is very specific: see AJAX proxy with PHP, is it possible?
A couple of times I've encountered this problem...
I create sites that have a certain degree of modularity. So, it is possible that there are "components" (think of a rough CMS) which carry their own PHP code, CSS, and JavaScript, all dynamically included. Think about a structure like:
{siteroot}/component/datagrid/datagrid.php
{siteroot}/component/datagrid/js/datagrid.js
{siteroot}/component/datagrid/css/datagrid.css
{siteroot}/component/datagrid/ajax/getsomedata.php
Now, the question is: for JavaScript files, and expecially AJAX calls, how do I make them context-aware with the URLs?
For example, if in datagrid.js I want to call siteroot/component/datagrid/ajax/getsomedata.php with AJAX I should write (with JQuery):
$("#ajax").load("siteroot/component/datagrid/ajax/getsomedata.php");
First problem: siteroot changes on different installations. I've managed that by including a general
var codeBase = <? echo json_encode(Config::$siteRoot); ?>
with PHP on every page, from a Config file that can be easily edited for every installation, so I can do with whatever JavaScript something like:
$("#ajax").load(codeBase + "/component/Datagrid/ajax/getsomedata.php");
What do you think of this approach?
Second problem: but I have PHP functions that return to me also the components folder, or the folder of other components. It would be nice to make the whole URL dynamic. This would account also for changes in the structure of the component if I want.
The only solution I've found is to use a .js.php dynamic Javascript. This is very unelegant, and I have to include all the framework in the JavaScript file, like:
<?php
include "../../libs/framework.php"; // get my functions...
$myUrl = Config::$siteRoot . Framework::getComponentAjaxDir("datagrid") . "/getsomedata.php";
?>
$("#ajax").load(<?=json_encode($myUrl)?>);
Another side effect is that I have to know exactly the include the path for framework.php... I don't want this so hard-codedin my ".js.php" file.
Any smart solutions about that?
As nobody answered in a suitable way, I answer to myself to provide a solution I've found out that can be useful.
The key to my solution is simple:
I create an AJAX proxy at a fixed location in my site structure, so I can use codeBase to reference the proxy from JavaScript
I call this proxy with two parameters: plugin and action, which identify a) the plugin folder in which the "real" ajax is and b) the ajax file to use, along with the other params:
$("#...").load( codeBase + "/main/ajax.php?plugin=Datagrid&action=gettable&otherparams"...)
In ajax.php I sanitize the parameters, and use plugin and action to obtain the "real" ajax file:
{serverRoot}/components/{plugin}/ajax/{action}.php
Then i simply include that file in ajax.php
To be honest your problems are realistic options and aren't that bad practice in general quite frankly.
But let's explore this a little further.
What would be the best approach is for you to have 1 main config.php file which you can then specify modules, i.e. your datagrid etc.
You could store all modules in an array variable like so:
$_SITE_PATH = "/var/www/html/";
$_HTTP_PATH = "http://example.com/";
$_MODULES_PATH = $_SITE_PATH."modules/"
$_MODULES = array(
"datagrid"=>$_MODULES_PATH."datagrid/init.php",
"something_else"=>$_MODULES_PATH."something_else/init.php"
);
Each module would have it's own directory with instantiation init.php so that it would load all it required to get going.
This way you could code as you liked and when you needed something (preferably in the header state) do something like this.
global $_MODULES;
require_once($_MODULES["datagrid"]);
Everything will be easily available as and when required without any variable path issues later down the line.

Internationalization for navigation with Codeigniter

I'm trying to find the best way of structuring a multi-language site navigation,.
I'm aware of the language class in CI but it seems to be more for defining random words and lines of text that are used commonly throughout the site. It appears that creating lang files for each language and then defining translations of all the links seems like the standard approach?
In past on non-codeigniter projects I’ve setup one class like this
class Link{
var $name = array();
var $url;
var $links = array();
function add_link($links){
$this->links[] = $links;
}
}
$all_sections = array();
$section = new Link();
$section->name['en'] = "Home";
$section->name['fr']] = "Uberdurky";
$section->url = "/";
$sub_section = new Link();
$sub_section->name['en'] = "About Acme Ltd";
$sub_section->name['fr'] = "Fabuka Acme Ltd";
$sub_section->url = "/about/";
$section->add_link($sub_section);
Then I have a function to loop through and output the nav, which just looks at the current name[Lang] as defined by session or URL
This to me seems simpler and less overhead - with the benefit that both the nav structure and translations are defined in one place. But I’m new to CI so I might be misunderstanding the standard approach… ? I've googled quite a bit and haven't seen a solution here in detail.
The important thing is that it works for you. There are a lot of benefits to using separate language files:
Clean separation
Only load what you need
Easy to keep track of which languages are available
Ability to let others easily translate the files
I don't see anything wrong with the way you're doing it, but if you want to optimize - don't bother defining all the different language lines. You don't need the French version defined if the language is English. Use only the ones you need, you shouldn't have to pass the whole array to add_link(), the Link class should be detecting the language and loading the appropriate array only...
...it's starting to sound like a language file might be a good idea actually.
For now you just have French and English. I'm assuming you know both languages and (Uberdurky?) are the only one working on this aspect, so it's easier for you to define them "inline". What happens when you want to support 3, 4, or 10 languages? Things will quickly become disorganized and cluttered.
However, you don't have to use the Codeigniter Language class, you might be better off using your own system for something like navigation, which tends to be littered with 1 or two word translations, and changes somewhat frequently (either per site or between sites).
Once again, it's your call. Do what works best for you now and optimize later.
This might be helpful to anyone coming across this question.
https://github.com/cflynn07/CodeIgniterInternationalizationUtility
It's a script to take a cleanly structed HTML table of language translations, and convert them into the required language files used in codeigniter.

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