My Blog

contains PHP and other web related content. (Sometimes there are some off topic things - don't freak out!)

Archive for the ‘Misc Web Design’ Category

How I test email recipients when I develop

Tuesday, August 31st, 2010

When developing an application, there are usually various different environments that you run the code in. First is the development environment. Next, you have the QA or test environment, staging, and then live or production. It stands to reason that if you are using outgoing e-mail in your application, and your application is in production, it should send to the proper recipients. However, what do you do in testing and development?

The Old Way: One Email to Rule Them All

The old way of testing was simple: If live, send to proper email address. If not live, send to my developer test address. So, if I ran a process, I might see something like 8 emails in my developer test box. The problem with this, however, is the only inkling I have that each e-mail is different is by any custom information inside of the email. Hopefully it says “Dear John Smith, ” or “Dear Suzie Q”. You also have no way of verifying if the e-mail address you retrieved for this particular message was in fact the right one – mainly because you overwrote it with a test one.

The New Way: Combining Test and Production Emails

Real quick, take a look at this RFC… Just kidding. But, after understanding the various formats of an e-mail address, I got a great idea. I should be able to use the + sign with the original email address and my developer test address. I may just need to replace the @ sign with _AT_. Why? Whenever you create an e-mail address, you can add the + sign after your user part of the email address to add additional tag information to it. So, if my e-mail address was thedude@guy.com, I will also receive e-mail if it is addressed to thedude+spammysite@guy.com.

So, for my code, if not in production, I’m going to replace the outgoing e-mail address with a specially formatted version of the email that contains the destination address but gets directed to my test email. So, in this case, my testing email address is test@aaronsaray.com. The outgoing address is newuserguy@hotmail.com. The resulting outgoing email address will be test+newuserguy_AT_hotmail.com@aaronsaray.com. It will enter my test e-mail box but I can still verify that the recipient would have been right.

Here is a bit of code I use to accomplish this:

1
2
3
4
5
6
$to = 'outgoing@email.com';
if (ENVIRONMENT != 'LIVE') {
    $parts = explode('@', 'test@aaronsaray.com');
    $to = str_replace('@', '_AT_', $to);
    $to = $parts[0] . '+' . $to . '@' . $parts[1];
}

Using Google Charts to make QR Codes

Tuesday, July 13th, 2010

QR Code for this page

QR Code for this page

Google Charts is my hero yet again. This time, I happened to notice that they have a chart in their API for QR Codes. Considering I was just searching google for a PHP class to do this, I was pretty ecstatic.

To implement, I made a quick line of jQuery to generate my QR Codes. Of course, I did this after the page loaded :) My goal was to generate a QR code for the page that the user is currently viewing. Pretty simple:

1
$("#qrImage").attr('src', 'http://chart.apis.google.com/chart?chs=150x150&cht=qr&chl=' + escape(window.location.href) + '&choe=UTF-8');

You can find all of the details and other parameters here: http://code.google.com/apis/chart/docs/gallery/qr_codes.html

Use your own short domain while waiting for BitLy Pro

Tuesday, May 11th, 2010

If you’ve checked out BitLy Pro, you’re probably pretty excited like I am. I saw it and immediately registered saray.me for a short URL. When I went to sign up, I found it was still in a queue system where you had to wait to get an invite. In the mean time, I still want to start using my domain.

After reading some of the documentation, I found that once you sign up for a bit.ly pro account, your existing bit.ly links that were created when you were logged in will be accessible via your short URL. With this in mind, I decided to just continue to create my bit.ly links but redirect my domain to bit.ly for the time being.

Log In to Bit.Ly

Goto bit.ly and login. (or create an account if you want). This is necessary so that you can now create and track your links.

Modify your domain

I’m using GoDaddy. I decided to forward my domain.

First, select your domain in the domain manager. Then, choose the forward domain option at the top of the list.

On the popup, choose the advanced option link. Make sure to choose temporarily forward the domain. This is needed because at some point, we’ll be redirecting this domain’s nameservers to bit.ly again to natively do this URL forwarding. Enter “http://bit.ly” in the box and click ok.

Try it out

Now, goto bit.ly and shorten an URL. I’m shortening http://aaronsaray.com/blog. This is now: http://bit.ly/cZqq0e. When I enter http://saray.me/cZqq0e into the browser, it serves the short URL from bit.ly.

Yay!

Timesaving Feature

Since I do continue to get my bit.ly links with http://bit.ly instead of http://saray.me in the beginning, I decided to make a Firefox bookmarklet to replace this for me. It’s pretty simple. All it does is take bit.ly and replace with saray.me.

1
var x=prompt('Bit.ly URL');alert(x.replace('bit.ly','saray.me'));

Here, you can drag this to your toolbar if you want :)
Saray.Me the Bit.Ly

IE6 warning on site

Thursday, April 22nd, 2010

So I got permission at the beginning of March to add an Internet Explorer 6 deprecation message to one of the sites I’m working on.

My goals are simple:

  • Do not pump the message out to search engines or anyone without IE6
  • Remind strongly but do not hinder the usage of the site

So, I felt the best way to do this was through a conditional comment. In the head of the document, the first thing I inserted is this:

1
2
3
<!--[if lte IE 6]>
<script type="text/javascript" src="/js/ie6warning.js"></script>
<![endif]-->

So, any browser that is Internet Explorer will understand this conditional comment. If it is Less Than or Equal to IE 6, it will load that javascript.

The javascript contains the following content:

1
2
3
4
$(function(){
	var ieDiv = $("<div id='ie6warning'><img src='/images/ie6logo.gif' alt='ie' /><div><h3>Did you know that your browser is out of date?</h3><p>To get the best possible experience using our website we recommend that you upgrade your browser to a newer version.<br />The current version is <a href='http://microsoft.com/ie'>Internet Explorer 8</a>.  The upgrade is free.  <em>(If you're using a PC at work you should contact your IT administrator.)</em> You may also try some other popular Internet browsers like <a href='http://getfirefox.com'>Firefox</a> or <a href='http://google.com/chrome'>Google Chrome</a>.</div></div>");
	$("#hd").prepend(ieDiv);
});

As you can tell, I’m using jQuery. However, the concept should translate to other javascript implementations as well. Basically, a message is created with a warning image. Then, the header element gets this box prepended to it.

Finally, we have a bit of css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/** ie 6 warning **/
#ie6warning {
	background-color: #FFFFDD;
	padding: 20px;
}
#ie6warning img {
	float: left;
	margin: 12px 0 12px 5px;
}
#ie6warning div {
	margin-left: 140px;
	padding-left: 27px;
	border-left: 1px solid #aaa;
} 
#ie6warning h3, #ie6warning p {
	margin: 0;
}

The finished product looks something like this:

Javascript and CSS Compression and Cache

Thursday, February 25th, 2010

I’ve been researching caching and compression techniques for my external resources for some time. My first design of JEMDiary was very greedy with HTTP connections. Couple that with having a less-than-perfect host (Dreamhost bleh…), users could feel the burn. I didn’t like it because it would even take ME forever to use my own website. I went on to discover many different key points I use when creating sites now – the Steps to Optimize Assets.

Steps to Optimize Assets

There are a few steps I live by when I design my websites now.

  • Use a subdomain for images, js and css. While I don’t go overkill with this (see: not 5 page brochure website), I do try to separate assets over multiple subdomains. The important thing is not to have too many – but none what so ever limit your user from loading your site as quick as possible. I generally use one for my assets and one for user submitted assets.
  • Use sprites. Whenever possible, reduce the amount of HTTP requests by combining images. It is faster to load an image that is 3x the size of the one you’re displaying than to open 2 more HTTP connections after you download the first image.
  • Cache non changing elements as long as possible. One of the biggest things I noticed on my dreamhost server was the misconfiguration of e-tags. After disabling them, I went and looked further into caching techniques. I found that most of my assets didn’t change – so I cached them up to a year.
  • Compress away white space. After you edit the source of your css, it doesn’t need to be pretty. In fact, things like comments and white space in css and javascript are just wasted bytes… bytes you could remove… but bytes you shouldn’t remove from your source. I deal with this by making a compressed copy on build.

These are my main rules. This article, however, is going to focus on how I deal with Javascript and CSS.

Disclaimer: The methods I’m going to describe here can be labor intensive. When you build your own system, you should strive to make some of these automated.

Preparing CSS for deployment

The first thing I do is create that subdomain. For my site example.com, users can visit http://example.com for the content. I create a subdomain called assets.example.com which is where I expect to get my content from. I generally create a server alias in the main config. This technically means that duplicate content could be served at both assets.example.com and example.com. I finish up by adding the following lines to the .htaccess file:

1
2
3
4
5
6
#make sure assets load properly
RewriteCond %{HTTP_HOST} ^assets.example.com
RewriteCond %{REQUEST_URI} !^/css
RewriteCond %{REQUEST_URI} !^/js
RewriteCond %{REQUEST_URI} !^/images
RewriteRule ^(.*)$ http://example.com/$1 [R=301,L]

This make sure that if the host is assets.example.com and the content is not coming form the css, js or images folder, to redirect with a 301 to the main domain. This will stop duplicate content.

Enough about this, what about my CSS?

I actually hold my css in a different folder in my architecture – not some place that is world readable. I usually call it the public_source folder – which is at the same level in the source tree as say the www or html folder. In this example, I’m going to call my example file main.css. So it is actually located at /var/www/public_source/main.css.

Next, I’ll create a file called dev.php in the assets folder where I plan to test my css from. So, this file is located at /var/www/html/css/dev.php. It may contain this content:

1
2
header ('Content-type: text/css');
readfile('/var/www/public_source/main.css');

So, now when I load my website, I can do the following to load my source css:

1
<link rel="stylesheet" type="text/css" href="http://assets.example.com/css/dev.php" />

Of course, when the website is built and deployed, we will be using a different URL.

Next, lets talk about compression of the CSS. I use CSS Tidy to compress my code. The code to invoke this is pretty simple.

1
2
3
4
5
6
7
8
9
10
11
require 'csstidy-1.3/class.csstidy.php';
$cssSource = file_get_contents('/var/www/public_source/main.css');
 
$css = new csstidy();
$css->load_template('highest_compression');
$css->set_cfg('remove_last_;',TRUE);
$css->set_cfg('sort_properties', TRUE);
$css->parse($cssSource);
$cssFinished = $css->print->plain();
 
file_put_contents('/var/www/html/css/main.1.css', $cssFinished);

You’ll notice that I named the file main.1.css. The number will be explained later (its used for caching).

So, the CSS is read, compressed and cleaned, and outputted to a location that the webserver can serve it from. Now, instead of using dev.php as the source, we’ll use main.1.css. Congratulations – a smaller CSS file!

The final thing to do is adjust the caching of this script. Whenever we change the CSS on the development platform, we’re reading it in new using dev.php. However, when this is built and deployed, it should be a built version (or compressed) of the file. This means every code deploy requires this build system. And with release numbers on main software, we’re also going to increment our file name. So our second deployment of the software package (if the CSS source has changed) will now be built using main.2.css – and the link statement will be pointed towards that.

The caching then can make the assumption that this file will never change. The CSS may change but the file is a new name then. And since we can’t just load portions of a file whenever there is a change, even a small change in a non-cached file will make the entire file load. So with this in mind, I cache my CSS files for one year. I put the following in my config:

1
2
3
ExpiresActive On
#1 yr
ExpiresByType text/css A31536000

This means that the file will be cached one year from the first time it is accessed. So, if the source HTML continues to point at the same CSS file (say… main

hCard – should I care?

Saturday, January 23rd, 2010

So lately, I’ve been looking into the semantic tools available on the web. I want to make sure that my online identity is easily searchable and undeniably accurate. Using semantic tools such as XFN, FOAF and hCard may help me.

I can’t help but seeing some of these and thinking ‘flash in the pan’ though. What I really want to see is a big – or a giant – company come through and make use of these. For example, LiveJournal is exporting FOAF information – but who cares? Where can I actually find value out of that information that was previously consumed? If I search ‘Aaron Saray’ on Google, will my friends show up along the sidebar?

At any rate, I did implement a very basic FOAF RDF file on my home page. I am reluctant to do anything further, however. Like I said, I’m not seeing much value as of yet. However, I did want to look at another alternative, hCard.

What is hCard

hCard is just an expansion on the vCard standard. The website says it has a 1:1 representation of the vCard properties. Plus, it goes further by allowing itself to be embedded into web properties. So basically, its a vCard that I show on my website, right? Isn’t this already what my contact page does? (Yes – but the argument is this is a standardized form so that it can be machine readable – I get it I get it).

Who is using hCard

More and more libraries are using hCard. The number one thing that caught my eye was the possible implementation by drupal (see http://groups.drupal.org/node/1898. Yet, I’m seeing many people put out the information to be consumed, but I’m not seeing many groups actually doing the consuming.

How can I use it?

Well besides looking at the specs, you can use the following two libraries in PHP:
phpMicroformats
Microformats Parser

So what did you do?

Ok so after all this complaining, I have to admit – I’m still guilty… I implemented it on my contact page :)

Friend of a Friend: FOAF

Wednesday, January 20th, 2010

So I added my own FOAF link on my home page. The RDF file is here:
http://assets.aaronsaray.com/assets/foaf.rdf

For those who aren’t familiar, Friend of a Friend is a protocol defined to help machines read relationships between entities (persons) on the internet. The relationships are set up in RDF file. (Mine is severely limited – either I have no friends – or am just lazy – you tell me!) For more info, check out http://www.foaf-project.org/.

By far, the best library I’ve found for parsing FOAF files is located here: http://gna.org/projects/phoaf

Protect Your Image from Download

Wednesday, December 16th, 2009

I came across a great idea dealing with protecting image downloads from the site. Now, this is not fool-proof. There are lots of other ways to download the image, but this may stop the casual downloader. Nope, its not disabling the right click or using java. It requires one single transparent gif. Let’s see how.

(more…)

Auto Failover for CDN based Javascript

Monday, November 30th, 2009

Using my javascript error reporter code helps me get a better understanding of what my clients are experiencing when visiting my website. One thing I did notice was the failures from time to time of Google’s CDN based Jquery.

To solve this issue, I decided to keep a local copy as well. For the most part, Google’s version is going to be faster and have a better cache method. However, I’d rather have an uncached version of it loaded into the user’s browser than nothing at all! So, in the very rare case that the user’s browser fails to load the Google javascript, I load a local copy of it.

First Step: Load JQuery From Google

The very first thing I do is to include jQuery from google’s code base using the following tag:

1
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>

This will retrieve the latest version (1.3.2) from Google with the proper compression and cache response I like.

However, this sometimes was failing – well according to my error reporting script. What to do?

Test for a successful load of jQuery

Since the SCRIPT tag does not have an ‘onerror’ standard notifier like our image, the next best thing to do is test for the jQuery object right after the page loads. Since we’re using inline javascript, the first request to the external javascript will block while loading. When it completes, this small snippet will then execute.

I’ll jump ahead one more step though before code.

If no jQuery found, load it dynamically

If the jQuery object is not found, a new script element is created dynamically. The source is pointed to my local version of the script. Finally, it is appended to the head. Hopefully this will load the jquery. If it fails here, well then – the client has some issues!

This is the full inline javascript after the external javascript reference:

1
2
3
4
5
6
if (typeof jQuery == 'undefined') {
	var e = document.createElement('script');
	e.src = '/js/noncdn-jquery-1.3.2.js';
	e.type='text/javascript';
	document.getElementsByTagName("head")[0].appendChild(e);
}

In this case, the path http://mydomain.com/js/noncdn-jquery-1.3.2.js contains my local javascript.

The results?

Before this fix, I saw a failed jQuery load about once a day. I have not seen a single one yet. I have yet to see this error reported. If anyone finds a better way to do this, please let me know!

Trim down your content – it is a MUST

Friday, September 18th, 2009

A while ago, I was reading a usability book – and the author suggested that every time you create your content, remove half of the words. Then remove half of them again. So, by the time you’re done, you really have 1/4th of your content – and it should still make sense.

I didn’t really think this was that useful, until I made my first version of project I was developing called Where Is The Band (the picture on the left). As you can see, the general idea was the same, but it was very busy and verbose. The new version (the picture on the right) shows the exact same interface, but measurably less content.

This is how I did it:

Take out assumptions

Part of the extra wording I did was to explain “what would happen.” The hope is, however, that if a user is taking the time to sign up for your website, they already trust you enough to know that you’ll do those things you’ve promised. So, there is no need for me to spit out all of this information right away. (see: If you have a page, we’ll search for it! – they should trust that this happens already).

Trust Common Sense

Another area I was too verbose was the zip code box search. I realized that most people will know that a band is at a venue. Also, I planned on showing both results – as a combined search – here are venues near by with their associated bands. So, this new combo message worked better.

Elevator Pitch Ax

Elevator pitches in the real world are about 30 seconds max. In the web world, you have 3 seconds. Any longer than that, they move on. I imagined my elevator pitch – the part below the zip code search – as being my 3 main points said in one second each.

Value whitespace

In areas where I didn’t know what to cut, I decided I must have enough whitespace (or in this case, blue space). I then forced my words to work around that space that I had cut out.

Thesaurus.com and Lingo/Slang

Last but not least, check out the thesaurus. Also, from time to time, I used real words that people use – not the proper written words. This helped shorten the content.

The Examples

The left picture is the original design. The right picture is the trimmed version.

  • twitter loader

Follow me on twitter: @aaronsaray

The views on this website are my own and do not reflect the opinions of my employer or clients.
Creative Commons License Home | Open Source | Book | Music | Art | Bio | Resume | Contact
My Baby