From the early days, Drupal had the ability to embed PHP code in its content. This provides flexibility and functionality, most importantly, nodes and blocks can contain dynamically fetched data from the database using custom queries and displayed them in other content.
This is an easy approach to get such data without writing a module. All you need to do is assign the PHP input format filter to the node or block and paste your PHP code in it, and voila, you have dynamic content.
Code in Content: the issues
However, this approach is suboptimal and has serious drawbacks, including:
Lack of Readability and Clarity
Since the code is embedded within pieces of otherwise HTML content, it is not obvious where the code is, so tracking it is really hard. Moreover editing it in a textarea is far less friendly than in a prope text editor with syntax highlighting. This leads to maintenance issues with this code in the long run.
Potential Security Issues
Since the code is not readily visible, it is more prone to be missed in doing code reviews or security audits, than if it would have been in a more conventional repository. This is why modules such as Paranoia exist, and why Drupal 6 now has a separate PHP module that has
to be explicitly enabled in order to get the PHP filter functionality.
Lack of Version control
Nodes and blocks are never put in a versioned code repository, such as CVS, SVN or GIT. Because of that tracking changes is very hard, and maintenance can be a nightmare.
Performance Drawbacks
Code stored in the database is first fetched from the database, then executed by PHP. Because of that, this code is never cached by accelerators/op-code caches, and can be slower to execute than cached code.
Search Implications
Embedding PHP output within Drupal's search provides some interesting challenges.
As you can see, there are several drawbacks here.
Views is another module that stores pseudo-code in the database (actually query generator instructions). However, views offer the ability to export its queries as PHP code which can be made into modules and suffer none of the above drawbacks.
Removing Code from Content
For the above reasons, we went on a mission over the past few weeks to rid sites of code embedded in content. So far, we have done 5 sites, the last of which is Drupal.org itself.
The process is described as follows:
Get A List of all PHP Content
First find out what is your PHP filter format ID. You can do this via the following SQL.
mysql> SELECT * FROM filter_formats; +--------+---------------+-------+-------+ | format | name | roles | cache | +--------+---------------+-------+-------+ | 1 | Filtered HTML | ,1,2, | 1 | | 2 | PHP code | | 0 | | 3 | Full HTML | | 1 | +--------+---------------+-------+-------+
Now, we know that 2 is the PHP filter format.
Next we estimate how many PHP nodes we have.
SELECT n.format AS id, COUNT(*) as cnt FROM node_revisions n WHERE format = 2 GROUP BY n.format; +----+-----+ | id | cnt | +----+-----+ | 2 | 14 | +----+-----+
And then we get the text of the nodes that have PHP in them, so can work on making it into modules. Note that some nodes may have the PHP format, but not PHP code in it, e.g. when you need to paste javascript verbatim.
SELECT nid, body FROM node_revisions WHERE format = 2;
And then the blocks too. Again, not all the blocks may contain actual PHP code.
SELECT * FROM boxes WHERE format = 2;
After that, we need to find blocks that have PHP visibility settings too, although the body may not have PHP:
SELECT * FROM blocks b INNER JOIN boxes x ON b.delta = x.bid WHERE status = 1 AND pages LIKE '%<?php%';
Now we have all the info we need, we then move to analysing it.
Do Some Analysis
Study each node and block and see whether you can use the code as is, or make it simpler as you refactor it and move it out from content to modules. This all depends on the actual code and what it does.
Convert Blocks into Modules
A basic block module will look like this, which should go in a file called something.module:
function something_block($op = 'list', $delta = 0, $edit = array()) { switch ($op) { case 'list': $blocks[0]['info'] = t('Some block'); return $blocks; case 'view': $block['subject'] = t('Some block'); $block['content'] = something_output(); return $block; } } function something_output() { // code goes here return $output; }
All you need is an something.info file to go with it, and you are all set.
Whether you combine several blocks in one module or keep it separate depends on your particular specifics.
Convert Dynamic Node Data into hook_nodeapi
Now, you need to convert the code that was in nodes to become modules. You can chose to combine several nodes in one module so as to reduce the number of modules on your site.
On Drupal.org, most nodes were there to preserve a place in the Handbook hierarchy, and provide dynamic data in them. In this case, we need to keep the specific nodes as they are, but change their format from PHP to Filtered HTML.
Then we have a module like the one below that appends the dynamic content at the end of the node body.
function something_nodeapi(&$node, $op = 'view', $teaser = FALSE, $page = FALSE) { if ($op == 'view' && $page) { $extra = ''; switch ($node->nid) { case 48380: $extra = something_output(); break; case 257382: $extra = something_other(); break; } $node->content['body']['#value'] .= $extra; } } function something_output() { // code goes here return $output; } function something_other() { // code goes here return $output; }
Of course, you need an info file to go with the above module as well.
Convert Views into Modules
Using the export function of views, you should convert the views into modules. Check the views documentation for more info.
Now you have the code versioned, visible, auditable, faster and more maintainable. You can sleep better now ...
Comments
Visitor (not verified)
finding php code alternative
Mon, 2009/11/09 - 07:11We use an sql export of the database and running a grep <?php to give a quick result.
Pages