Drupal, HTML Purifier, and embedding IFRAMES from YouTube
Posted: - Modified: | drupal, geek, workI know, I know. I shouldn’t allow IFRAMEs at all. But the client’s prospective users were really excited about images and video, and Drupal’s Media module wasn’t going to be quite enough. So I’ve been fighting with CKEditor, IMCE, and HTML Purifier to figure out how to make it easier. I’m hoping that this will be like practically all my other Drupal posts and someone will comment with a much better way to do things right after I describe what I’ve done. =)
First: images. There doesn’t seem to be a cleaner way than the “Browse server” – “Upload” combination using CKEditor and IMCE. I tried using WYSIWYG, TinyMCE and IMCE. I tried ImageBrowser, but I couldn’t get it to work. I tried FCKEditor, which looked promising, but I got tangled in figuring out how to control other parts of it. I’m just going to leave it as CKEditor and IMCE at the moment, and we can come back to that if it turns out to be higher priority than all the other things I’m working on. This is almost certainly my limitation rather than the packages’ limitations, but I don’t have the time to exhaustively tweak this until it’s right. Someday I may finally learn how to make a CKEditor plugin, but it will not be in the final week of this Drupal project.
Next: HTMLPurifier and Youtube. You see, Youtube switched to using IFRAMEs instead of Flash embeds. Allowing IFRAMEs is like allowing people to put arbitrary content on your webpage, because it is. The HTML Purifier folks seem firmly against it because it’s a bad idea, which it also is. But you’ve got to work around what you’ve got to workaround. Based on the Allow iframes thread in the HTMLPurifier forum, this is what I came up with:
Step 1. Create a custom filter in htmlpurifier/library/myiframe.php
.
<?php // Iframe filter that does some primitive whitelisting in a // somewhat recognizable and tweakable way class HTMLPurifier_Filter_MyIframe extends HTMLPurifier_Filter { public $name = 'MyIframe'; public function preFilter($html, $config, $context) { $html = preg_replace('/<iframe/i', '<img class="MyIframe"', $html); $html = preg_replace('#</iframe>#i', '', $html); return $html; } public function postFilter($html, $config, $context) { $post_regex = '#<img class="MyIframe"([^>]+?)>#'; return preg_replace_callback($post_regex, array($this, 'postFilterCallback'), $html); } protected function postFilterCallback($matches) { // Whitelist the domains we like $ok = (preg_match('#src="http://www.youtube.com/#i', $matches[1])); if ($ok) { return '<iframe ' . $matches[1] . '></iframe>'; } else { return ''; } } }
Step 2. Include the filter in HTMLPurifier_DefinitionCache_Drupal.php
. I don’t know if this is the right place, but I saw it briefly mentioned somewhere.
// ... rest of file require_once 'myiframe.php';
Step 3. Create the HTML Purifier config file. In this case, I was changing the config for “Filtered HTML”, which had the input format ID of 1. I copied config/sample.php
to config/1.php
and set the following:
function htmlpurifier_config_1($config) { $config->set('HTML.SafeObject', true); $config->set('Output.FlashCompat', true); $config->set('URI.DisableExternalResources', false); $config->set('Filter.Custom', array(new HTMLPurifier_Filter_MyIframe())); }
Now I can switch to the source view in CKEditor, paste in my IFRAME code from Youtube, and view the results. Mostly. I still need to track down why I sometimes need to refresh the page in order to see it, but this is promising.
2011-08-05 Fri 16:34
17 comments
jehzlau
2011-08-06T04:03:00ZGood thing, even if Youtube switched to IFRAMEs, the old embed code still works. I think there's a better way in Drupal, perhaps replicating the auto-embed featured of Wordpress? :)
Sacha Chua
2011-08-06T04:21:25Zjehzlau: Given my client's target users, I'll be lucky if I can get most of them to copy the embed code, much less click on the classic embed code checkbox and grab that instead... =) Darn Facebook for raising expectations when it comes to autoembeds! ;)
jehzlau
2011-08-06T04:28:28ZOh yes... the clients. They don't care about the embed code as long as they can embed it. Haha! I think even if the embed code includes an external link to a malicious site, they won't bother. We need to look for a workaround to fix it for them... Geez.. Oh well. :)
Arjan
2011-08-06T16:19:12ZHow about Video filter?
MacRonin
2011-08-06T17:06:33ZWould this issue/module help tackle the CKEditor MediaEmbed plugin challenge ?
http://drupal.org/node/872868
Plus a video on how to configure the mediaembed plugin in ckeditor
http://jesox.com/posts/how-...
Joe
2011-08-08T20:38:10ZDuuuude... Embedfilter module by KarenS. Then search the issue cue for the iframe patch.
Sacha Chua
2011-08-09T03:46:41ZCan I get that to play nicely with HTMLPurifier without going crazy? Might be useful for future projects. =)
Joe
2011-08-09T06:26:06ZYou would have to get iframes to pass through the HTML Purifier filter. Or just don't use that behemoth :). Then put the patched Embedfilter after it in the processing order. Embedfilter will then strip all iframes except the ones from the domains that you specify in the mod settings.
sbandyopadhyay
2011-10-01T08:04:53ZInstead of using a custom filter, you can use what will be included in the next version of HTML purifier: HTML.SafeIframe (http://htmlpurifier.org/pho....
As for the issue with needing to refresh the page, are you using Chrome? If so, see here: http://www.rahulsingla.com/...
I had the same issue, except it was with the iframe instead of the javascript.
Sacha Chua
2011-10-01T08:06:42ZGlad to hear HTML Purifier will support it better next time! Thanks for the Chrome tips too. =)
Edward Savage
2011-12-21T00:44:50ZThis is a very clever solution, but the problem I have with it is that these to necessary attributes are stripped out: frameborder="0" allowfullscreen
Do you have a work-around for that?
Edward Savage
2011-12-21T01:58:29ZSacha, I poked around and made some changes to put necessary attributes back in and also added Vimeo support. You can see my code on this Stack Overflow answer: http://stackoverflow.com/a/...
Sacha Chua
2011-12-21T02:21:02ZYay! Thanks for sharing.
Nikos Stylianou
2012-02-18T01:22:56ZI created this sandbox project which adds a youtube and vimeo button to ckeditor which embeds iframes.
http://drupal.org/sandbox/t...
Nikos Stylianou
2012-02-18T01:26:27ZI just read the bit again about how you're having to refresh the page to see it. Using full html and my sandbox module I saw the same effect.
trkest
2013-01-14T17:37:53ZI found this was not necessary - this config worked for me:
http://drupal.org/node/7117...
toby
sachac
2013-01-14T23:53:26ZThat's good to hear. Thanks for the update!