Scotty Delicious Web Services

FileDownloadPE


FileDownloadPE (Pirate Edition) is a secure file downloading snippet for the MODx CMS/F. FileDownloadPE is secure as it hides the actual path to your file. FileDownloadPE keeps track of how many times each file has been downloaded and lets you display that number wherever you want. There are no extra plugins to install with FileDownloadPE, and you can have multiple download links per page. Each "FileDownloadPE" file being served is a MODx document, so you have the full service of Access Control Lists (ACL) meaning you have the ability to restrict downloads to certain groups. FileDownloadPE uses a PHP5 class to ensure data protection and encapsulation. As such, a server running PHP 5.x or greater is required.

FileDownloadPE uses MODx Template Variables (TVs) to specify file name, file path, and MIME type. To get started, download FileDownloadPE.

Installation Updated 2008.06.18 for version 1.1

  1. Step 1:

    Create a new snippet called "FileDownloadPE" and paste the contents of "filedownloadpe.snippet.php" into the Snippet code (php) area. Before you paste you should remove the opening and closing php tags because the text you just copied already has them in it. Click "Save" when you are done.

  2. Step 2:

    Create a new template called "Downloads". In the Template code (html) area, put [ !FileDownloadPE! ]. (If you copy and paste this snippet call, remove the spaces between the square brackets and the exclamation points.)

  3. Step 3: Create three two new template variables: File
    Variable Name:
    File
    Caption:
    File
    Description:
    Path to file
    Input Type:
    File
    Template Access:
    Make sure the "Downloads" template is checked.

    FileMime
    Variable Name:
    FileMime
    Caption:
    FileMime
    Description:
    MIME Type
    Input Type:
    DropDown List Menu
    Input Option Values:
    force-download||application/zip||application/pdf||image/jpg||image/png||text/plain
    Default Value:
    force-download
    Template Access:
    Make sure the "Downloads" template is checked.

    FileName
    Variable Name:
    FileName
    Caption:
    FileName
    Description:
    File Name
    Input Type:
    Text
    Template Access:
    Make sure the "Downloads" template is checked.

    *NOTE: The FileName TV is used to get download counts so make sure it is unique Now uses the document's alias.


Usage

  1. Create a new MODx Document.
  2. Give it a title and alias. * The alias is now used in the database to keep count of the downloads.
  3. Set the "Uses template" drop down menu to "Downloads".
  4. Skip the Document content, and go right to the "Template Variables" section.
    1. Put a unique file name in the FileName TV. * No longer needed. Uses the document alias instead.
    2. Select the correct MIME type from the FileMime drop down TV.
    3. Click "Insert" on the File TV and upload / choose the file to serve.

      *NOTE: You can also manually type in the path of the file relative to the site root.

  5. From the "Page Settings" tab, uncheck "Searchable" and "Cacheable", set the "Content Type" to text/plain, and set the Content Disposition to Attachment.

Parameters

&action (string)
set to count to use this snippet as a download counter.

* Required for providing a download count.

&filename &id (int)
Used with &action to specify the document ID to get counts for.

* Required for providing a download count.

&dberror (string)
The text displayed when an error is encountered while processing the file.

* Optional. Default: "There was an error processing your download request."

&nofile (string)
The error displayed when no file is specified.

* Optional. Default: "No file specified."

&fileNameTV (string)
The name of the MODx TV that holds the file's unique name.

* Optional. Default: "FileName".

&fileMimeTV (string)
The name of the MODx TV that holds the file's MIME type.

* Optional. Default: "FileMime".

&filePathTV (string)
The name of the MODx TV that holds the file's path on the server.

* Optional. Default: "File".

Examples

I created a MODx document (the document ID turned out to be 36) in the fashion described above and set the "FileName" TV to example, the "FileMime" TV to application/zip, and using the "File" TV, I uploaded the file example.zip to my server and chose it as the value for the "File" TV. I gave this document an alias of example.zip. I used the string "example.zip" as the alias so that Windows knows what to use to open it if it is downloaded with IE. On this site, I have the Friendly alias suffix set to blank (I don't think a visitor should EVER have to look at file extension, but that is another blog entry), so if you have a suffix set in your MODx configuration, it could potentially cause problems with a Windows/IE combination unless you manually provide the href in your links instead of letting the MODx parser generate it from the doc ID.

As an example, I duplicated this document (The new document's ID is 37) and gave it an alias of random-name-whatever.zip. As you can see, the URI does not need to match the actual file name. It can be whatever you want. The actual file was uploaded to the root of my site, but you can put your files in any web accessible folder.

Download An example file: Downloaded 1966 times.

Download Same file, different URI: Downloaded 1966 times.

View the source code for this example.

Best Practices

As a best practice for keeping your directory structure clean I suggest creating a MODx document at the root of your site called "Downloads", with an alias of "downloads". This is especially helpful if you use Friendly URLs with Friendly Alias Paths. That way, you directory tree stays clean and your download URLs point to http://yoursite.tld/downloads/FileName. For each file you want to serve, create a new document as a child of this "Downloads" document, configured as described in the Usage section.

XHTML links in new window with jQuery


When I am visiting a website and reading a blog post or forum thread, I like it when I click on a link that is going to take me to another domain, that it opens in a new tab or window. It is just a personal preference but, especially on really long pages, it takes forever to reload the content when I click the back button. It is far more convenient for me to just hit Command + W (ctrl + W) to close the new tab when I am done reading it and be right were I was on the page where I clicked the link. For example, When I am reading articles on Digg and I click a link to read the actual article, it would suck if it simply went to the article, especially if I am halfway through a boatload of nested comments.

With HTML 4, all you needed to do was add a target="_blank" attribute to your anchor tags. In XHTML, the "target" attribute has been depreciated.

If you want your pages to validate to XHTML 1.0 Strict or XHTML 1.1, You are S.O.L. on opening the links in a new window without some Javascript. I prefer to use the jQuery library, so I am going to discuss how to open links in a new window with that.

First, I marked up all my external links with a class of "external_link".
For example <a href="http://google.com" class="external_link" title="Google">Google</a>.

The next step is to include the jQuery library in the head of your document, then use a few lines of code to find the a tags that have been marked as external.

<script src="/js/jquery.packed.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript" charset="utf-8"> $(document).ready( function() { $('a.external_link').click( function() { window.open(this.href); return false; }); }); </script>

I will step through this one line at a time.

$(document).ready( function () {

In this first line, the document is wrapped in a jQuery object. The "ready" method of the jQuery object is called and we pass, as it's only parameter, an anonymous function. The "ready" function is called as soon as the DOM is available. This is important, because we need to make sure all the anchor tags that are marked can be accessed before trying to operate on them. This is different than "window.onload" because it does not need to wait for all the resources (images, scripts, etc...) to load before it is safe to use. Once the DOM is "ready", the anonymous function is run.

$('a.external_link').click( function() {

This line finds all the anchor tags with a class of "external_link" and binds a "click" function to them. This event is fired when a DOM element matching the criteria encounters the "onclick" event. The click function is passed another anonymous function.

window.open(this.href);

A standard javascript window object method, the "open" method opens a URL (passed as it's paramter) in a new window. You can of course specify other parameters such as window size, toobar, window title, etc... But that is not needed for this particular implementation. The parameter passed as "this.href" is the value of the href attribute for the link that was clicked.

return false;

The last step is to prevent the browser from taking its standard action, which is to open the link inline in the current browser window. by specifying "return false;", we are squelching that behavior.

Redesign


I have been busy this last week rebuilding my site. Over the last few months I have been experimenting with the Zend Framework. As far as frameworks go, it fits my coding style better than some of the others I tried (CakePHP, CodeIgniter, Symfony, RoR). It is a pretty schwag setup, but there are some things, like Zend_Form, that were just taking too much work to get it functioning & displaying like I wanted to. There is a tremendous amount of flexibility in this framework, but with that comes a LOT of additional ground work.

Previously, this site had been built on the MODx Content Management System. I like MODx, but I was looking for a change and something to sharpen my (PHP) teeth on.

As I set out on this redesign project, my intention was to build the entire application with the Zend Framework. After spending about 50 hours working with it, the site was still nowhere close to ready. So... I decided to roll my own. This site is now build on a combination of the Zend Framework and a heavily modified MODx. I get the convenience of the MODx Document Parser class, and with a little (read as "a lot of") modification, I have Ditto (for the blog) and Jot (for the comments) working with the database abstraction taken care of via Zend_Db_Table. The great thing about using Zend_Db_Table for the database queries is that the entire application lives ouside the web root.

I am curious as to what you think about the design of the site, and if anyone has any success or horror stories on using the Zend Framework, please post a comment. I did roll along with Pádraic Brady's blog, which is a great resource, and I have a few side projects that I think will be perfect as 100% Zend Framework powered, but I needed to get this done post haste.

Anniversary in Chicago


Tuesday, June 3rd was Andria's and my two year anniversary. We decided to take a trip to Chicago to get away and have some fun. Andria booked a hotel room at Hotel Allegro In the theater district (Randlolph & LaSalle). It was pretty swank. They just dropped a bunch of cash redesigning all the rooms. It's an old building, and it has this real classic charm (and smell, unfortunately). Also, it is within a few blocks of the museums and the aquarium, so that was convenient.

The weather was really nice all three days we were there so we walked everywhere. I don't know how many miles we put on, but my dogs were barking for a few days. We got in on to town on the 3rd, around 3:30pm and spent the first afternoon rushing through exhibits at the Art Institute (they close at 5pm), but we managed to take in quite a bit.

Day 2 we hiked up to the Field Museum. We spent most of the day there. The "Evolving Planet" exhibit and "Mythic Creatures: Dragons, Unicorns & Mermaids" were really, really cool.

In the afternoon, we walked up to the Shedd Aquarium. It was ok, but not as cool as I remember it when I was a kid. That eveneing we grabbed some dinner at the hotel restaurant and hoofed it down to the Sears Tower observation deck to check out the fireworks they shoot off from Navy Pier every Wednesday during the summer. It was an incredible perspective to say the least. Andria tried to snap some pics with the Nikon D40, but the backlighting caused too many reflections, and the focal area was too dark so even with a high ISO, the shutter speed was too slow to get any clear images.

Archives