Chris Hope's LAMP Blog - The Electric ToolboxChris Hope's LAMP Blog - The Electric Toolbox

Linux Apache MySQL and PHP articles by Chris Hope

This is Chris Hope's blog for Linux, Apache, MySQL and PHP (known as LAMP) and Javascript/jQuery. "The Electric Toolbox" is the name of my company and I started this website several years ago with articles about web programming, Linux and Windows tips and tricks, howtos etc.

I currently post new content every second day; read my posting schedule for more details.

The ten most recent articles can be found below in their entirety. Navigating the sections in the right navigation (under Categories) will bring up all the other posts, and you can also use the search box at the top of the page to find what you might be looking for.

Using an include file for footer links with PHPUsing an include file for footer links with PHP

Posted August 30th, 2010 in PHP

I was asked an interesting question by email over the weekend and thought I'd share my response here. The question was "I wish to include in the footer links to my other developed websites. I don't wish to update the footer on each html page every time I create a new webpage. What would be your advice for implementing something like that using html, js and css".

Client-sided vs server-sided

The question asked about using Javascript as well as HTML and CSS and didn't mention a server-sided programming language at all. While it is possible to write out the footer links using Javascript from a common JS file, I wouldn't recommend it.

Apart from just feeling a little bit of a "hacky" way to do it, there are SEO advantages from having the links actually coded into the HTML of the page; if they're written out in Javascript search engines are unlikely to follow your links and assign weight to them etc.

Making static HTML files dynamic with PHP and Apache

Making the assumption that the files are a bunch of static HTML files, I suggested that if the site is hosted on a server that supports PHP then to make the regular HTML files be parsed as PHP, which I have shown how to do in my "get Apache to parse .html files as PHP" post.

Use include() to include the footer file

Now that the files are being parsed as PHP you can add blocks of PHP code to the HTML files. Nothing needs to be done to them to make this work, and even if there is no PHP in the files they will still be served as they are sending the existing HTML to the web browser.

At the appropriate place in the each HTML file, add the following tag, where 'footer-links.html' is the name of the file that contains the footer links:

<?php include('footer-links.html'); ?>

Then add links to the file, add stlying to it with CSS etc etc.

Conclusion

Ideally you really don't want your site to be a bunch of static HTML files because it makes updating the site structure etc in the future much more difficult, but if that's what you are stuck with then this is an easy enough to implement solution.

It's a bit quick and dirty but it means the links will be served in the HTML itself and maybe you can at the same time think about changing your site over to a more structured system with separation of content and template.

Detect IE6 with jQuery or Conditional CommentsDetect IE6 with jQuery or Conditional Comments

Posted August 18th, 2010 in Javascript

I rarely need to detect whether the user's browser is Internet Explorer version 6 but when working on some stylized drop down boxes using the Stylish Select Box jQuery plugin the customisation I had done wouldn't render in IE6 so I decided to make it so the plugin isn't used for that browser. This post shows a couple of different ways to detect if it's IE6 with jQuery and then regular Javascript using Internet Explorer's conditional comments.

Detect IE6 with jQuery's $.browser

jQuery supports a $.browser object which is deprecated and the jQuery developers suggest it should not be used, but there are no plans to remove it at the present time. It can easily be used to detect IE6 as shown in the following example:

var isIE6 = $.browser.msie && parseFloat($.browser.version) < 7;

I have covered the $.browser object previously here.

Detect IE6 using Conditional Comments

The second method is to use the conditional comment system which is built into Internet Explorer to set a variable as shown in the second example below:

<script type="text/javascript">
var isIE6 = false;
</script>
<!--[if lte IE 6]>
<script type="text/javascript">
isIE6 = true;
</script>
<![endif]-->

The isIE6 variable is first initialized in a chunk of Javascript that is run by all browsers as false, and then change to true if the conditional comment is true. We need to initizlize the variable first so that subsequent calls to if(isIE6) { } do not result in a parse error in browsers other than IE6.

PHP: get keywords from search engine referer urlPHP: get keywords from search engine referer url

Posted August 16th, 2010 in PHP

This post shows how to use PHP to extract the keywords searched on by a user when they found your website using a seach engine. Bing, Google and Yahoo are covered here and you can easily add your own to the PHP code supplied.

PHP functions used

The code example here uses the parse_url function to extract the parts from the referer URL and then the parse_str function to extract the parts of the query string into array variables. I've covered those functions before in an article titled "Extract query string into an associative array with PHP".

The referer URL is stored in the $_SERVER PHP superglobal as $_SERVER['HTTP_REFERER'], but only if it was set by the web browser. I have covered this value in some detail in the tutorial titled "Using the HTTP_REFERER variable with PHP".

Referer URL examples

Here's some example referer URLs from Bing, Google and Yahoo from people reaching this blog.

http://www.bing.com/search?q=javascript+date+to+timestamp&src=IE-SearchBox&FORM=IE8SRC
http://www.google.de/search?q=apache+restart&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:de:official&client=firefox-a
http://us.yhs.search.yahoo.com/avg/search?fr=yhs-avg-chrome&type=yahoo_avg_hs2-tb-web_chrome_us&p=concatenation+in+mysql

You can see from looking at the URLs that Bing and Google store the keyword word as the "q" variable and Yahoo does it with "p".

The code

Here's the PHP code to extract the keywords entered from the above examples:

function search_engine_query_string($url = false) {

    if(!$url) {
        $url = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : false;
    }
    if($url == false) {
        return '';
    }

    $parts = parse_url($url);
    parse_str($parts['query'], $query);

    $search_engines = array(
        'bing' => 'q',
        'google' => 'q',
        'yahoo' => 'p'
    );

    preg_match('/(' . implode('|', array_keys($search_engines)) . ')\./', $parts['host'], $matches);

    return isset($matches[1]) && isset($query[$search_engines[$matches[1]]]) ? $query[$search_engines[$matches[1]]] : '';

}

The way that it works is to either use a URL passed in or $_SERVER['HTTP_REFERER'] if one is not passed. It then extracts the parts from the URL (line 10) and then the breaks the pieces of the query string into values in an associative array (line 11).

A list of search engines is defined from lines 13 to 17 as an associative array containing the main part of the domain (i.e. in www.google.com the 'google' bit) mapped to the variable name in the query string. You can add additional search engines to this array.

Note that the array index (i.e. the 'google' bit) is used to match against the search engine's domain using this index value plus a period/dot. Therefore 'google' would match www.google.com, www.google.co.nz and even notgoogle.com.

The regular expression could be modified to ensure there's a period/dot at the start of the host OR the host starts with the domain, but I'm personally happy to leave it as-is for the moment; you are free of course to modify the code if you prefer to ensure a more exact match.

The regular expression on line 19 matches the search engine name into the $matches array, and line 21 returns the keywords if the search engine domain matched and a keyword variable was found.

Note that parse_str will remove any URL encoding so e.g. "javascript+date+to+timestamp" will be returned as "javascript date to timestamp".

Examples

So here's some examples running the above function using the referer URLs from the beginning of the post:

echo search_engine_query_string('http://www.bing.com/search?q=javascript+date+to+timestamp&src=IE-SearchBox&FORM=IE8SRC');
// echoes "javascript date to timestamp"
echo search_engine_query_string('http://www.google.de/search?q=apache+restart&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:de:official&client=firefox-a');
// echoes "apache restart"
echo search_engine_query_string('http://us.yhs.search.yahoo.com/avg/search?fr=yhs-avg-chrome&type=yahoo_avg_hs2-tb-web_chrome_us&p=concatenation+in+mysql');
// echoes "concatenation in mysql"

Apple Magic Trackpad on Windows (not Boot Camp)Apple Magic Trackpad on Windows (not Boot Camp)

Posted August 14th, 2010 in Offsite Articles, OSX and Windows

I started using an Apple Magic Trackpad yesterday and already far prefer it to a mouse (I'll do a review of it next week once I've used it a bit more). This post has a link to a page which shows how to connect a Magic Trackpad to a Windows machine that's not on Boot Camp and a few observations I made when attempting to connect.

Use an Apple Magic Trackpad on Windows

This article at Digital Inspiration shows how to use a Magic Trackpad with your Windows PC. It has links to the driver files to download from Apple and 7-Zip which you will need to extract the necessary files. You'll obviously also need to be able to connect to bluetooth devices with your Windows PC. In my case I had a Bluetooh dongle which did the trick nicely.

Issues I had and solutions

I had some issues trying to connect the trackpad in the first place but the main issue turned out to be that it was still connected to my Mac, even though it was a floor below where I was and there were a few walls inbetween me and the mac; so you may need to disconnect it from the Mac first.

The other thing I needed to do was keep hitting the on button on the right side; it kept turning itself off after every 5 seconds (or thereabouts) which prevented it from connecting to the Windows PC. This may have been a continuing issue with the Mac being in range and may not affect you.

Usability

I only just connected the trackpad to the computer I am writing this on a few minutes before writing this post, so haven't had much of a chance to play around with it yet, but the following do work:

  • it uses tapping by default for clicking
  • one finger moves the mouse as expected
  • two finger scrolls up and down and left and right as expected
  • to click and drag you have to use the same finger; on a Mac you could e.g. use your thumb to click and then drag with the other finger
  • double finger tap does a right click (same as on a Mac)

On the downside, I have found:

  • no inertial scrolling (but then I didn't actually expect it)
  • sometimes a tap does a click-drag type of thing and you end up selecting all (or some of) the text on a web page or dragging stuff all over the place

I haven't tried any other gestures yet (and don't expect them to work anyway) and will update this post if I find anything else useful or interesting.

Prevent Parallels creating Windows application folders in the DockPrevent Parallels creating Windows application folders in the Dock

Posted August 13th, 2010 in OSX

When Parallels starts a Windows Virtual Machine it creates a folder in the dock containing Windows Applications. I run my Parallels Virtual Machines in windowed mode so prefer these folders not to be created at all. This post shows how to prevent Parallels from creating the Windows Applications folder in the dock on Mac OS X.

With Parallels already running, open up the Virtual Machine and select "Virtual Machine" then "Configure" from the menu. Then click the "Options" button and select "Shared Applications"

The resulting dialog is shown in the screnshot below with the options and shared applications options highlighed with a red box.

parallels virtual machine configuration

Either uncheck "Share Windows applications with Mac OS X" to disable all the sharing options, or just "Show Windows applications folder in Dock". Also optionally uncheck the "Share Mac OS X applications with Windows" if you don't want this sharing done as well.

Note that you can chnage these options while the VM is running; it will automatically remove the Windows Applications folder from the dock for you.

Password protection with Apache but allow from an IP addressPassword protection with Apache but allow from an IP address

Posted August 11th, 2010 in Apache

I have posted how to password protect a directory and remove password protection from a subdirectory with Apache and in this post look at how to have a password for all users except those from a defined IP address or set of IP addresses.

Basic password protection

Refer to the full post about password protection for all the examples and details, but here's a quick look at how to add the appropriate lines to an .htaccess file or a <Directory> or <Location> block within the main Apache configuration:

AuthUserFile /path/to/.htpasswd
AuthName "Restricted Access"
AuthType Basic
require user [username]

Allowing users in from an IP address

If you don't want to prompt users from a particular IP address or group of IP addresses then this can be enabled while still asking for a username and password from everyone else.

This can be useful if you want to allow access from your office or someone else's business location when they have a stactic IP address, or even if you have some automated bot on a server that you don't want to have to code the logic in for passing along the username and password.

To do this, add "satisfy any", "deny from all" and "allow from xxx.xxx.xxx.xxx" lines to the above example as shown below. In the example below, we allow access from 192.168.1.1 to 192.168.1.255, 10.1.1.45 and 172.16.5.106.

AuthUserFile /path/to/.htpasswd
AuthName "Restricted Access"
AuthType Basic
require user [username]
satisfy any
deny from all allow from 192.168.1. allow from 10.1.1.45 allow from 172.16.5.106

The IP addresses can also be done on a single line like so:

AuthUserFile /path/to/.htpasswd
AuthName "Restricted Access"
AuthType Basic
require user [username]
satisfy any
deny from all allow from 192.168.1. 10.1.1.45 172.16.5.106

 

SilverStripe: Escape raw values for a SQL querySilverStripe: Escape raw values for a SQL query

Posted August 9th, 2010 in Quick Tips and SilverStripe

This is just quick little post for self reference to show how to escape values which go into a raw SQL query in SilverStripe; I find myself never being able to remember this and having to always look it up.

Escape a value using convert::raw2sql

When using DB::query, DataObject::get and DataObject::get_one with filters, etc in SilverStripe you may need to include variables which have come from user input. As with all database queries these values need to be escaped to a) prevent SQL injection and b) to ensure there are no quer errors.

In SilverStripe use the following to escape the variable so it is safe to put into the query:

convert::raw2sql($value)

So for example, to put it into a query using DB::query:

DB::query("DELETE FROM Foo WHERE Bar = " . convert::raw2sql($somevalue));

Download/embed fonts with @font-faceDownload/embed fonts with @font-face

Posted August 7th, 2010 in HTML and CSS

I wouldn't normally bother with anything other than the default web fonts but the design for the new Personalised Plates website (still in development) calls for a stylized font which is similar to that used on the plates themselves for headings, lead-in paragraph text and so on. As a result I've been messing around with @font-face this week and present how to do this here, along with a bunch of useful references online.

Font and browser support

There are a number of different font formats which different browsers support so you need to provide the font in multiple formats (see the Font Squirrel section below for how to convert). But then you didn't really expect it to be easy now, did you?

Internet Explorer has supported font embedding with @font-face since IE4. The fonts must be in EOT format = Embedded OpenType.

Firefox supports @font-face since since 3.5, with 3.5 supporting TrueType and OpenType fonts, and 3.6 adding support for WOFF (Web Open Font Format). WOFF is a "strong favorite" for standardization by the W3C and a major plus is that it is already compressed making it by default a smaller download than other font formats (but also refer to the mod_deflate section below).

Chrome supports TrueType and OpenType from 4.0. SVG fonts have been supported in Webkit from 325 so presumably Chrome has always supported @font-face; it doesn't really matter with Chrome anyway because it always updates itself to the current stable major version.

Safari supports TrueType, OpenType and SVG fonts from version 3.1 (525). As mentioned above, SVG fonts have been in Webkit since 325 but I don't know which version of Safari this relates to.

Opera supports TrueType, OpenType fonts from version 10.0 and SVG from 9.0.

iPad/iPhone/iPod support SVG only, apparantly from iOS 3.1. I have the iPhone Simulator running on my Mac (I'll write a post about this next week) and can confirm these work.

How to embed fonts with @font-face

Since the fonts have to be converted anyway, I recommend using Font Squirrel (see below) which generates all the necessary CSS information. But to make this post complete I'll include the CSS information here.

The font being embedded with this example is called KlavikaRegular and the CSS to embed it is like so:

@font-face {
    font-family: 'KlavikaRegular';
    src: url('/path/to/klavika-regular-webfont.eot');
    src: local('KlavikaRegular'),
        url('/path/to/klavika-regular-webfont.woff') format('woff'),
        url('/path/to/klavika-regular-webfont.ttf') format('truetype'),
        url('/path/to/klavika-regular-webfont.svg#webfontiYJyHRas') format('svg');
}

You can then set up a style like e.g.:

h1 {
    font-family: KlavikaRegular;
}

In the @font-face declaration, the font-family refers to the name the font should be referred to in the rest of the style sheet. The src: attributes specify where the fonts should be found.

In order for Internet Explorer to use the fonts correctly, it needs its own src declaration and the secondary src declaration needs a "local" setting so that IE will ignore it. The other browsers will then use the other declarations, using which ever font format is applicable in order of preference; the first matching one is the one that will be used.

With SVG fonts, they also need a #hashtag; again Font Squirrel will generate this all for you. The examples used above were all generated with Font Squirrel.

Licensing Issues

Before embedding any fonts, make sure you are legally allowed to embed them in a web page. Font Suqirrel has some you are free to use and there are also many online resources with freely available fonts that you can use in personal and/or commercial projects.

Converting fonts: Font Squirrel

OK so you only have the font as an OTF or a TTF and need to convert it to all the other formats required. I tried a couple of different online font converters (and read bad things about Microsoft's EOT converter) and found Font Squirrel to be easy to use and, as an added bonus, created all the CSS I needed to embed the font in my web page.

Go to Font Squirrel's @font-face Generator and follow the instructions. This will provide you with a zip file containing everything you need.

Compression with mod_deflate

WOFF is already compressed so ideally make that the font with the highest precedence even though only one browser version currently supports it; others will follow if it is to be the standard. The nice thing with WOFF is it doesn't need to be compressed on the server side which puts less load on the server.

For the others, add some rules like so to your main Apache configuration or .htaccess file to compress them on the fly. SVG compresses down the best so that should have the highest precedence overall. I did experience some issues with SVG fonts on Opera myself, but it may be due to the font itself rather than Opera.

AddType application/x-font-ttf ttf
AddType application/vnd.ms-fontobject eot
Addtype application/x-font-otf otf
AddOutputFilterByType DEFLATE application/x-font-ttf application/vnd.ms-fontobject image/svg+xml application/x-font-otf

If you are using a different browser then I can't help you as I only use Apache myself.

Google's font directory

Google has a font directory and makes it very easy to embed fonts but you are limited to the small range of fonts they supply; if you want to use something else you are out of luck.

Useful references and source articles

Vendor-prefixed CSS Property OverviewVendor-prefixed CSS Property Overview

Posted August 6th, 2010 in HTML and CSS and Offsite Articles

CSS allows for vendor-specific extensions which can start with a dash or an underscore, although in practise they all appear to start with a dash. Although this is declared in the official syntax reference, the W3C does recommend that authors should avoid vendor-specific extensions. Nevertheless, they exist and this post links through to an overview of all the vendor-specific extensions available.

Vendor-prefixed CSS Property Overview

Peter Beverloo posted the Vendor-prefixed CSS Property Overview on his blog and it appears to be regularly updated. It includes the prefixes for Gecko (i.e. Firefox and deritives); WebKit (i.e. Konqueror, Safari and Chrome); Presto (Opera); and Trident (Internet Explorer).

Some of those in the list are available in the actual specifications as well, as a draft or candidate recommendation. In the case of these ones there are links through to the appropriate specification.

View the full list here.

But... CSS vendor prefixes can be considered harmful

Meanwhile, over at Quirksmode, they posted "CSS vendor prefixes considered harmful" which looks into the vendor prefixes in some detail and why they are bad.

From the article:

It’s time to abolish all vendor prefixes. They’ve become solutions for which there is no problem, and they are actively harming web standards.

Vendor prefixes force web developers to make their style sheets much more verbose than is necessary, while also running the risk of accidentally forgetting one set of vendor-prefixed declarations.

Besides, why do we need to use several declarations for obtaining one single effect? Weren’t web standards supposed to prevent that sort of thing?

Read the full post (and comments) for more details.

Track outgoing links with Google Analytics and jQueryTrack outgoing links with Google Analytics and jQuery

Posted August 4th, 2010 in Javascript and Offsite Articles

Neal Grosskopf posted "Tracking Outgoing Links in Google Analytics Using Event Tracking and jQuery" which looks at the correct way to track outgoing links compared with the incorrect way people often post which suggests to track them as pageviews.

The article

In the article, Neal looks at:

  • The Old and Wrong Way
  • The Right and New Way
  • Dissecting pageTracker._trackEvent
  • How the Data Looks in Google Analytics

and then posts a link to the official documentation, which is here. Read Neal's full post here.

My comments

The post uses jQuery but you obviously don't have to use jQuery. If you are not already using jQuery in your project then it may not necessarily be advisable to include jQuery just to use this code; you can modify it to suit the framework you already use, or use traditional onClick="" style event handlers.

And secondly, the post uses the old style non-async tracker as pointed out by the first comment on the page. That comment also shows the code to use to track it using the new async tracker.