Thursday, July 1, 2010

Integrating CKEditor and CakePHP : Part 3

In Part 2 of this series, I covered how to add CKFinder to your CakePHP and CKEditor installation. This article will cover a particular requirement to upload files to a specific directory based on the content identifier.

In my TinyMCE solutions, I use cookies to communicate to the TinyMCE uploader which directory it should upload files to, and what the relative URL is for that location. In hindsight, it's probably not so secure, because we end up sending absolute paths in the cookie data to the client. So for this time around, I'm going to use the PHP Session, as generated by CakePHP. It will assume that we're using basic PHP Sessions, as defined by using the value "php" for our core config item "Session.save".

With regards to the requirement for uploading to specific directories, I usually have a publish behaviour attached to most of my editable models, where the user can make changed to an unpublished version, but it's not made apparent on the website until it's published. Going along with that idea are also any images or files that are uploaded for use in the content, and they are also copied to a published version of the content item. I'm not going to cover the publish behaviour here, but I will cover uploading to a specific directory, so that all images are uploaded to app/webroot/files/img/contents/X and files to app/webroot/files/files/contents/X, where X is the id of your contents item.

The first change to make is for CakePHP to indicate to the browser new $baseUrl and $baseDir settings. We're going do this via the PHP session, and the ckeditor element. We also want to prevent uploading if it's a brand new content item, since an id will not have been created yet. Here's the revised code:

<?php 
echo($javascript->link(array('/ckeditor/ckeditor','/ckeditor/adapters/jquery','/ckfinder/ckfinder'))); 
?>
<script type="text/javascript">
$(function() {
 
 $('textarea').ckeditor();
<?php
if (isset($this->params['pass'][0])) {
 // only allow upload if we have a place to put it
    $_SESSION['path_to_dest_image'] = '/files/img/'.$this->name.'/'.$this->params['pass'][0].'/'; 
 $_SESSION['path_to_destsvr_image'] = WWW_ROOT.'files/img/'.$this->name.'/'.$this->params['pass'][0].'/'; 
 @mkdir($_SESSION['path_to_destsvr_image'], 0, true);
 $_SESSION['path_to_dest_file'] = '/files/files/'.$this->name.'/'.$this->params['pass'][0].'/'; 
 $_SESSION['path_to_destsvr_file'] = WWW_ROOT.'files/files/'.$this->name.'/'.$this->params['pass'][0].'/';
 @mkdir($_SESSION['path_to_destsvr_file'], 0, true);
?> 
 $('textarea').each(function() {
  var editor = $(this).ckeditorGet();
  CKFinder.setupCKEditor(editor, 
   {basePath: '/ckfinder/', 
   rememberLastFolder: false
   }
  );
 }); 
<?php
} 
?>
});
</script>


What I've done here is to make sure we actually have an id to work with (via $this->params['pass'][0]) before we add CKFinder, and then add the session variables, and make sure the directory actually exists.

Secondly, I've created a separate file to contain my CKFinder config code. I like to keep that sort of thing out of the ckfinder directory, but also out of the main CakePHP app, so I've gone for app/vendors/ckfinder/config.inc.php. You'll also want to link that into the app/webroot/ckfinder/config.php file, somewhere near the top. Now, because all CKFinder PHP code is run relative to ckfinder/core/connector/php/connector.php, you'll want your config.php entry to look as follows:

include_once "../../../../../vendors/ckfinder/config.inc.php";


That's alot of parent directories!

In the config.inc.php, I make sure I tap into the CakePHP named session, start it, then set $baseUrl and $baseDir on the session values.

<?php 

session_name('CAKEPHP');
session_start();

if ($_GET['type'] == 'Images') {
 $baseUrl = $_SESSION['path_to_dest_image'];
 $baseDir = $_SESSION['path_to_destsvr_image']; 
} else  /* if ($_GET['type'] == 'File') */ {
 // File is the default
 $baseUrl = $_SESSION['path_to_dest_file'];
 $baseDir = $_SESSION['path_to_destsvr_file'];
}


I haven't catered for the CKFinder Flash type, but if you wanted to, you could.

And one more change to the ckfinder/config.php. Since I have separate directories for images and files, I don't really want another subdirectory for the file types. So I've changed the ResourceType entries to just be $baseUrl and $baseDir for url and directory respectively, for Images and Files.

And I don't want thumbnails appearing in my CKFinder browser, so I've added "_thumbs" to the HideFolders config item.

And that's how I integrate CKFinder to use a specific upload directory via the CakePHP session, assuming you're using basic PHP Sessions.

However, that's not enough. I have some products that are using database CakePHP sessions. I'll cover how to deal with that in my next article.

Series Index : Part 1, Part 2, Part 3, Part 4, Part 5, Part 6

No comments:

Post a Comment