Configuring FCKEditor for Yii-Driven Sites

December 1, 2009
The Yii Book If you like my writing on the Yii framework, you'll love "The Yii Book"!

I’ve created three Yii-driven PHP sites in the past few months, each of which required an administrative area to dynamically manage the site’s content. Much of the content can contain some HTML, including media (images, videos, etc.), typography, lists, and so forth. So that non-technical people can create nice-looking HTML, I use a Web-based WYSIWYG editor like FCKEditor or TinyMCE. Getting either to work within the Yii environment isn’t too hard, once you know what to do. But because assembling the disparate parts can be tricky, I outline the specific steps and requirements in this post. Note that the post does assume familiarity with Yii.The first thing you’ll need to do is download FCKEditor. FCKEditor has been updated to a newer version called CKEditor. The two are not interchangeable but the older FCKEditor is still maintained and available. You may want to compare the two before proceeding, and also be certain to review the documentation to determine whether or not you need to purchase a license.

Once the FCKEditor package is downloaded, you’ll need to expand the ZIP or TAR.GZ file (you can download the package in either format). The resulting folder is called just fckeditor and can be moved, in its entirety to the root of your Web directory. (You don’t actually need all the files in the folder but it’s fine to have them on the server.) Later on I’ll discuss configuring the editor but for now let’s move on to the Yii side of things.

Next, download the FCKEditor integration widget for Yii. Expand the downloaded ZIP file and you’ll end up with another folder called just fckeditor. Move this entire folder to your application’s extensions directory (i.e., protected/extensions).

To use the FCKEditor in a form, you’ll need to edit the _form.php file for the particular View. For example, on one site I edited protected/views/page/_form.php, as the admin created the site’s content through a Page Model. By default the form will have a standard textarea for every TEXT type MySQL column:

<?php echo CHtml::activeTextArea($model,'content',array('rows'=>6, 'cols'=>50)); ?>

To use FCKEditor instead of the textarea, invoke the integration widget by replacing that code with this:

<?php $this->widget('application.extensions.fckeditor.FCKEditorWidget',array(
 'model'     =>  $model,
 'attribute' => 'content',
 'height'    =>  '600px',
 'width'     =>  '100%',
 'fckeditor' =>  dirname(Yii::app()->basePath).'/htdocs/fckeditor/fckeditor.php',
 'fckBasePath' => Yii::app()->baseUrl.'/fckeditor/')
 ); ?>

That code starts by saying a widget should be rendered in this place, specifically the FCKEditorWidget. That widget gets passed an array of values to configure it. To start, pass the Model, which Yii stores in the $model variable by default (in older versions of Yii, you would have seen a specific Model name there instead, like $page). The attribute element is the name of the Model attribute, which will likely also match the field name in the database. Those two values are the most important and must be correct for each form. The height and width are obvious. The next two values point to the location of the FCKEditor on the server. If you moved those files into the root Web directory, still in the fckeditor folder, these lines will work just fine (assuming htdocs is the root Web directory).

So those steps are pretty easy to understand and will get you a working WYSIWYG editor in no time. But you’ll likely need to tweak how the FCKEditor behaves, too, which is much more complicated. For starters, if you want to allow the admin to upload files to the server, like images or videos, you’ll need to enable the file manager. Presumably you’ll be using PHP for this purpose. In that case, open fckeditor/editor/filemanager/connectors/php/config.php in your text editor or IDE. This tool is disabled by default, thanks to this line:

$Config['Enabled'] = false ;

To enable file management, this variable must be assigned a true value. You could do this:

$Config['Enabled'] = true ;

but that’d be terribly insecure, as it’d allow ANYONE to manipulate files on the server (shudder). You could use Apache’s HTTP Authentication to restrict access to the filemanager/connectors/php directory, but then you’d have a separate, secondary login system from your application’s login system. So instead, I tap into the Yii user management system here. Presumably an administrator has to login in order to update the content. If so, then they’ll have a session, by default named PHPSESSID. So you can check for a cookie:

$Config['Enabled'] = isset($_COOKIE['PHPSESSID']) ;

Of course, that would also allow logged-in non-administrative users to use the file manager, too. So another clause needs to be added to this conditional. What that clause is will depend upon your situation but will likely involve something stored in $_SESSION. For example, perhaps your content admin account has a user name of ‘moderator’. If so, then you could use this code to verify that the user should be allowed to use the file manager:

session_start();
$Config['Enabled'] = (isset($_COOKIE['PHPSESSID']) && (in_array('moderator', $_SESSION))) ;

A couple of explanations: First, you have to start the session in this file, as it won’t otherwise be started. Second, Yii stores values in the $_SESSION array using a somewhat more secure technique. Instead of just having name => value, Yii prepends a hash of random characters to the name of each element in $_SESSION. The user’s name, therefore, might be stored in session like so:

$_SESSION['a4d58ee27e5fb1f0827af0550771ea7e__name'] = 'moderator';

Because of this, you can’t just easily check the value of, say, $_SESSION[‘name’], which is why I use in_array() in the above code.

Also, while you’re editing the config.php file, you may want to change the name of the UserFilesPath:

$Config['UserFilesPath'] = '/something_clever/' ;

This is where the user-uploaded files will be stored. This value will appear in the HTML source when those files are used on a page, so this isn’t a huge security benefit, but it’s an easy step to take. You’ll need to create the corresponding folder, too.

Next thing up, you’ll likely want to configure the FCKEditor as it’ll behave in the Web browser. To do so, you’ll edit the FCKEditor configuration file (fckeditor/fckconfig.js). There are a ton of options there, best described in the FCKEditor manual. For example, you can set the EditorAreaCSS and EditorAreaStyles values so that the FCKEditor window uses the same styling as your whole site. I also normally edit the toolbarsets so that limited options are presented to the end user (thereby keeping them from making a mess of the site).

You can also change some FCKEditor settings on the fly when you invoke the Yii widget. To do so, pass a config element with an array of values when calling the widget:

<?php $this->widget('application.extensions.fckeditor.FCKEditorWidget',array(
'model'     =>  $model,
'attribute' => 'content',
'height'    =>  '600px',
'width'     =>  '100%',
'fckeditor' =>  dirname(Yii::app()->basePath).'/htdocs/fckeditor/fckeditor.php',
'fckBasePath' => Yii::app()->baseUrl.'/fckeditor/'),
'config' => array('EditorAreaCSS'=>Yii::app()->baseUrl.'/css/other.css')
); ?>

You might do this to change the styling of a specific FCKEditor window, as in that code.

Finally, consider that the Views, by default, echo out Model data using the CHtml::encode() method. This is a logical and necessary security feature, as it prevents cross-site scripting attacks (XSS). However, it also makes the FCKEditor-generated HTML completely useless (it’s the equivalent of PHP’s htmlspecialchars() function). A logical work-around is to use PHP’s strip_tags() instead, providing it with the optional second argument of allowable tags:

echo strip_tags($model->content, '<p><a><div><ul><ol><li><span>');

Okay, so there’s that then. I think that’s everything you should know to get going with FCKEditor and Yii. Let me know if you have any questions or would like me to write up any other subject. As always, thanks for reading what I have to say.

Larry