Efficient way to handle multiple HTMLPurifier configs - php

I'm using HTMLPurifier in a current project and I'm not sure about the most efficient way to go about handling multiple configs. For the most part the only major thing changing is the allowed tags.
Currently I have a private method, in each class using HTMLPurifier, that gets called when a config is needed and it creates one from the default. I'm not really happy with this as if 2 classes are using the same config, that's duplicating code, and what if a class needs 2 configs? It just feels messy.
The one upside to it, is it's lazy in the sense that it's not creating anything until it's needed. The various classes could be used and never have to purify anything. So I don't want to be creating a bunch of config objects that might not even be used.
I just recently found out that you can create a new instance of HTMLPurifier and directly set config options like so:
$purifier = new HTMLPurifier();
$purifier->config->set('HTML.Allowed', '');
I'm not sure if that's bad form at all or not, and if it isn't I'm not really sure of a good way to put it to use.
My latest idea was to create a config handler class that would just return an HTMLPurifier config for use in subsequent purify calls. At some point it could probably be expanded to allow the setting of configs, but just from the start I figured they'd just be hardcoded and run a method parameter through a switch to grab the requested config. Perhaps I could just send the stored purifier instance as an argument and have the method directly set the config on it like shown above?
This to me seems the best of the few ways I thought of, though I'm not sure if such a task warrants me creating a class to handle it, and if so, if I'm handling it in the best way.
I'm not too familiar with the inner workings of HTMLPurifier so I'm not sure if there are any better mechanisms in place for handling multiple configs.
Thanks for any insight anyone can offer.

Configuration objects have one important invariant: after they've been used to perform a purification, they cannot be edited. You might be interested in some convenience methods that the class has, in particular, inherit, and you can load an array of values using loadArray.

I just wrote up a quick, simple config handler class.
You can view / use it # http://gist.github.com/358187/
It takes an array of configs at initialization.
$configs = array(
'HTML.Doctype' => 'HTML 4.01 Strict',
'posts' => array(
'HTML.Allowed' => 'p,a[href],img[src]'
),
'comments' => array(
'HTML.Allowed' => 'p'
),
'default' => array(
'HTML.Allowed' => ''
)
);
Directives put directly into the array are global and will be applied to all configs. If the same directive is set inside a named config, the value in the named config will be used.
Then you can grab a config like so:
$purifierConfig = new purifierConfig($configs);
$commentsConfig = $purifierConfig->getConfig('comments');
or, shorthand:
$commentsConfig = $purifierConfig['comments'];
If the requested config does not exist or no config is specified in the call, the default config will be returned.
I'll probably flesh it out at some point, but for now this works.
I was looking for how people handled such things in their projects or if there were any built in mechanisms that made something like this more steamlined, but I suppose my question was a bit too narrow in scope.

Related

Call method from class of unknown name

The title may be confusing, but I'm not sure how to word it otherwise. So I want to be able to initialize a class and call methods from it without knowing the class name before getting it from an array.
What I want to do
$modules = array(
'Forums' => array(
'class'=>'Forums',
'classVar'=>'forum'
)
);
foreach($modules as $name => $module) if ($module['enabled']) {
require_once('include/scripts/'.$module['link']);
$$module['classVar'] = new $module['class'];
$$module['classVar'] = $module['classVar'];
global $$module['classVar'];
}
However, I know that this is a roundabout way to accomplish this, and I need to know if there's an easier way, and if this is even logical.
The reason I want to do this is because what I'm working on will be able to accept modules, and I need to be able to get all of the stats from the modules and display them in the main admin panel, but there's no way to know if a module is enabled and running if I didn't create it. For instance, if someone created module.php that tracked how many times someone clicked a specific link, the software wouldn't natively know about it, and I need it to be able to get stats from it.
Hmm, you might be interested in the Singleton design pattern (http://en.wikipedia.org/wiki/Singleton_pattern and http://www.phptherightway.com/pages/Design-Patterns.html).
In this case you'd have a list of classes in your configuration array and call "getInstance()" when you actually want to do something with the actual module.
Also, have a look at the Factory pattern, it might be useful for your purposes as well.

Symfony 1.0 - Extend sfRouting

Anyone know if the following 'class' entry in routing.yml is possible in SF1.0? I tried to add it and override some methods like getInstance() and getCurrentRouteName(), but they never get called upon, even though I am making calls to them manually.
checkout_landing:
class: CustomRoute # Can I do this in SF1.0?
url: /checkout/landing/:k/*
param: { module: sharedCheckout, action: landing }
We have implemented this 'per-route' custom class configuration in SF1.2, but it doesn't seem to be working for SF1.0. I suspect for SF1.0 I will have to add a custom class entry to the factories.yml file which will affect all routes.
Bonus question: Anyone able to emulate the 'extra_parameters_as_query_string' in SF1.0? Right now, with the above url entry, and GET params are converted to pseduo sub-dirs, for example a querystring like:
$params = array('foo' => 'bar', 'pet' => 'dog');
$url = sprintf('#checkout_landing?%s', http_build_query($params));
// Looks like:
http://example.com/checkout/landing/foo/bar/cat/dog
// I need it to look like
http://example.com/checkout/landing?foo=bar&pet=dog
As you suspect, neither of those things is possible in sf1.0 without either making the compromise you suggest for a custom extension of sfRouting (in factories.yml), or adding the functionality of sf1.2+ for the extra_parameters_as_query_string.
I would suggest the easiest option for you is to upgrade to the last stable version of sf1.3 (sf1.3.11) and using the bundled sf10CompatPlugin to help you emulate the sf1.0 features you use in the existing app, while adding the sf1.2+ features you desire from the sf1.3 core.
There are very few compatibility errors from doing this, and I have used it myself on dozens of projects without any hitches.
I browsed the compiled cached code for routes, and sure enough in SF1.0 there are no custom object references based on 'Class' entries in the yaml file. However when I view compiled cache code for routes generated in SF1.4, the custom objects are available.
As upgrading is not an option, I opted to generate the urls the old fashioned way, manually.

Constants in Kohana

I've used codeigniter in the past but on my current project I'm making the switch to Kohana. What is the best practice on constants?
In codeigniter there is the actual constants.php, but going through Kohana's source I'm not seeing something similar.
Never used kohana, but after a quick googling I find that you can use the config API to create your own config that will house the constants you need.
This thread suggests that if you are storing database sensitive items, to place them in the database.php config, etc.. making them relative to the type of data they are storing.
I'm familiar with Kohana, but not CI so much, so I'm guessing a bit to what you mean by 'constants.' I believe the closest thing to this is indeed Kohana's config API. So, if you wanted to make templates aware of some site-wide constant like your site name, that's a great thing to use the config API for.
To accomplish this, you'll need to create a config file under your /config folder, probably in the /application directory. What you call it isn't very important, but since it contains site information, let's call it site.php.
To quickly get going, here is what you'll want to have in that file:
<?php defined('SYSPATH') or die('No direct script access.');
return array(
// Your site name!
'name' => 'Oh me, Oh my',
);
Now, you can bring this in to a template by doing something like:
A better way to do this (using dumb templating) would be to assign this as a template variable in your Controller. So, assuming you have some default controller set up, the code would be:
public function action_index() {
$this->template->site_name = Kohana::config('site.name');
}
And then your template would have something like this:
<title><?php echo $site_name; ?></title>
Kohana's config API is interesting because it is hierarchical, meaning you can override and merge new configuration values on top of existing config structures. When you call Kohana::config('site.name'), the engine looks through all the config files named site.php, runs all of those config files and merges the results in to an array. The application-level config files will overwrite modules, which will overwrite system, etc... Then, based on that result array, Kohana will attempt to find the 'name' key and return it.
Assuming you want global constants...the following worked well for me.
application/config/constants.php:
define('MY_COOL_CONSTANT', 'foo');
return array();
index.php:
Kohana::$config->load('constants');
MY_COOL_CONSTANT should then be available globally.

Can I have a default controller called if the called controller doesn't exist?

I'm trying to learn more about the codeigniter framework by porting an existing website to it -- something that's not too complex, or so I thought.
Currently the site is replicated for its users and presents personalized data based on the url, for example, Joe might have his site at:
www.example.com/joe
www.example.com/joe/random-page.php
And you'd replace "joe" with any given user name. The URLs need to be structured this way: /joe/ isnt FOR joe, its for joe's visitors, so I can't rely on a user login or method of this sort. I could switch to joe.example.com but would rather not.
Is there a way I can make this play nice with Code Igniter?
Currently, it would want to call the joe controller. My initial thought is trying to find a way to have a default controller called when a controller doesn't exist, but if some CI pros have advice on a different, better way to handle this, it would be great.
Upgrade to CodeIgniter 2.0 and use $route['404_override'] = 'controller'; or install Modular Extensions which does the same thing, but for now they use $route['404'] instead.
There are a number of different ways to go about this. Just be warned, both of these solutions require you to edit CI's core files. That means you can't upgrade without breaking these edits. Unfortunately hooks do not suitably address this issue.
The easy way:
line 188-195 in system/vodeigniter/CodeIgniter.php handle the logic for what happens when a controller is not found.
The harder but better way:
There is a hook (http://codeigniter.com/user_guide/general/hooks.html)
pre_controller
But this will not work! The reason is that this is called after the controller has been determined, but before anything is actually executed. In other words, it is too late. The next earlier one
pre_system
is in fact too early, because routing has not been done and anything you do the routing will get overwritten.
So I needed the first controller to look the same, yet end up calling a different controller. The reason was that the page was accessed in a hierarchical way, so that it would be the subsection of a subsection and so on.
What I did was add on line 43 of system/libraries/Controller.php
$this->_ci_initialize();
Basically I had it autoload the libraries BEFORE the controller was called, because I was finding that the libraries were not loaded before the controller was called and I needed it to be done so because I needed to check user access authentication and hook directly into the routing itself.
After I did that, I extended one of the native core libraries that were autoloaded (in this case session, for applicaiton specific reasons) and then executed the rerouting.
$RTR = & load_class( 'Router' );
$this->URI = & load_class( 'URI' );
$this->URI->_fetch_uri_string();
I called this code in the start, then put my logic afterwards. This is a sample of what my rerouting logic looks like
if ( $this->segment( 1 ) == 'institute' )
{
if ( ! in_array( $this->segment( 3 ), $course ) )
{
$RTR->set_class( 'courseClass' );
$RTR->set_method( 'index' );
if ( ! $this->segment( 4 ) )
{
$RTR->set_class( 'course' );
$RTR->set_method( 'index' );
}
else
{
$RTR->set_class( 'course' );
$RTR->set_method( $this->segment( 3 ) );
}
}
The original is much longer. I probably should consider writing some sort of plugin or superior way to handle the rewriting rather than silly spagetti logic. However, I needed extremely fine grain control of the controllers being called based on the URLs. This will literally give you god mode control over your controller based on the URLs. Is it a hack? Yes. Is it inelegant? Absolutely. But I needed it done.
Just remember since this edits the core files, you can't easily upgrade after. I think the Kohana framework has a solution to this.
I kept reading the CI docs after Alex's post and found info on the routes.php file which does exactly what I needed.
It allows you to use regular expressions to rewrite the routes (URLs), much in the same manner as mod_rewrite, so I could strip out the user name and end up passing it as a param.

What is the best way to store configuration variables in PHP?

I need to store a bunch of configuration information in PHP.
I have considered the following....
// Doesn't seem right.
$mysqlPass = 'password';
// Seems slightly better.
$config = array(
'mysql_pass' => 'password'
);
// Seems dangerous having this data accessible by anything. but it can't be
// changed via this method.
define('MYSQL_PASSWORD', 'password');
// Don't know if this is such a good idea.
class Config
{
const static MYSQL_PASSWORD = 'password';
}
This is all I have thought of so far. I intend to import this configuration information into my application with require /config.inc.php.
What works for you with regard to storing configuration data, and what are best practices concerning this?
I've always gone with option #2 and just ensure that no one but the owner has ANY sort of access to it. It's the most popular method among PHP applications like Joomla, vBulletin, Gallery, and numerous others.
First method is too messy to me (readability) and the third is WAY too dangerous to do. I've never thought about the Class method, so someone else can provide their input on that one. But I guess it's fine so long as the right access is used on the class' usage.
Example..
define('EXAMPLE1', "test1"); // scenario 1
$example2 = "test2"; // scenario 2
function DealWithUserInput($input)
{
return eval($input);
}
Now this example of code is really dumb, but just an example. Consider what could be returned by the function depending on which scenario the user could try to use in their input.
Scenario 2 would only cause an issue if you made it a global within the function. Otherwise it's out of scope and unreachable.
I'd say it also depends of userbase a bit. If configurations has to be very user friendly or user has to have ability to change config via web etc.
I use Zend Config Ini for this and other settings are stored in SQL DB.
I generally use the second method... When handling database connections I generally open a connection at the beginning of the request, then close it at the end. I have a function that establishes the connection, then removes the username/password from the global array (with the unset() function), This prevents other parts of the system from accessing the "sensitive" mysql connection data.
I'm also with option 2 for most config values. If you were going to implement the Class then I would tie the specific values to the Class that it affects instead of a general config Class.
In your example, your Class would be for database connections and an instance would save the password, db_name, etc. This would encapsulate the data properly and also provide an easy means to create multiple connections if that was ever needed.

Categories