Hello, and welcome to the online home of Robert Price - Software Architect for web and mobile at multinational media company Bauer
(but don't let that put you off).
Here you'll find Rob's blog, focusing mainly on
web and mobile technology, but anything can (and does) get posted here.
Latest Blog Entries
I was looking at adding zebra stripes to some data to improve readability to a page of data generated from PHP using the Twig templating system.
Twig provides a method called cycle that can be used to alternate through a list of values, so this is was the obvious candidate.
cycle takes 2 parameters, the first is an array of values to iterate through, the second is an integer with the cycle value.
This means all I have to do is to pass in an array with the css class names I'm using for my striping, and the position of the loop I'm iterating through to display my data. For example...
{% if users|length > 0 %}
<ul>
{% for user in users %}
<li class="{{ cycle(['even','odd'],loop.index) }}">{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}
I have a list of users that I'm iterating through. For each user I choose wether to display use either the odd or even class using the cycle function. I have to pass in loop.index as the cycle value to count as this increments each time the loop is iterated through.
This gave me an output something like this...
<ul>
<li class="even">Rob</li>
<li class="odd">John</li>
<li class="even">Paul</li>
<li class="odd">George</li>
<li class="even">Ringo</li>
</ul>
Entered: 2012-01-09 20:50:09
Modified: 2012-01-09 20:51:21
"We need all our URL's to have a trailing slash", was a request I had in recently.
This sounds easy enough, a quick rewrite rule will do the trick, and that is what I added.
RewriteRule ^(.*[^/])$ /$1/ [R=301,L]
I look at the start of the URL, grab every character to the end of the URL, making sure the last one isn't a slash already, then rewrite that with slashes around it, issuing a 301 redirect and informing Apache not to process any more rules.
This works great for pages already on the server, for example /guestbook becomes /guestbook/. However, what if we wanted to load /logo.gif, this would rewrite to /logo.gif/ and cause a error.
OK, so we need not to match every character in the URL, but only if it doesn't have a dot in there. The site in question was a Zend Framework application, and this caused it's own problems.
Zend Framework applications have their own rewriting rules...
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]
This checks if the requested resource is actually a real object Apache can serve, if not it passes it over to the Zend Framework to handle internally via the index.php script.
So what happens if /guestbook is actually a Zend Framework application?
Well, the URL would be rewritten to /index.php/.
Why? Well the first rewrite we added a slash, this caused the page to re-requested, this then passed to the Zend Framework rewrites, this saw it needed to rewrite to index.php, this caused the page to be re-requested again internally, which added a slash to the end, and redirected again. Finally this request was /index.php/ which doesn't exist and failed.
Wow, that was a mouthful, let's look at that as a sequence diagram.
What we need is to only rewrite the requested URL if it doesn't have a trailing slash and if it doesn't have a dot in the request and if it isn't an internal Apache redirect. We also only want to rewrite if the request is a GET, POSTs (DELETE's and PUT's too) don't support rewriting in the browser.
This indicates a series a conditions that need to be met, so tells me we should be using Apache's RewriteCond directive.
Let's check for a GET request first...
RewriteCond %{REQUEST_METHOD} GET [NC]
The %{REQUEST_METHOD} variable in a rewrite rule tells us the HTTP method used to make the request, so we just need to check if that is GET. The [NC] makes the check case insensitive so matches GET, get, Get, etc...
Next we need to see if the request already has a trailing slash.
RewriteCond %{REQUEST_URI} !/$
This checks the requested URI and sees if the last character isn't a slash.
Now we need to check if there are any dots in the request.
RewriteCond %{REQUEST_URI} !\.
This just checks that there isn't a dot in the requested URI. As dot normally matches any character, we need to escape this with a clash first.
If all these conditions match, we can issue our RewriteRule.
RewriteRule ^.*$ %{REQUEST_URI}/ [R=301,L]
This takes the requested URI, adds a slash and issues a 301 status code to force the browser to re-request the page and change the URL shown in the address bar. We add the L to tell Apache not to process any more rules.
Let's put this all together, and insert it above the normal Zend Framework rewrites, but after RewriteEngine On.
RewriteCond %{REQUEST_METHOD} GET [NC]
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{REQUEST_URI} !\.
RewriteRule ^.*$ %{REQUEST_URI}/ [R=301,L]
Let's request /guestbook again, and see what happens.
Entered: 2011-11-30 18:45:08
Modified: 2011-11-30 18:46:27
A few days ago I wrote about a problem I had with some javascript ad code defering execution. Well another problem arose today with the code, and I thought I'd share the solution.
Some pages on the site I'm developing on are served over https, others are served over http. They share a common template so the same ad code is served across all pages. At the moment they serve purely over http, and this is great most of the time, however when the page is served over https a security alert is shown asking the user if they want to show unsecure content. Most users would say no in this situation so our ads won't be shown.
What we need is a way for ads to be shown if a user is on a secure or normal connection.
Thankfully our ad provider allows us to request the same ad in either http or https by just changing the protocol, e.g. http://ad... or https://ad... .
The ad is written out using a document.write statement and is meant to be executed as the page is rendering.
We need to detect how the current page is being served, so we know what protocol to request the ad in.
This is easy in JavaScript, we can just query the value document.location.protocol. This returns either 'http:' or 'https:'. Note the trailing colon...
We can use the value document.location.protocol directly, but just incase another protocol has been used, we can default everything to http if https hasn't been used. The following code will help here...
var protocol = 'https:' == document.location.protocol ? 'https' : 'http';
Here we are seeing if document.location.protocol is the value 'https:', if it is set the value of protocol to 'https', else set it to 'http'.
Let's look at the original ad code...
<script type="text/javascript">
<!--
if (window.adgroupid == undefined) {
window.adgroupid = Math.round(Math.random() * 1000);
}
document.write('>scr'+'ipt language="javascript1.1" src="http://adserver.adtech.de/addyn|3.0|311.0|3328078|0|225|ADTECH;cookie=info;alias=FindClassicCars+Maserati+7+leaderboard;loc=100;target=_blank;key=key1+key2+key3+key4;grp='+window.adgroupid+';misc='+new Date().getTime()+'"></scri'+'pt>');
//-->
</script>
We can take our earlier ternary expression to embed the protocol directly into the ad code like this.
<script type="text/javascript">
<!--
if (window.adgroupid == undefined) {
window.adgroupid = Math.round(Math.random() * 1000);
}
document.write('>scr'+'ipt language="javascript1.1" src="'+( 'https:'==document.location.protocol?'https':'http') +'://adserver.adtech.de/addyn|3.0|311.0|3328078|0|225|ADTECH;cookie=info;alias=FindClassicCars+Maserati+7+leaderboard;loc=100;target=_blank;key=key1+key2+key3+key4;grp='+window.adgroupid+';misc='+new Date().getTime()+'"></scri'+'pt>');
//-->
</script>
The ad code will now serve ads to our customers if they are on either a normal or secure page, and our ad team is happy again.
Entered: 2011-11-09 18:26:57
Modified: 2011-11-09 18:31:38
I came across an interesting problem trying to debug a website that had issues with some ad code earlier. The site was working fine until ad code had been added, then in Internet Explorer it was only showing the ad instead of the page. Firefox, Safari and Chrome were fine, so it suggested a problem with the ad code.
The ad code in question was pretty common, the sort that inserts a script tag via a document.write.
<script language="javascript" defer="defer" async >
<!--
if (window.adgroupid == undefined) {
window.adgroupid = Math.round(Math.random() * 1000);
}
document.write('>scr'+'ipt language="javascript1.1" src="http://adserver.adtech.de/addyn|3.0|311.0|3328078|0|225|ADTECH;cookie=info;alias=FindClassicCars+Maserati+7+leaderboard;loc=100;target=_blank;key=key1+key2+key3+key4;grp='+window.adgroupid+';misc='+new Date().getTime()+'"></scri'+'pt>');
//-->
</script>
The problem turned out to be with the attribute defer in the script tag.
Defer gives the browser a clue that a piece of JavaScript can be run later, rather than as soon as the browser sees it. This can be used to speed up the rendering of a site. However, Internet Explorer runs differently to other browsers. As the script in question was inline, all the other browsers ran it immediately, whereas Internet Explorer didn't. On Internet Explorer the code was run once the page DOM had been created, so writing out the fresh tags after the document was closed. This caused the ads to show on what looked like a new page on IE's below version 9, and on IE 9 the ads appeared at the bottom of the page.
The fix is to simply remove the defer attribute and change the the opening script tag to the following, leaving the rest of the ad tag in place.
<script type="text/javascript">
You may have noticed I've ignored the async attribute that was in the original script tag. That's an interesting new attribute in HTML5, but alas a topic for another time.
Entered: 2011-11-05 00:17:08
Bookmarks from del.icio.us
Entered: 2011-09-25 00:15:03
Bookmarks from del.icio.us
Entered: 2011-09-22 00:15:04
Bookmarks from del.icio.us
Entered: 2011-09-21 00:15:08
>> Continue reading blog entries...