Thứ Hai, 2 tháng 6, 2014

Filters [Manipulating User Input: The Filter System]

Filters are almost always a single action such as strip  out all hyperlinks,” add  a random image to this post,” or even “translate this
into pirate-speak (see pirate.module at http://drupal.org/project/ pirate). As shown in Figure  12-1, they take some kind of textual
input, manipulate it, and  return output.


Figure 12-1. A filter transforms text in some way and returns the transformed text.


A common use for a filter is to remove unwanted markup from user-submitted input. Figure  12-2 shows Drupals HTML filter at
work.


Figure 12-2. The Limit allowed HTML tags filter allows only certain  tags through.
This filter is essential for preventing cross-site scripting attacks.


Filters and Text formats

Trying to find a list of installed filters within the administrative interface isn’t intuitive and  assumes yoalready understand what
filters do to know wha to look for. For filters to perform their jobs, you must assign them to a Drupal Text format as shown in
Figure 12-3. Text formats group filters together so they can run  as a batch when processing content. This is much easier than checking
off a handful of filters for each  submission. To view a list of installed filters, either configure an existing Text format or create new one by clicking on the Configuration link at the top of the page,  followed by the Text format link on the Configuration page and
the Add text format link.


Figure 12-3. Installed filters are listed on the “Add text format” form.

Drupal ships with three text formats (see Figure  12-4):

     The Filtered HTML text format is made up of four filters:
      The Limit allowed HTML tags filter, which restricts which tags are allowed to pass through the filter
      The Convert URLs into links filter, which transforms web and  e-mail addresses into hyperlinks
      The Convert line breaks into HTML line break converter, which converts carriage returns to their  HTML counterparts
      The Correct faulty and  chopped off HTML filter
     The Full HTML text format doesn’t use the Limit allowed HTML tags filter, but does implement the Convert URLs into links,
Convert line breaks into HTML, and Correct faulty and  chopped off HTML filters.
     The Plain Text text format, which displays HTML tags as plain text
     The PHP Code text format is made up of a filter called  PHP evaluator, and  its job is to execute any PHP within a post. A good
rule of thumb is never to give users the ability to execute a Text format that uses PHP evaluator. If they canrun  PHP, they can do
anything PHP can do, including taking down your site, or worse  yet, deleting all your data. To protect against this possibility, Drupal
ships with the PHP evaluator filter disabled. If you must make it available,enable the PHP filter module.


Figure 12-4. Drupal installs with four configurable text formats by default.

Because text formats are collections of filters, they are extensible. You can add and  remove filters, as shown in Figure 12-5.
You can change the text format’s name, add a filter, remove a filter, or even rearrange the order in which a text format’s filters are 
executed to avoid  conflicts. For example, you might want  to run  the URL filter before the Correct faulty and  chopped off HTML
filter runs so the filtecan inspect the anchor tags created by the URL filter.



Figure 12-5. Text formats are made up of a collection of filters. Shown in this figure are Drupals four default Text formats.
Installing a Filter

Installing a filter follows the same procedure as installing a module, because filters live within module files. Making  a filter available
to use is therefore as easy as enabling or disabling the corresponding module by clicking on the Modules link in the top menu.Once
installed, click on the Configuration linat the top of the page,  and  on the Configuration page,  click on the Text formats link to assign the new filter to the text format(s) of your choosing. Figure  12-6 shows the relationship between filters and modules.


Figure 12-6. Filters are created as part of modules.

Knowing When  to Use Filters

You might be wondering why a filter system is even needed when you can easily manipulate text using existing hooks found else
where. For example, it would be just as easy to use hook_node_view() to convert URLs to clickable links rather than using  the URL
filter. But consider the case in which you have five different filters that need to be run  on the body field of nodes. Now suppose
you’re viewing the default http://example.com/?q=node page,  which displays ten nodes at a time.
That means 50 filters need tbe run to generate a single page view, and  filtering text can be an expensive operation. It would also
mean that whenever a node is called, it has to run through the filters, even if the text that’s being filtered is unchanged. You’d be
running this operation over and over again  unnecessarily.
The filter system has a caching layer that provides significant performance gains.  Once all filterhave run  on a given piece  of text,
the filtered version of that text is stored in the cache_filter table, anit stays cached until  the text is once again  modified
(modification is detected using  an sha256 hash of thfiltered contents). To go back to our example, loading ten nodes could effectively by pass all filters anjust load their  data straight from the cache table when that text hasnt changed—much faster!
Now you could get really clever and  say, “Well, what  if we resave the filtered text back to the node table in our node_view hook?Then  it would behave the same as the filter system.” Although that certainly addresses the performance issue,  you’d be breaking a
fundamental concept of the Drupal architecture: never alter a user’s original data.  Imagine that one of your novice users goes back
to edit a post  only to find it smothered in HTML angle  brackets. You’ll most certainly be getting a tech  support call on that one.  The goal of the filter system is to leave the original data untouched while making cached copies of the filtered data available to the rest of the Drupal framework. You’ll see this principle over and over agai with other Drupal APIs.

Creating a Custom Filter

Sure, Drupal filters can make links, format your content, and  transform text to pirate-speak on the fly, but what  woulbe really
slick would be for it to write our blog entries for us, or at least help  us get our creative juices  flowing. Sure, it can do that, too!
Lets build  a module with a filter to insert random sentences into a blog entry. We’ll set it up so that when you run  out of juice in
your post  and  need a creative spurt, you can simply  type [juice!] while writing, and  when you save your entry, it’ll bereplaced with
a randomly generated sentence. We’ll also make it so that if you need lots of creative juice, you can use the [juice!] tag multiple times
per post.

Create a folder  named creativejuice located in sites/all/modules/custom/. First, add the creativejuice.info file to the creativejuice
folder:

name = Creative Juice
description = "Adds a  random  sentence filter to  content." package  = Pro Drupal Development
core  = 7.x
files[] = creativejuice.module php = 5.2

Next, create the creativejuice.module file and  add  it, too:
<?php
/**
*   @file
*    silly module to  assist whizbang novelists who are  in  a  rut  by providing   a
*   random  sentence generator for  their posts.
*/

Implementing hook_filter_info()


Now that the basics of the module are in place, let’s add our implementation of hook_filter_info() to creativejuice.module:
/**
*   Implement hook_filter_info().
*/
function creativejuice_filter_info() {
$filters = array();
$filters['creativejuice'] = array( 'title' => t('Creative Juice   filter'),'description' => t('Enables users   to  insert random
sentences into their post'),'process callback' => '_creativejuice_filter_process', 'tips  callback' => '_creativejuice_filter_tips',);
return  $filters;}

The Process Function

The process function creativejuice_filter_process is called  every time  a node is saved—when the input type set for the node
matches a text filter where the creative juices  filter is enabled.
/**
*   Creativejuice filter process callback
*
*   The actual filtering is  performed here. The supplied text  should  be
*   returned, once  any necessary substitutions  have  taken  place.
*/
function _creativejuice_filter_process($text,  $filter, $format)  { while  (strpos($text, '[juice!]') !==  FALSE)  {
$sentence = creativejuice_sentence();
$text = preg_replace('&\[juice!\]&',  $sentence, $text, 1);
}
return  $text;
}
The function is relatively simple. The first step  is to call a helper function that returns a random sentence, and  the second line of code
simply  uses the PHP string replace function to replace every instance of [juice!] with the random string  returned fromthe creative
juice_sentence helper function.

Helper Function

I’ve created a helper function that returns a random sentence that will be used by the filter to replace the [juice!] tag.
/**
*   Generate  a  random  sentence.
*/
function creativejuice_sentence()  {
$beginnings = array();
$beginnings[] = t('A majority   of  us  believe');
$beginnings[] = t('Generally speaking,');
$beginnings[] = t('As times  carry  on');
$beginnings[] = t('Barren in  intellect,');
$beginnings[] = t('Deficient in  insight,');
$beginnings[] = t('As  blazing blue  sky  pours  down torrents of  light,');
$beginnings[] = t('Aloof from the  motley  throng,');
$beginnings[] = t('While crafting a  new Drupal module,');
$middles  = array();
$middles[] = t('life flowed  in  its accustomed  stream');
$middles[] = t('he ransacked  the  vocabulary');
$middles[] = t('the grimaces  and caperings of  buffoonery  sting');
$middles[] = t('the mind freezes at  the  thought');
$middles[] = t('reverting to  another  matter  enables freedom');
$middles[] = t('he lived as  modestly  as  a  hermit');
$middles[] = t('the coder  repeatedly invoked  hooks');
$ends  = array();
$ends[] = t('through the  red  tape  of  officialdom.');
$ends[] = t('as it set anew in  some fresh and appealing   form.');
$ends[] = t('supported by evidence.');
$ends[] = t('as fatal as  the  fang  of  the  most venomous snake.');
$ends[] = t('as full of  spirit as  a  gray  squirrel.');
$ends[] = t('as dumb  as  a  fish.');
$ends[] = t('like a  damp-handed  auctioneer.');
$ends[] = t('like a  bald  ferret.');
$ends[] = t('with a  frozen, sharpened  badger.');
$ends[] = t('and  achieve CMS  nirvanna.');
// For every  phrase  group,  pick  a  random  value.
$sentence = array($beginnings[mt_rand(0, count($beginnings)  - 1)],$middles[mt_rand(0, count($middles)  - 1)],
$ends[mt_rand(0, count($ends)  - 1)],);
// Take the  three   random  values from the  sentence groups,
// implode  them together, and return  the  sentence.
return  implode(' ', $sentence);}

The function is pretty simple—it creates an array of sentences and  randomly picks a sentence to return to the calling  function.
You use _creativejuice_filter_tips() to display help  text to the end  user By default, a short message is shown with a link to
http://example.com/?q=filter/tips, where more detailed instructions are given for each  filter.
/**
*   Filter tips  callback for  creative juice filter.
*
*   The tips  callback allows filters to  provide  help  text to  users   during  the  content
*   editing process. Short  tips are  provided  on the  content editing  screen,  while
*   long  tips are  provided  on a  separate linked page.  Short  tips are  optional,
*   but  long  tips are  highly recommended.
*/
function _creativejuice_filter_tips($filter, $format,   $long  = FALSE)  {
return  t('<em>[creativejuice]</em> is replaced with  the  random  sentences.');
}
In the preceding code,  you return the same text for either the brief or long help  text page,  but if you wanted to return a longer
explanation of the text, youd chec the $long parameter as follows:
function _creativejuice  filter_tips($filter, $format,   $long  = FALSE)  {
if ($long)  {
// Detailed explanation for http://example.com/?q=filter/tips  page.
return t('The  Creative Juice filter is for those times when your brain is  incapable of  being   creative. These  times come for every
one, when even  strong coffee and   barrel of  jelly beans  do  not create the   desired effect.  When  that  happens, you  can  simply
enter the   [juice!] tag   into your  posts...');}
else  {
// Short  explanation for  underneath  a  post's textarea.
return  t('Insert a  random  sentence into  your  post  with  the  [juice!] tag.');}}
Once  this module is enabled on the modules page,  the creativejuice filter will be available to be enabled for either an existing Text
format or a new Text format. For example, Figure  12-7 shows what  the “Text format” section of the node editing form looks like
after the creative juice filter has been added to the Full HTML Text format.


Figure 12-7. The Full HTML Text format now contains the creative juice filter, as indicated by the
preceding section of the node editing form.

You can create a new blog entry with the correct Text format and  submit text that uses the [juice!]

Today was a  crazy  day.  [juice!] Even if that   sounds  a  little odd, it still doesn't beat  what I heard  on the  radio. [juice!]

This is converted upon submission to something like the following:

Today was a  crazy  day!  Generally   speaking, life flowed  in  its accustomed  stream  through  the red  tape  of  officialdom. Even if that   sounds  a  little odd,  it still doesn't beat  what heard  on the  radio. Barren in  intellect,reverting to  another  matter  like a  damp-handed auctioneer.

Summary

After reading this chapter, you should be able to

     Understand what  a filter and  a Text format are and  how they are used to transform text.

     Understand why the filter system is more efficient than performing text manipulations in
other hooks.

     Understand how Text formats and  filters behave.

     Create a custom filter.

     Understand how the various filter operations function.

Không có nhận xét nào:

Đăng nhận xét