Technology
Downloadable File Protection
by jandrews on Apr.08, 2010, under Web Development
We are going to talk today about protecting files, and allowing access to them through some kind of authentication scheme. Let’s say you have a website that has a membership area. This membership area allows for a user to log in and view content such as pdfs and spreadsheets and word documents. The issue that any website may fall into is that these documents by default aren’t protected. Anyone who has the URL of the file can access it. Therefore you really should find some way of protecting it.
The first thing you should do is keep the web server from showing a directory listing. This is just proper security from the get go. It can be dangerous to let this information be available. With apache this is done either in the httpd.conf or in the .htaccess file.
Options Indexes FollowSymLinks
The above code tells apache to show Indexes. Removing this from your httpd.conf or redefining it in the .htaccess file will resolve the problem.
Options FollowSymLinks
My preferred method of file protection is to not store these files in a publicly accessible directory, and instead create a file that can access them. This gives me all the control I want. I can detect if someone is logged in, I can also define permissions for files, so if someone is logged in but doesn’t have proper credentials to access a file then I can send them to the proper location.
<?php
// Where are files are stored.
$storageDir = "/some/path/to/store/files";
// get the file name from the querystring.
$fileName = $_REQUEST['file'];
// Check if the file exists if not redirect to denial page.
if(!file_exists($storageDir . '/' . $fileName)) header("Location: /denied.php\n\n");
// put what ever other detection you want here. Check for login etc....
// If we haven't redirected to a denied page we can send them the content.
// Important headers to set so we can force the download.
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='. $fileName);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . filesize($storageDir . '/' . $fileName));
ob_clean();
flush();
readfile($fileName);
exit;
?>
Now when a file is requested if it exists and meets all the standards you have requested it will allow to download.
Now let’s say you don’t have php on the server, or asp or ruby or python…. I know highly unlikely, but it could happen. Or say you have a website where you have already linked 1000 of these files, and using the above method would cause you to have quite a bit of work. You could use mod rewrite to protect the files using 2 different methods.
The first is detecting the http referer. By detecting the refering page URL you are basically telling the server to only allow access to the files from the pages and not directly from the URL. If the pages that the files are linked to are secured via an authentication scheme then bingo the access to the files are protected.
What we are doing here is using mod_rewrite to detect if the referer is empty. If it is then we redirect them to a page telling them that it is unaccessable.
RewriteEngine On
RewriteCond %{HTTP_REFERER} ^$
RewriteRule /* http://mydomain.com/denied.html
The second is to use mod_rewrite to detect if a specific cookie is set a specific way. Here we test to see if a specific cookie is set to true. You could also write the expression just to see if it exists. If it doesn’t then you are denied.
RewriteEngine On
RewriteCond %{HTTP_COOKIE} !^mycookie=true$
RewriteRule /* http://mydomain.com/denied.html
These are just a few examples of how you can prevent access to files, and keep your important documents safe from those who may not have paid access to them, or who you don’t want to have access.
Media Region Control destroy’s culture sharing.
by jandrews on Mar.14, 2010, under Politics, Technology
Anyone who knows me knows that I have traveled far beyond the boarders of the US. I have had the ability to experience a culture that most Americans only see through hollywood’s eyes. In most cases incorrectly. The best way to accurately experience culture of a foreign land without visiting it, is through their eyes. Whether it be books, music, or video it can more accurately depicts what that culture values.
Back in the 1980s we had the video revolution. People could go to the store and buy a VCR, rent movies from a local shop. You could go on vacation overseas and bring back movies to enjoy with your friends, or if you knew someone over seas you could even trade movies. The ability was also there to buy “import cds” from music stores. I remember as a teenager, there were many European bands that had 4-5 CDs and only 1 released in the US, so if you wanted those CDs you had to special order them.
The problem began with the Playstation. Sony’s hit video game machine that won over the heart of the video game world in the 90s. Sony had built in a protection schema to prevent people from buying video games in Japan from other countries in the world by making it so that other players couldn’t read discs from other regions. Many games that were released in Japan never made it to other countries, so if you wanted to play that “Castle of Cagliostro” game you needed a Japanese playstation.
Eventually the electronic nerds of the world figured out how to modify the play station to allow playing of any region game. At the same time they broke the copy protection schema, so that you could now copy playstation games with CDR media.
Soon there after came the DVD. The MPAA decided that it also wanted to use region protection on it’s DVDs. There are 13 regions. The US is region 1, Japan and UK are region 2. If you buy a region 2 disc from the UK it will not play in your DVD player. Destroying any fair use that you have to the media you legitimately own, and forcing you to buy a DVD player from the UK. Again soon after the nerds came to the rescue and did a couple things. Many hacked their machines to play multi region discs. DVD Jon broke the encryption schema called CSS and allowed you to copy DVDs to blank DVDs and remove the region protection.
Now we have blue ray discs. The media companies have smartened up a little though. They have internet connections and once a Discs key is broken they no longer produce discs with that key and update your blue ray player. Blue Ray keys get broken all the time, so this is also pretty ineffective.
The RIAA tried to do the same thing with DVD Audio, but since MP3s came out and took over digital audio, the DVD Audio plans fell on it’s back and have never been heard from again.
This now brings me to my point. The inclusion of region controls is bad. It prevents the people of the world from sharing their culture with one another unless an entity licenses the rights to distribute the media. While we have been lucky in the US with Japanese animation. There are other aspects of other cultures that I personally would love to see. I saw a great Korean film on a flight to Japan. Will I be able to buy it on blue ray and play it in the US? Probably not. We are stifling the ability for other cultures to understand each other. We can listen to President Obama praise or scold some foreign country, but until we have the ability to see what their people see first hand. To see what values they hold without restriction from the media conglomerates, we the people of the world miss out.
PHP Class – Calendar Matrix
by jandrews on Mar.08, 2010, under PHP Development
The other night I found myself needing a PHP class file that would give me calendar data. Specifically I needed something that I could build a calendar display with. The problem was I didn’t want it to write the HTML, I just wanted it to give me a multidimesional array of weeks and days. That way I could have whatever content I wanted in it. Not finding anything that didn’t write out HTML I created the CalendarMatrix class.
/**************************************************************************
Copyright 2010 James Andrews (email : contact at jamesmandrews dot com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation version 2 of the License
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
**************************************************************************/
class CalendarMatrix implements ArrayAccess, Iterator, Countable
{
// Define a list of the days of the week in english.
private $daysOfWeek = array( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday','Saturday','Sunday');
private $dayCount = 0;
private $matix = array();
public function __construct($year, $month)
{
$this->dayCount = cal_days_in_month(CAL_GREGORIAN, $month, $year);
$this->generateMonthWeeksMatrix();
}
public function calendarDayHeaderArray()
{
return $this->daysOfWeek;
}
public function getMonthName($year=false, $month=false)
{
return date('F', mktime(0, 0, 0, $month, 1, $year));
}
private function firstDayOfMonth() {
return date("l", strtotime(date('m').'/01/'.date('Y').' 00:00:00'));
}
private function primeMatrix($startPos)
{
// Set up the first matrix array
$this->matrix[] = array();
for($count=0; $count < $startPos; $count++)
{
$this->matrix[(count($this->matrix)-1)][$count] = "";
}
return $matrixPos = count($this->matrix[(count($this->matrix)-1)]);
}
private function generateMonthWeeksMatrix()
{
// Get the position for the first day in the week header array.
$startPos = array_keys($this->daysOfWeek, $this->firstDayOfMonth());
// prime the matrix
$matrixPos = $this->primeMatrix($startPos[0]);
// Handle each day of the week
for($day = 0; $day < $this->dayCount; $day++)
{
// Fill in the date into the array value
$this->matrix[(count($this->matrix)-1)][] = ($day+1);
// If the current array hits a length of 7 start a new one.
if(count($this->matrix[(count($this->matrix)-1)]) == 7){
$this->matrix[] = array();
}
}
}
/*
* Below are our "implementataion functions."
*/
// We don't want to be able to change the data, so this
// function though here for compatibility does nothing.
// We'll throw an exception later.
public function offsetSet($offset, $value) {
}
public function offsetExists($offset) {
return isset($this->matrix[$offset]);
}
public function offsetUnset($offset) {
}
public function offsetGet($offset) {
return isset($this->matrix[$offset]) ? $this->matrix[$offset] : null;
}
public function rewind() {
reset($this->matrix);
}
public function current() {
return current($this->matrix);
}
public function key() {
return key($this->matrix);
}
public function next() {
return next($this->matrix);
}
public function valid() {
return $this->current() !== false;
}
public function count() {
return count($this->martrix);
}
}
The class is designed to mostly work like an array. With one exception, you can not modify an indexed value. It does how ever allow you to use for, and foreach statements to iterate through the array.
// Instantiate the matrix using the year and month in the constructor.
$matrix = new CalendarMatrix(2010, 03);
The matrix will now initialize itself with the constructor and you can use it like so.
<table>
<?php foreach($matrix as $week): ?>
<tr>
<?php foreach($week as $day): ?>
<td<>?php echo $day; ?></td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
</table>
The code will now have created an calendar with the first row being Monday the last row being Sunday. There is also a function go build the day header at the top.
<table>
<tr>
<?php foreach($matrix->calendarDayHeaderArray() as $dayName): ?>
<th><?php echo $dayName; ?></th>
<?php endforeach; ?>
</tr>
<?php foreach($matrix as $week): ?>
<tr>
<?php foreach($week as $day): ?>
<td<>?php echo $day; ?></td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
</table>
It is also flexible enough to be used to build a calendar out of divs simpley use both foreach calls next to each other and then put a div in the middle instead of a <td> tag.
Review – Ibis Reader
by jandrews on Feb.27, 2010, under Programming, Software, Web Development, iPhone Programming
Today I was browsing through my tweeps when I saw that @liza had an announcement. A project she’s been working on for some time has come to life, and is viewable for all too see. This project is Ibis Reader, and HTML5 based ePub reader, which allows you to read ePub applications on any mobile devices who’s browser supports HTML5.
I decided to take it for a test drive. I grabbed my iPhone was went to Ibis Reader where I was redirected to the mobile version, and to where I was given instructions on how to setup Ibis Reader on the iPhone. One of the things it asked me was if it could use 50MB of storage on my phone. I agreed, and next I found myself in an area where I could browse books. I scrolled through a couple pages until I got to one called “Japanese Fairy Tales”. I’m a big Nipponophile (Japanese nut), so I decided to grab that, and start to read.
The interface is very simple. touch the right side of the screen and you advance a page, touch the left side of the page and you go back a page. Very easy from the get go. The text displays at a nice readable font size, with a font that’s easy on the eyes. Flipping the iPhone on it’s side, Ibis Reader knows to change the size of my page. The only thing that doesn’t seem to work here is the cover, which is a graphic, and not a huge concern in my opinion.
Since Ibis Reader takes advantage of local storage space the book reads fast. Page loads take only rendering time, and since it’s text, that’s no time at all.
I am very happy with how simple and easy this application runs. If I didn’t know better I would think it was a native app that ran locally on my iPhone. Bravo @liza, this is work to be very proud of.
Wordpress is more than a BLOG!
by jandrews on Feb.19, 2010, under Web Development
Since it’s inception Wordpress has been customized and built into probably the most easiest CMS to use for maintaining website. The page administration is real simple to use. They have created a wonderful API that is simple to understand, so that even the most novice developers can jump in and get their hands dirty. I have fallen very much in love with that simplicity.
For the past few days I have thought that I wanted a new look for my website. I am not a designer. I can cobble together something that looks “ok-ish”, but that’s about it. I turned to a website that I have come to rely on when I need designs for personal projects. That site is called Themeforest.net. It allows you to buy designs, prebuilt HTML templates, and even Wordpress themes that you can use on your site un-exclusively. Now I could have gone and found a design, and coded all the HTML/CSS/PHP for myself, but I didn’t want to spend the time. I have other projects on my plate, so I thought I would simply find a Wordpress theme that was appealing purchase it and make a go of it. SIx hours of watching video.
While the theme is artistically pleasing, and full of all sorts of features it fails like so many other themes whose designers still see Wordpress as a blogging tool, and not a content management system. The home page is driven by blog category instead of it being a “page”. The javascript carousel is also driven by a category. While I can’t say that I feel it’s 100% wrong, I have had customers who have bought themes and became frustrated because the theme they bought didn’t support pages in the carousel, and then I had to figure out a way to fix it.
These designer/developers have to figure out that Wordpress is not just a blog, and that their customers do not want to rely on the blog aspect and categories to manage “pages” of a site when “pages” is already part of the Wordpress functionality.
I have spend too much time this evening hoping for a response on their forums, or my comment on Themeforest.net. Then trying to debug the code because I really wanted the new look up tonight. Alas, that is not the case. I have it at 99%, but am missing something stupid I am sure. Tomorrow is a new day, maybe I’ll 1) get a response with a fix, or 2) figure out what I am missing.