Use Only Genuine Interocitor Parts

Add to Technorati Favorites

Endorsements

Firefox 3

Kobayashi Maru For Developers

Friday, June 20th, 2008 at 12:45 pm by Kenny

Being the geek that I am, I remembered the reference to the Kobayashi Maru from Star Trek many years ago, but I was surprised when one of my professors in college brought it up in reference to a sorting algorithm. His linking these two references changed the way I thought about solving problems.

But first, a brief history…

In Star Trek lore, there is a test that captains must go through. Notice I said "go through" rather than "pass". The purpose was to test the character of the captain-to-be. The test setup a no-win situation in which the captain had to choose between letting one of two groups of people die. It was impossible to save both groups of people. However, as the story goes, Kirk was the only captain to find a way to "pass" the test. He did so by reprogramming the simulator such that there was a way to pass.

And now back to our story…

In my Data Structures II class in college, we were given the task to write the most efficient program to sort a list of 1000 random integers from the set 1 to 1000. (I think it was 1-1000, it might have been 1-10000 or more. It doesn't really matter for the purpose of this explanation.) That is, the list could contain the same number twice or more or there may not be any instances of a particular number. Every student would be given the same list of numbers, so the test was to see how fast you could sort the list.

Most students hit a wall when they Googled and found the fastest way to implement standard sorting algorithms that end up with O(n log n) time for best case performance. Dr. Charles Anderson, one of my professors for another class (who is now my business partner at Western Skies), suggested that he had a way to perform the sort in O(n) time but that it was cheating and he wouldn't tell me how until after the contest was over. The only hint he gave me was "Kobayashi Maru". I know what the Kobayashi Maru was, but I had no idea how it applied here, so he left me quite confused.

The next week, when the contest was over, he explained to me how he could sort the list of integers in O(n) time instead of O(n log n):

  1. Declare an array (we'll call it arr[]) that is the size of the largest integer possible in the list, in this case 1000, and initialize all the values of the array places to 0.
  2. Pass over the list with a loop. A every position in the list, increment the value at that location in arr[] by 1. That is, if the first item in the list is 47, perform arr[47] += 1.
  3. Once that first loop has been created, pass over each place the array and print that location the number of times of the value stored in that location.

In other words, in pseudocode:

arr[] = array(1000)

// load array
for x in unsortedIntegers while 0 < i <= 1000
  arr[x] += 1
  i++

// print sorted list
for x in a arr[] while 0 < i <= 1000
  while 0 < j <= arr[x]
    print i + ','
  i++

The trick is that you aren't actually sorting the list. You are identifying how many times each number occurs and then using the array data structure to identify those occurrences in order. Rather than O(n log n), you've only passed over n twice, which is then O(2n), or just O(n).

At the time, this blew my mind and, in a way, it still does. This isn't thinking outside the box. It's thinking of a different box to fix the problem in the first box! It opened up my mind to a new way of thinking and new possibilities.

I recently used this when I needed to search for the occurrence of a 2-letter country code in an array of country codes in JavaScript. Rather than loop through the array and search for the country codes, I converted the array to a string and then searched for the occurrence in that string, which was a O(n) operation. I will admit, however, that I'm not familiar with the internal workings of JavaScript. This version may be as inefficient as looping over the array, which is probably what toString().search() does anyway. Here's how I did it in JavaScript:

var countries = document.getElementById("CountryCode");
countries.onchange = function(){isEurope();};	

function isEurope()
{
  var codes = ["AL","DZ","AD","AO","AI","AQ","AM","AT","AZ","BH","BY","BE","BJ",
              "BA","BW","BV","BG","BF","BI","CM","CV","CF","TD","KM","CG","CD",
              "CI","HR","CY","CZ","DK","DJ","EG","GQ","ER","EE","ET","FO","FI",
              "FR","FX","GA","GM","GE","DE","GH","GI","GR","GL","GN","GW","IS",
              "IR","IQ","IE","IL","IT","JO","KZ","KE","KW","KG","LV","LB","LS",
              "LR","LY","LI","LT","LU","MK","MG","MW","ML","MT","MR","MU","YT",
              "MD","MC","ME","MA","MZ","NA","NL","NE","NG","NO","OM","PS","PL",
              "PT","QA","RE","RO","RU","RW","SH","SM","ST","SA","SN","RS","SC",
              "SL","SK","SI","SO","ZA","ES","SD","SJ","SZ","SE","CH","SY","TJ",
              "TZ","TG","TN","TR","TM","UG","UA","AE","GB","UZ","VA","EH","YE",
              "YU","ZM","ZW"];

  var isEurope = false;

  for(i = 0; i < countries.length; i++)
  {
    if(countries.options[i].selected)
    {
      if(codes.toString().search(countries.options[i].value) > 0)
      {
        isEurope = true;
      } // end if test
    } // end if test
  } // end for loop

  if(isEurope)
  {
    // do some stuff
  } // end if test
} // end function isEurope

And there you have it. My own little Kobayashi Maru. While this isn't the most spectacular example, the point of this demonstration is to show you that there are more interesting ways thinking about problems. Try putting the data in a different box to solve a problem.

Edit:

Dr. Anderson pointed out to me that another way to do this would be to put all the country codes into an associative array and then search by looking for a value at index country code. Also, the complexity is more like O(mn) than O(n) as the search() function, even implemented in C within JavaScript, has to be a linear search. Although that's still faster than doing your own nested search in JavaScript. The hot ticket is to put all the country codes into an associative array so that search is based on key, which drops the complexity to O(1).


  • E-mail this story to a friend!
  • Google
  • bodytext
  • Technorati
  • del.icio.us
  • Slashdot
  • TwitThis
  • Furl
  • Fark
  • Reddit
  • StumbleUpon
  • Facebook

Yahoo vs. Eric Meyer CSS Reset

Thursday, June 19th, 2008 at 12:09 am by Kenny

In my post titled WebVisions 2008 Conference Debriefing, I mentioned the concept of a CSS reset and provided links to two versions: the Eric Meyer CSS Reset and the Yahoo UI Library CSS Reset. Both address the issue of browser having their own internal stylesheets that don't necessarily match.

For example: an h2 tag in one browser might have font-size: 16px; and margin-bottom: 12px; while another might have font-size: 18px; and margin-bottom: 14px;. That means that without any of your own CSS work, the same plain-Jane <h2>Some Subtitle</h2> code will look differently. These are the battles web developers have to face and why we hate IE for its non-standard renderings.

The purpose of the concept of a CSS reset is to put all browsers on an even playing field before you begin to style the content. That is, make sure that all elements render the same on all browsers (or rather, all major browsers) so that adding your own styling will have the same effect across the spectrum of renderings. That's not to say that you won't need to make special hacks to fix inconsistent renderings *cough-IE-cough*, but a CSS reset puts you a lot closer to the end goal than where you started.

I've only tried implementing and developing CSS with the Eric Meyer CSS reset and the Yahoo reset once each, so my experience here is somewhat limited, but these are my initial impressions. While both are essentially the same technique and could be adapted to behave more like the other, I'm going to address the out-of-the-box functionality.

Eric Meyer's CSS Reset - Eric Meyer CSS Reset

This was my first attempt at using a CSS reset and you're looking at the results in this current blog theme (as of the date of this post). Meyer's method is to set all elements to be, essentially, unstyled. That is, all elements render as plain text. No bolding for <strong>, no italics for <em>, no margins for <p>, etc. The nice thing about this is that you get to style everything from the ground up. The bad thing about this is that you have to style everything from the ground up. I was excited at first, but I became increasingly frustrated with having to write quite a bit of CSS just to get elements to behave even remotely like they normally do. I understand the purpose in doing this, but it is a ton of work just to get the most basic HTML to display with standard behaviors. I eventually realized that a work-around for this would be to develop a "CSS starting point" where there are definitions for elements that just define the basic behavior.

Another downside to Meyer's method is that he simply provides the code. This didn't seem like a downside at all to me until I used Yahoo's implementation, which I will explain shortly. In fact, it never even occurred to me that there could be a better way.

Don't get me wrong. I have a tremendous amount of respect for Eric Meyer and he has done a great job putting together the code for the CSS reset. I only see the ways to improve on it after having used Yahoo's CSS reset. *Segue*

Yahoo's CSS Reset - Yahoo UI Library CSS Reset

First, let me admit my bypasses. I didn't use, or even look at, the Yahoo CSS Reset before trying Eric Meyer's because…well…I'm a Google-guy. If the link had been to the exact same content at Google, I would have not even looked at (okay, that's an exaggeration) Meyer's version. I drink the Google-flavored Kool-Aid with the left hand and the Apple-flavored Kool-Aid with the right. (There, Microsoft zealots. Are you happy? I'm an admitted zealot too, just on the other side.)

I was very impressed initially with the organization and presentation of the Yahoo page. The code was very readable and the instructions were clear and concise. They also provide a cheat sheet (PDF download), an SDK download, and several other tools and examples that I found very helpful and interesting.

Yahoo also provides a hosted file for the CSS reset so you can simply call the include from their server in the head of your HTML. This was a nice feature. One less file to maintain and serve.

Additionally, and this was the biggest selling-point for me, Yahoo provided the "CSS starting point" code that I was looking for to get the elements to their minimal display characteristics and, like the CSS reset, they also provided a hosted file for me to include. After adding two lines of meta code in the head of my HTML file, I had reset the CSS to zero and then styled it to a standard display. Perfect! Just what I was looking for and here it was in an easy to consume, highly supported codebase.

Coming Soon…

Google CSS Library - Google Blueprint CSS Framework

As I was writing about being a Google zealot and wishing that Google had a CSS reset, I decided to search for "google css reset" and, lo and behold, the very first link that Google returned (imagine that!) was for the Google Blueprint CSS Framework, which includes a CSS reset and starting point styling. I should have known that Google would swoop in and save the day. I'll try the Google CSS reset for my next site and report my findings.

EDIT:

I recently tried validating some CSS that I added to a site after using the Yahoo CSS reset. I was sad to find out that it doesn't validate. I think I read somewhere that the Eric Meyer CSS reset doesn't validate either. I decided to punt on this one and just make sure that my personal CSS code that I built on top of the reset code will validate, but then, technically, my whole page doesn't validate since I'm using the CSS reset. I guess that's something I'll have to wrestle with until a better solution comes along.


  • E-mail this story to a friend!
  • Google
  • bodytext
  • Technorati
  • del.icio.us
  • Slashdot
  • TwitThis
  • Furl
  • Fark
  • Reddit
  • StumbleUpon
  • Facebook

Sending Email From PHP On GoDaddy (And Possibly Other Hosts)

Monday, June 16th, 2008 at 11:37 pm by Kenny

Recently, while working on the temporary site for Moonfar, I wanted to send the user an email as confirmation that they had signed up for email notifications. Essentially, you define the recipient, the subject line, the body, a few headers, and then call the mail() function while passing those parameters to it. PHP's mail() function does the rest, provided that your host has PHP configured properly.

Let me preface this by saying that I've only tested this on GoDaddy's Linux Deluxe Hosting plan. If you are trying to do this with another web host, you need to make sure that the install of PHP you are using supports the mail() function.

<?php
  $to = 'user@theirdomain.com';
  $subject = 'Your subject line';

  // the message here is HTML, but you could
  // use plain text in the same manner
  // this could also be pulled from a template file
  $message = '
    <html>
    <head>
      <title>Your Title Here</title>
    </head>
    <body>
      <p>Your content here...</p>
    </body>
    </html>';

  // To send HTML mail, the Content-type header must be set
  $headers  = 'MIME-Version: 1.0' . "\r\n";
  $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
  // Additional headers
  // I'm not sure how the To: field in the header functions since it's part
  // of the function call, so I've commented it out here
  //$headers .= 'To: ' . $emailAddr . "\r\n";
  $headers .= 'From: YourName <you@yourdomain.com>' . "\r\n";
  $headers .= 'Cc: ' . "\r\n";
  // if you want to receive a copy
  $headers .= 'Bcc: you@yourdomain.com' . "\r\n";

  // Mail it
  mail($to, $subject, $message, $headers);
?>

It's as easy as that. That said, I read somewhere that there is a 1000 emails per day limit using this method on GoDaddy without paying for outbound emailing services, but I could be mistaken.


  • E-mail this story to a friend!
  • Google
  • bodytext
  • Technorati
  • del.icio.us
  • Slashdot
  • TwitThis
  • Furl
  • Fark
  • Reddit
  • StumbleUpon
  • Facebook

WebVisions 2008 Conference Debriefing

Sunday, June 15th, 2008 at 11:05 pm by Kenny

I recently attended the WebVisions 2008 conference in Portland, OR. It was my first conference, so I can't speak to the quality with much experience. However, my general opinion was that there was some good, some bad, and some ugly, as one might expect. That said, the good was well worth the experience. Plus, I won the grand prize raffle: Adobe CS3 Premier. Although, as of the date of this post, I have not yet received it.

You can find the podcasts of the presentations and the associated presentation slides with these links:

Here is a quick debriefing of my impressions of the presentations and the most important things I learned

Blogging For A Living
Jim Turner
http://www.genuineblog.com/

  • Bloggers are social media managers
  • Be an evangelist through your blog
  • Monitor the net for negative or inaccurate information about your organization and use your blog to rapidly respond and provide an official statement to correct misinformation
  • "Control is an illusion. You can't control what is being said. It's already happening. You can't stop employees from spreading information, so push forward with positive blogging." (Paraphrased)

Hacking Social Media
DL Byron
http://texturadesign.com/
http://bikehugger.com/

  • DL was a very inspiring individual, but there wasn't much that I was able to draw from the presentation except for providing examples of how small organizations can combine (through mashups, etc.) services for cheap, rich aggregate tools.

Design Is In The Details
Dan Rubin, Bryan Veloso
http://design.isinthedetails.com/
http://bryanveloso.com/
http://superfluousbanter.org/

  • Great presentation. The best of the conference.
  • Let your layout breathe
    • Allow space between elements
    • You don't need borders on elements if you have 2 elements with a different colored space in between, such as two white boxes with a gap between them on a black background
  • Multiples and factors of a common measurement
    • If your main text font is 12px, then 6, 12, 18, 24, etc. for margins and other sizes are a good way to keep common feel through your site
  • Subtle effects
    • Use effects subtly, such as in drop shadows
    • Add noise for a subtle texture on a background to add a real-world feel
  • To get varying shades of the same color, pick your base hue, then add layers of black or white using soft light blending mode and transparencies to achieve shades and tints

Drupal
Sean Larkin
http://www.opensourcery.com/

  • This presentation sucked was less of a "howto" and more of a "this is how we make money" presentation. I wanted to hear more about how to use Drupal.

Faster, Cheaper, Better
David Verba
http://www.adaptivepath.com/aboutus/david.php

  • This was essentially a review of how it's cheaper and faster to make web apps now, which is obvious and doesn't require a conference session to make that point.
  • Saying "…and finally…" 6 times is 5 times too many.

CSS Transformation
Christopher Schmidtt
http://christopherschmitt.com/

Ruby On Rails
Jim Meyer
http://www.cucinamedia.com/
http://blog.geekdaily.org/

  • Very pro-Agile Dev and pro-TDD (Test Driven Development)
  • For any development, to improve scalability and performance:
    • Stay out of the DB as much as possible
    • Stay out of the dynamic code as much as possible
    • Push info (code?) as close to the user as possible

Web Site Optimization
Kimberly Blessing
http://www.kimberlyblessing.com/

  • Analyze, test, and tune
  • Validate
    • declare a valid DOCTYPE to ensure that the browser will stay in STANDARDS MODE, otherwise it will go into QUIRKS MODE which will cause slower rendering
    • Validate (X)HTML/CSS
  • Simplify
  • Concatenate
    • Use only 1 CSS file and 1 JS file; you can always merge at the build cycle if you prefer to keep them separate for development organization
  • IE-Proof CSS
    • Code against the FOUC (Flash Of Unstyled Content)
    • Don't use @import, use link
  • Call Javascript As Needed
    • Define JS near where it is needed
  • Save Scripts For Last
    • If it isn't needed on load, define it at the end of the page to prevent parsing until the page has displayed
  • If you can't GZip, then strip
    • Get rid of whitespace and comments, convert spaces to tabs (if you want to save spacing) in build phase

  • E-mail this story to a friend!
  • Google
  • bodytext
  • Technorati
  • del.icio.us
  • Slashdot
  • TwitThis
  • Furl
  • Fark
  • Reddit
  • StumbleUpon
  • Facebook

Add A Digg Badge To WordPress Posts/Pages

Saturday, August 25th, 2007 at 12:38 pm by Kenny

I know there are a lot of widgets and plugins for WordPress out there for adding a Digg badge to posts (I know, because I tried half a dozen or so of them) but I didn't find any that worked consistently and provided the functionality I wanted. After researching the Digg Tools API and a few other examples online, I've composed this block of code for generating Digg badges.

To add a Digg badge to your WordPress posts or pages, simply add the following code block immediately before or after the PHP block that contains the_content(). For posts, you would want to modify the Main Index Template, Single Post, and Archives theme files. For pages, you simply need to modify the Page Template theme file. Here's the code:

<div class="diggLink">
    <script type="text/javascript">
        digg_url = '<?php the_permalink() ?>';
        digg_title = '<?php the_title(); ?>';
        //digg_topic = 'TOPIC'; // replace TOPIC

        /*
        Use the output buffer to capture the text
        output from the_ID() rather than having
        it rendered to the page.
        */

        digg_bodytext = '<?php
            ob_start();
            the_ID();
            $postID = ob_get_contents();
            ob_end_clean();

            /*
            Get the body of the post, remove HTML,
            remove carriage returns and line feeds,
            escape 's, return only the first 350 char.
            */
            $postObj = get_post($postID, OBJECT);
            $body = strip_tags($postObj->post_content);
            $body = str_replace(chr(10), '', $body);
            $body = str_replace(chr(13), '', $body);
            $body = addslashes($body);
            echo substr($body, 0, 350);
        ?>';
    </script>
    <script src="http://digg.com/tools/diggthis.js"
        type="text/javascript"></script>
</div>

I've also added a class to the wrapping DIV and added it to the stylesheet for my theme to style the positioning of the Digg badge. I place the above code right before the the_content() block and this CSS class is what positions my Digg badge to the right of my posts.

.diggLink
{
    float: right;
    margin-bottom: 4px;
    margin-left: 4px;
}

If you'd like to set your posts to all submit to one particular topic, you can uncomment the line that refers to digg_topic in the code block and then change TOPIC to the topic you'd like to use. You can find the list of topics on the Digg Tools API page.

If you have any questions, feel free to comment and ask me. By the way, this same code block is currently in use at Pac Ten Review.


  • E-mail this story to a friend!
  • Google
  • bodytext
  • Technorati
  • del.icio.us
  • Slashdot
  • TwitThis
  • Furl
  • Fark
  • Reddit
  • StumbleUpon
  • Facebook

Eternally Up To Date Copyrights

Wednesday, July 25th, 2007 at 11:48 pm by Kenny

I can't tell you how many times, both personally and professionally, I've come across web sites that have out of date copyright dates. A living, breathing, up to date site should have a current copyright date somewhere on the page, usually in the footer. Changing the year is easy enough if it's static, but it's one of those things you have to remember to do (and you have to know how to do it). If your code isn't modularized (that is, if every page has the copyright date hard coded), then having to change these dates each year could be a very laborious process, even if you're savvy enough to use a global find and replace.

Why should you even have to make this update by hand? The web page should know that the copyright year is always the current year. There are a couple of ways to do this, depending on what you have available on your web server.

Concept

The concept behind this technique is very simple. You simple replace the year with a dynamically written number pulled from the supporting language's date functions. Here is the static code that we will start with:

<p>Copyright &amp;#169;2007 Your Web Site</p>

By the way, &amp;#169; is the © symbol.

Client-side Code Method

If you don't have any access to a dynamic server-side technology such as PHP, Java, Python, Perl, .NET, or some other programming language, then you will need to use Javascript. Here's an example of generating the year dynamically with client-side Javascript:

<p>Copyright &amp;#169;
<script type="text/javascript">
    var date = new Date();
    document.write(date.getFullYear());
</script>
Your Web Site</p>

The downside to this method is that, since the date is rendered by the browser, it is dependent upon the client's environment. If the user has Javascript disabled or if there is just some other unpredictable variable in the client's browser then the copyright year will be completely missing rather than just a year or two out of date. The other problem that arises is this: if the client's computer has the year set to 1963, then the copyright date on the web page will appear as 1963.

Server-side Code Method

If you have the ability to utilize a server-side technology, such as PHP, then you should. This method is preferred because you control the behavior and the date is written to the client as plain text. That is, it is rendered on the server and then streamed to the client as plain text. Here's an example in PHP of server-side dynamic copyright year text:

<p>Copyright &amp;#169;<?php echo date('Y'); ?> Your Web Site</p>

I could list out a dozen examples of how to dynamically generate the year, but I would probably end up leaving out the specific language that you are looking for. You can use this technique with any language. Yes, I know this isn't a ground-breaking technique, it's just printing the year, but I've seen enough examples of people with out of date copyright years that I thought this was a worthwhile tip to share. Good luck.


  • E-mail this story to a friend!
  • Google
  • bodytext
  • Technorati
  • del.icio.us
  • Slashdot
  • TwitThis
  • Furl
  • Fark
  • Reddit
  • StumbleUpon
  • Facebook

Spam-proof MailTo Links

Friday, July 13th, 2007 at 11:03 pm by Kenny

I like providing links for e-mail on web pages, but I hate that spam-bots scrape sites looking for e-mail addresses linked in the usual manner. There are many hacks to try to avoid spam-bots

The Cander Method Version 1 (AKA: "Make The User Do The Work")

Named for a friend that I learned this from, one way to avoid this is to use ineffective links that require a person to modify address before sending it. Here's an example:

<a href="someuser_AT_somedomain_DOT_com">someuser_AT_somedomain_DOT_com</a>

…which appears as…

someuser_AT_somedomain_DOT_com

While this isn't spam-proof, it's spam-resistant. However, as I said, the user would then have to replace _AT_ with @ and _DOT_ with . in order for the e-mail address to be valid.

The Cander Method Version 2 (AKA: "Promiscuous Links, Strong Immune System")

The theory behind this method is "ah, screw it". Well, kinda. This method, also gleamed from the same friend, employs a standard mailto link that is completely vulnerable to spam-bots. Rather than try to trick spam-bots, you just resign yourself to the fact that spam is part of life and it's more important provide users with a good link. The spam protection is then handled by a good spam filter or by redirecting all your e-mail to a Gmail account, which is famously known for it's fantastic spam filtering. While I understand this approach, I still think that a good offense is the best defense.

The Corporate Method

Form e-mail is also a good option if your server supports it. That is, you can setup a script to take text from a standard HTML form and submit it via e-mail to you. This requires a bit more code and monkeying with the server to make sure that the web server is up and functioning and some web hosts may not even allow for this.

The Script-Redirect Method

Another method that I ran across (again, compiled from many sources and some original tinkering) is to provide a redirect that prevents spam-bots from scraping the address. The downside to this method is that you don't display the text of the e-mail address. The upside of this method is that the link works as-is and the user doesn't have to clean up the address before sending the e-mail. Here's how it works:

<a href="mailto.php?u=someuser&d=somedomain.com"
    onclick="target='_blank';"
    onmouseover="this.style.cursor='pointer';">E-mail</a>

Incidentally, the onclick and onmouseover events provide an XHTML Strict method of opening a new window without using extensive Javascript.

Place the preceding link wherever you'd like the e-mail link to occur. You'll notice that the link points to another script called mailto.php and it has a couple query string parameters. The u parameter refers to the username in the e-mail address (everything before the @) and the d parameter refers to the host (everything after the @).

Now that we have the link setup, we need the script that we are actually calling: mailto.php. This is the really easy part. It's one single line that pulls the query string parameters, puts them into standard e-mail address form, and redirects the browser to the mailto link. It's as simple as that. Here's the script for mailto.php:

<?php
    // pull values from query string and
    // redirect to a mailto link
    header("Location: mailto:$_GET[u]@$_GET[d]");
?>

While this may not fool all of the spam-bots out there, it should hopefully cut down on a significant bulk of spam that you might incur from posting a link to your e-mail address.


  • E-mail this story to a friend!
  • Google
  • bodytext
  • Technorati
  • del.icio.us
  • Slashdot
  • TwitThis
  • Furl
  • Fark
  • Reddit
  • StumbleUpon
  • Facebook

Make A File Dropbox For Quick Downloads

Friday, July 13th, 2007 at 10:30 am by Kenny

I frequently need to setup a quick and temporary link for file download either for myself or others, but I hate having to create a new page with links to files that are only going to exist for a few hours. Apache and other web servers often provide this functionality with directory browsing, but I usually want directory browsing disabled or the server that I'm using (that isn't mine) has directory browsing disabled and I can't turn it on.

I wrote (and by "wrote", I mean "wrote some, borrowed some from all over the web–yes, I know I'm not the first to write a script like this) this script to parse a directory and display links for all the files in that folder.

Take the script below and either create a folder called 'files' in the same directory as this file or you can modify the $filesDir variable to point to the location that you'd like to place your temporary downloads. For example, on my server, I have a folder under the root called downloads (http://myserver.com/downloads/) and I place this script in the folder and name it index.php. Within downloads/, I have another folder called files where I place the files for download.

If you want the files in the same folder as the script (that is, you want them all at the same level), I've included a check before the links are displayed to make sure that it's not displaying index.php. If you don't call this script index.php, you'll need to modify that piece of the code.

Let me know if you have any questions or comments. As with the usual disclaimer, I'm sure there are enhancements that can be made to this for both performance and security and the code comes as-is and without warranty. :)

<?xml version="1.0" encoding="iso-8858-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
    <title>Download Dropbox</title>
</head>
<body>
    <h1>Download Dropbox</h1>
    <hr />
    <?php
        $filesDir = './files/'; // where you intend to drop files
                                // relative to this page
        $files = array();
        $dir = opendir($filesDir);

        // get the list of files
        while(($file = readdir($dir)) !== false)
        {
            // ignore directories and special files that
            // we don't care about
            // .DS_Store is a Mac system file that I
            // don't want displayed
            if($file !== '.' && $file !== '..' && !is_dir($file) &&
                ($file !== '.DS_Store'))
            {
                $files[] = $file;
            } // end if test
        } // end while loop

        closedir($dir);

        if(count($files) < 1)
        {
            echo "<p>There were no files found.</p>n";
        } // end if test
        else
        {
            // display links for download
            natcasesort($files); // sort files

            echo "<ul>n";

            for($i = 0; $i < count($files); $i++)
            {
                if($files[$i] != "index.php")
                {
                    echo "<li><a href=\"files/" . $files[$i] . "\">" .
                    $files[$i] . "</a></li>n";
                } // end if test
            } // end for loop

            echo "</ul>n";
        } // end else test
    ?>
</body>

  • E-mail this story to a friend!
  • Google
  • bodytext
  • Technorati
  • del.icio.us
  • Slashdot
  • TwitThis
  • Furl
  • Fark
  • Reddit
  • StumbleUpon
  • Facebook

Turn Blogger Into Your Own Blog

Friday, July 6th, 2007 at 10:20 pm by Kenny

Recently I was working with a client who wanted a blog for their site but they didn't have the money (and I didn't have the time) for a completely one-off solution. The initially proposed solution was to simply make the "Blog" link point to a Blogger (which was purchased by Google a while back, if you missed it) site for the client. I didn't feel very comfortable with this idea because I didn't think it would look very professional to link to a free blogging site, so I started out by using the template editor that Blogger provides to mimic the client's site. While this was a better solution, it still didn't seem professional enough. The site was still a Blogger site; the URL was Blogger's and I couldn't exactly match the look-and-feel of the client's site.

This is when I remembered that Blogger (as many with many other sites) provides an XML-based RSS feed of each individual blog. Why not consume the RSS feed and redisplay the content on the client's site?! This technique allowed me to utilize the blog publishing and management tools from Blogger while full integrating the blog into the client's site. Now, instead of linking to an external site for the blog, I would just create a page that scraped the RSS feed, parsed the XML, iterated over the entries, and displayed the content.

Now for the meat. First, you need to create a Blogger account (if you have a Google/Gmail/G-anything account, that will work), then create a blog under that account and enter some dummy posts. Make sure that your blog has site feeds enabled; consult the Blogger help if you can't figure this out. Once you have that setup, your blog's feed can be found at http://someblog.blogspot.com/feeds/posts/default?alt=rss where "someblog" is the name of your blog in your URL. Also, you'll notice that I've appended ?alt=rss to the link. This is mentioned in the Blogger documentation in reference to forcing the feed into RSS format rather than Atom.

The following PHP code example shows a function that parses an RSS feed into a 2D array for display within your site. Note: the simplexml_load_file() function is part of PHP5, so you'll need to make sure that your server is running PHP5 if you want to use this code directly.

<?php
    function getBlogPosts($blogFeedURL)
    {
        $xml = simplexml_load_file($blogFeedURL);
        $posts = array();

        if($xml)
        {
            // get all posts
            foreach($xml->channel->item as $post)
            {
                $posts[] = array('title' => $post->title,
                                    'pubDate' => $post->pubDate,
                                    'description' => $post->description);
            } // end foreach loop
        } // end if test

        return $posts;
    } // end getBlogPosts function
?>

This next block of code utilizes this function and iterates over the 2D array to display the blogs. Also, I've incorporated the concept of paging where you can specify the number of posts to display at a given time and paging links are found at the top and bottom of each page.

<?php
    global $blogFeedURL; // defined globally, URL to RSS feed
    global $blogPostsPerPage; // defined globally, used for paging

    $posts = getBlogPosts($blogFeedURL);

    if(count($posts) < 1)
    {
        ?>
            <p>There are no posts currently available.</p>
        <?php
    } // end if test
    else
    {
        // get paging index from query string
        $firstPost = (array_key_exists('first', $_GET) &&
                                is_numeric($_GET['first'])) ?
                                $_GET['first'] : 0;

        // if first post index plus offset is more than total posts,
        // set last post to total number of posts
        $lastPost = (($firstPost + $blogPostsPerPage) > count($posts)) ?
                                count($posts) : ($firstPost + $blogPostsPerPage);

        // previous page link
        if($firstPost > 0)
        {
            $first = (($firstPost - $blogPostsPerPage) < 0) ?
                                0 : ($firstPost - $blogPostsPerPage);
            ?>
                <p><a href="<?php echo $_SERVER['PHP_SELF'] . '?first=' .
                                $first; ?>">Previous Page</a></p>
            <?php
        } // end if test

        // next page link
        if($lastPost < count($posts))
        {
            $first = (($firstPost + $blogPostsPerPage) > count($posts)) ?
                                count($posts) : ($firstPost + $blogPostsPerPage);
            ?>
                <p><a href="<?php echo $_SERVER['PHP_SELF'] . '?first=' .
                                $first; ?>">Next Page</a></p>
            <?php
        } // end if test

        // display only those for this page
        for($i = $firstPost; $i < $lastPost; $i++)
        {
            $title = $posts[$i]['title'];
            $pubDate = date('D, M j, Y g:i A', strtotime($posts[$i]['pubDate']));
            $description = $posts[$i]['description'];
        ?>
            <div>
                <p><?php echo $title; ?></p>
                <p><?php echo $pubDate; ?></p>
                <p><?php echo $description; ?></p>
            </div>
        <?php
        } // end foreach loop

        // previous page link
        if($firstPost > 0)
        {
            $first = (($firstPost - $blogPostsPerPage) < 0) ?
                                0 : ($firstPost - $blogPostsPerPage);
            ?>
                <p><a href="<?php echo $_SERVER['PHP_SELF'] . '?first=' .
                                $first; ?>">Previous Page</a></p>
            <?php
        } // end if test

        // next page link
        if($lastPost < count($posts))
        {
            $first = (($firstPost + $blogPostsPerPage) > count($posts)) ?
                                count($posts) : ($firstPost + $blogPostsPerPage);
            ?>
                <p><a href="<?php echo $_SERVER['PHP_SELF'] . '?first=' .
                                $first; ?>">Next Page</a></p>
            <?php
        } // end if test
    } // end else test
?>

As I said earlier, the great thing about this method is that someone else (Google and Blogger) did all the hard work for you. The downside is that you have to login to Blogger to post content, but I think that's a small price to pay for the amount of work that is already done for you. You get the layout-free content and you can style it yourself and embed it in your own site as you see fit. Alternately, you could of course do this in Python, Java, .Net, or any language that you can make an HTTP call and then parse the XML.

As for the usual caveats, I'm sure there are ways to improve the security, add layers of error checking, use objects instead of a 2D array, so feel free to modify as you wish. This is where the "This software is presented as-is and without warranty…" bit goes.


  • E-mail this story to a friend!
  • Google
  • bodytext
  • Technorati
  • del.icio.us
  • Slashdot
  • TwitThis
  • Furl
  • Fark
  • Reddit
  • StumbleUpon
  • Facebook