• Feb
  • 04

PHP Speedy updated - now works with Joomla and Drupal

I have made some more improvements to PHP Speedy - many thanks to everyone who gave me feedback. The improvements are:

  • Added in compress method for direct content compression
  • Made the gzipping functions more robust
  • Added in check for query string in file paths
  • Changed name of view class to avoid conflicts

Due to popular demand I have also tested it with Drupal and Joomla, and have instructions on how to get it working with both.

Drupal

  • Edit index.php in the root Drupal folder
  • Include the PHP Speedy code at the top of the page as normal
  • At the bottom of the page change print theme('page', $return); to
    print $compressor->compress(theme('page', $return));

I'm not a Drupal user so have only tested on a basic installation - please let me know if this doesn't work for you (preferably with a solution!)

Joomla

  • Again, edit index.php in the root Joomla folder
  • Include the PHP Speedy code AFTER the first two includes made by Joomla. So it would look something like this:
    CODE:
    require( 'globals.php' );
    require_once( 'configuration.php' );
    require('/home/your_site/public_html/php_speedy/php_speedy.php');

  • At the very bottom of the page add $compressor->finish();

Again, I must add the disclaimer that I've only tested this with a basic installation so any problems please let me know.

You can download the lastest version of PHP Speedy at the dedicated page: PHP Speedy

Don't forget to subscribe to my feed to stay up-to-date.

Posted by admin in php
30 comments
 
  • Feb
  • 01

Speeding up your website just became easier

UPDATE: New version available: 0.4.6

New to aciddrop.com? Go directly to the PHP Speedy page for a beginners' guide

PHP Speedy

Introducing... PHP Speedy!

Following all the feedback on the site speed boost script, I have fixed all the bugs, added the features that were requested and come up with a name. It was confusing calling it alternately "site speed boost script", "compressor", "aciddrop compress" etc, so I decided to come up with a new moniker. And then waste a few hours designing a logo, of course ;-) (and it's supposed to be flames, not a sea creature).

So, PHP Speedy now boasts:

  • An installer. Lots of people were having problems with the paths, so we now have an installer that*should* take care of everything very easily. If you need to change anything you can either just re-run the installer, or change the config.php file directly.
  • Full support for relative image paths in your CSS, in multiple CSS files. Image paths in CSS are now converted to absolute paths, so you no longer have to worry about where to cache the CSS.
  • Added support for different rel types. (rel="alternative" and rel="stylesheet" are cached separately)
  • Added support for conditional comments in the HEAD tags (this also fixed the problem of commented out stylesheets)

There are still some requirements:

  • You must specify the type when you include your CSS or JavaScript i.e type=text/css
  • Your site can't use ob_end_clean(); or anything that retrieves the buffer in its code. This rules out Joomla, for example.
  • You need to put the CSS and JS in the between the <head> and </head> parts of your page.
  • If your JavaScript dynamically loads other JavaScripts they won't be cached. You should link to each individual script in your <head> tags.

In order to install PHP Speedy you should:

  • Download and unzip the PHP Speedy package into its own directory
  • Point your browser to the PHP Speedy directory
  • Follow the installation instructions

For those of you who are upgrading, just create a new directory for PHP Speedy and install it there. At the end of the install you will be given the new code to include the PHP Speedy file.

Please let me know how you get on, and report and bugs or problems via the comment form.

Download

You can download PHP Speedy from this link: PHP Speedy 0.4.6 download

Tests and examples

Check out the new PHP Speedy dedicated page

Stay up-to-date

I have some more killer features planned for PHP Speedy, and also a Wordpress plugin version, so make sure you subscribe to my RSS feed to stay up-to-date.

Posted by admin in php
28 comments
 
  • Jan
  • 23

Site speed boost script updated

Version 0.4 is now available. It now features:

  • An installer.Lots of people were having problems with the paths, so we now have an installer that*should* take care of everything very easily. If you need to change anything you can either just re-run the installer, or change the config.php file directly.
  • Full support for relative image paths in your CSS, in multiple CSS files. Image paths in CSS are now converted to absolute paths, so you no longer have to worry about where to cache the CSS.
  • Added support for different rel types. (rel=”alternative” and rel=”stylesheet” are cached separately)
  • Added support for conditional comments in the HEAD tags (this also fixed the problem of commented out stylesheets)

It's available from this page: PHP Speedy

-----------------------------------

Version 0.3 is now available.

  • Added check for gzip compression compatibilty.
  • Added check for external javascript files
  • Fixed bug in head grab function

It's available for download here: aciddrop website speedup v0.3

You can see the new demo online here:

Many thanks to those who contributed with bugs and fixes.

-----------------------------------

Version 0.2 Info

Following feedback on the compression class (thanks to all who commented), version 0.2 is now available.

Changes include:

  • Added support for different CSS media types
  • Fixed bug in relative file paths.
  • Improved file cleanup function
  • Changed file versioning to by date instead of by file size
  • Added check for trailing slash on cachedir

You can see the new demo online here:

In testing this new version I found a couple of gotchas:

  • Don't use it at the same time as my Smarty output class that joins the CSS and Javascript. Apache will get confused.
  • Don't comment out any stylesheets in your HTML if they're not in use. The class can't recognise that (yet!).

Also, for those wondering if it works with Wordpress, I changed the code of this Wordpress theme to use the new class.

Posted by admin in php, tutorials
49 comments
 
  • Jan
  • 21

Improve website load time by 500% with 3 lines of code

Major New Update - PHP SPEEDY: latest version available here

PHP Speedy
----------------

There are 4 relatively easy ways by which you can speed up the time it takes a browser to download a page:

  • Make fewer HTTP requests
  • Add a far-future expires header
  • Gzip your page's components
  • Minify your JavaScript, CSS and HTML

Following on from my post on joining CSS and JavaScript files, I have written a PHP script which will automatically do all of the above. All you have to do is call the following at the top of your page:

The code

PHP:
require_once('class.compressor.php'); //Include the class. The full path may be required
$compressor = new compressor('css,javascript,page');

And the following at the bottom of the page:

PHP:
$compressor->finish();

The Demo

That's it! Before I go into the details, the impatient amongst you can check out the test pages here:

The class can be downloaded here: site speed boost class download

Requirements

  • A server running at least PHP4. For JavaScript minification to work as well, PHP5+ is required.
  • You should set the folder where you are running the class from as writable

Setting basic options

Options can be set with a comma separated string as follows:

PHP:
$compressor = new compressor('css,javascript,page');

The string can contain 'css', 'javascript' and 'page' depending on which elements you would like to be compressed. Any element contained in the string will be gzip encoded and minified.

Setting advanced options

Alternatively, an array can be passed to the class constructor with an advanced set of options. This array would set all the compression options to on:

PHP:
$compressor = new compressor(array("javascript"=>array("cachedir"=>'/minify',
"gzip"=>true,
"minify"=>true,
),
"css"=>array("cachedir"=>'/wp-content',
"gzip"=>true,
"minify"=>true,
),
"page"=>array("gzip"=>true,
"minify"=>true
)
));

You can change this array to add or remove all the available options.

Note that "cachedir" should not include a trailing slash. If your CSS files contain relative links for background images, you should set the CSS cachedir to the same directory the standard CSS files are stored in.

Speed gains

On my test page the load time with the compressor turned on was generally below second, and without the compressor between 3-5 seconds. The Yahoo Yslow rating went from F(45) to A(97).

Test page with Firebug, before compression

Firebug before compression

Test page with Firebug, after compression

Firebug before compression

Test page with Yslow, before compression

Firebug before compression

Test page with Yslow, after compression

Firebug before compression

Download

Please see the updated page

Credits

The JavaScript minification uses jsmin-php.

Subscribe

If you liked this tutorial, please subscribe to my RSS feed for more of the same.

Posted by admin in php, tutorials
comments closed
 
  • Jan
  • 03

Automatically join Javascript and CSS into a single file

Update: A script is now available to do this, and much more, here: site speed boost script. This script doesn't rely on Smarty.

One of the keys to getting your pages to load quicker is to make fewer HTTP requests. So, for example, if you have 6 javascript files it would be much quicker for you to join all the JavaScript together into one file and serve that instead. However, doing this manually is a pain. Even using a tool to join them together can be a pain. Far easier would be to set up a PHP script to automatically do it for you.

Example

This plugin can automatically turn this:

HTML:
<script src="/app/resources/js/scriptaculous-js-1.8.0/lib/prototype.js" type="text/javascript"></script>
<script src="/app/resources/js/scriptaculous-js-1.8.0/src/builder.js" type="text/javascript"></script>
<script src="/app/resources/js/scriptaculous-js-1.8.0/src/effects.js" type="text/javascript"></script>
<script src="/app/resources/js/scriptaculous-js-1.8.0/src/dragdrop.js" type="text/javascript"></script>
<script src="/app/resources/js/fastinit/fastinit.js" type="text/javascript"></script>
<script src="/app/resources/js/controllers/controller.sitewide.popup.js" type="text/javascript"></script>
<script src="/app/resources/js/beyond_the_dom/beyond_the_dom.js" type="text/javascript"></script>
<script src="/app/resources/js/newsticker/newsticker.js" type="text/javascript"></script>
<script src="/app/resources/js/image_swapper/image_swapper.js" type="text/javascript"></script>
<script src="/app/resources/js/NiftyCube/niftycube.js" type="text/javascript"></script>
<script src="/app/resources/js/validation/validation.js" type="text/javascript"></script>
<script src="/app/resources/js/flash_detect/flash_detect.js" type="text/javascript"></script>
<script src="/app/resources/js/swfobject/swfobject.js" type="text/javascript"></script>

into this:

HTML:
<script type="text/javascript" src="/app/resources/cache/03e8cd4518c686feb8e18fa1eb329abb.js"></script>

Smarty

This script is an output filter for Smarty, a template engine for PHP. If you don't already use Smarty, the script can be adapted and used with PHP's output buffer functions. If you do use Smarty, setting this up with be a breeze.

Installing the Plugins

You should call

PHP:
$smarty->load_filter('output','join_javascript');
$smarty->load_filter('output','join_css');

from within your application. Then just drop the plugin files into your Smarty plugins directory. Make sure you specify a "cachedir" in the plugins. This is the directory where the joined files will be stored. It should be writeable by the server.

Joining Javascript

Your JavaScript links should contain src and type tags. For example:

HTML:
<script src="/wp-content/themes/leon/libs/scriptaculous-js-1.8.0/lib/prototype.js" type="text/javascript"></script>
<script src="/wp-content/themes/leon/libs/nifty_corners/nifty.js" type="text/javascript"></script>

This is the only requirement for the HTML of your page.

The script will take the JS within the files, join it together, and create a new file. The new file will be saved in the directory you specify, and a new link to it created.

Joining CSS

Your JavaScript links should contain href and type tags. For example:

HTML:
<link href="/wp-content/themes/leon/libs/nifty_corners/niftyCorners.css" type="text/css" rel="stylesheet" />

Again, the script will automatically join together all files with the text/css type tag.

Note that when you make a change to your original CSS or JavaScript files, you will have to delete the cached file.

Download

You can download the plugin files here: http://aciddrop.com/aciddrop/aciddrop_output_filters.zip

Examples

I use this technique on a number of sites, including this one. Check out the source of pitch-invasion.com, simplifydiy.com and purrl.net for examples.

Posted by admin in php, tutorials
11 comments
 
  • Dec
  • 17

Quick, easy and free nearest store postcode/ZIP finder

This tutorial will describe step-by-step how to create a store locator for your website. It works for post codes in any country, and if you're UK based that means you won't have to pay hundreds to the Post Office for the data.

If you want to just straight to the demo it's online here: Easy Store Finder Demo. To see a live example go to http://www.pitch-invasion.com and enter a UK postcode (or address) into the "Your nearest league" box in the right bar, or check out this search for a plumber in central London from simplifydiy.com

Step 1 – Preparing the data

You will need to have the data for your stores in a database. For each store, you will have to know the postcode. This should be stored in a "postcode" field. You should also create fields for "lat" and "lng". Note that the longitude is stored as "lng" as "long" is a reserved word in MySQL. Optionally, you can include a field for the domain of the address. This allows for easy lookups for multiple countries - as you can see below we have addresses from around the world.

Here is an example table, in MySQL format.

MySQL:
CREATE DATABASE `postcode_finder` ;

CREATE TABLE IF NOT EXISTS `store` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(75) NOT NULL DEFAULT '',
`address` TEXT NOT NULL,
`postcode` VARCHAR(10) NOT NULL DEFAULT '',
`lat` DOUBLE NOT NULL DEFAULT '0',
`lng` DOUBLE NOT NULL DEFAULT '0',
`domain` VARCHAR(10) NOT NULL DEFAULT '',
PRIMARY KEY  (`id`)
) ENGINE=MyISAM

INSERT INTO `store` (`name` , `address` , `postcode`, `domain`)
VALUES (
'Waterloo Station', 'Lambeth, London', 'SE1', 'co.uk'
), (
'Gatwick Airport ', 'South Terminal, Gatwick', 'RH6', 'co.uk'
), (
'Edinburgh Waverley Railway Station ', 'Network Rail, Room 255, North Block, Edinburgh', 'EH1 1BB', 'co.uk'
), (
'Beverly Hills', 'California', '90210', 'com'
), (
'Penn Station ', '17 W 32nd St New York', '10001', 'com'
), (
'Sagrada Familia', 'Barcelona', '08013', 'es'
), (
'FC Bayern Munchen', 'Sabener Str. 51, Munchen, Germany ', '81547', 'de'
)

Step 2 – Inserting the latitudes and longitudes

For each of the stores in your database you need to know the latitude and longitude. You can find this out from Google Maps very easily. They have a Geocoding service which will return the latitude and longitude for any address. So all we need to do is loop through our database and update each store with the lat and long.

Note that the API key below (the part after key=) is the key for aciddrop.com. You should get your own key here: http://code.google.com/apis/maps/signup.html

PHP:
/**
* Update lat lngs
*
*/

function update_lat_lngs() {

//Get the list of stores
$query = "SELECT * FROM store";
$stores = $this->db->executeQuery($query);
$stores = $stores['result'];

//Run through stores and get lat / lng
foreach($stores AS $store) {

$latlng = $this->get_lat_long($store['postcode'],$store['domain']);

//Update store with its lat lng
$this->db->quick_update("store",
array('lat','lng'),
array($latlng['lat'],$latlng['lng']),
array('id'=>$store['id'])
);

}

}

/**
* Returns a lat / long of a given postcode
*
*/

function get_lat_long($postcode,$domain=null) {

if(!$domain) {
$domain = "co.uk";
}

$url = "http://maps.google." . $domain . "/maps/geo?q=" . urlencode($postcode) . "&output=json&key=ABQIAAAAWjc0ZH2RENLxziofASg9ABQH987j_SlqISv1l93HS7ksPkvN9xRAXjKLSj-Yj2Xw7I6gP3RHQb4UQj";

$json = $this->curl->get_page(array("url"=>$url));

$store_data = json_decode(str_replace(""","\"",htmlentities($json))); //Take care of accents

$lng = $store_data->Placemark[0]->Point->coordinates[0];
$lat = $store_data->Placemark[0]->Point->coordinates[1];

//Return
if($lng && $lat) {

return array('lat'=>$lat,
'lng'=>$lng
);

} else {

return false;

}

}

The first function gets the list of stores form the database, and stores it in the array $stores. For each store postcode (and domain), we then run the function get_lat_long. This queries the Google maps geocoder, which returns a json string. This string is then decoded, and the lat and long taken from the resulting object. Finally, the stores table is updated with the lat and long for each store. Note that this uses curl and json_decode, which need to be installed on your server. There are alternatives, however.

The time that this takes will vary depending on how many stores you have. If you have hundreds the script will take a while to process. Also, the Google API restricts you to 15,000 queries a day so if you have more stores than this you may have to run it a few times on different days. Note that this will also be a problem if you have more than 15,000 lookups a day from your users.

Step 3 – Querying the stores database

Now that we have all our data set all we have to do is query our stores database with the latitude and longitude of the postcode that is our starting point. The query does the maths directly in MySQL so it's very quick – even for thousands of records. It uses the Haversine formula to take into account the curvature of the earth, so it's pretty accurate (certainly more so than other formulas which use Pythagoras).

Note that we also use a checkPostcode() function, which is UK specific. If the postcode entered is a UK postcode it will format it correctly. Thanks to John Gardner at http://www.braemoor.co.uk/software/postcodes.shtml for the code.

PHP:
/**
* Get a list of our stores, sorted by distance to this postcode
*
*/

function get_stores_list($postcode) {

//If it's a UK postcode then format correctly
$postcode = $this->checkPostcode($postcode);

$latlng = $this->get_lat_long($postcode);

if(!$latlng) { //Unrecognised postcode
return false;
}

$latitude = $latlng['lat'];
$longitude = $latlng['lng'];
//    print_r($latlng);

$query = "SELECT *,
(((acos(sin(("
.$latitude."*pi()/180)) * sin((`lat`*pi()/180))
+cos(("
.$latitude."*pi()/180)) * cos((`lat`*pi()/180))
* cos((("
.$longitude."- `lng`)*pi()/180))))*180/pi())*60*1.1515)
as distance
FROM `store`
ORDER BY distance ASC
"
;
$stores = $this->db->executeQuery($query);
$stores = $stores['result'];

return $stores;

}

This will return a list of all the stores, sorted by distance. You can now display as you see fit. If you wish to limit the amount of stores returned, this can be done directly in the query.

So there you have it – a completely free store finder that will work for any international postcode.

The Demo

No tutorial is complete without a demo. You can see it online here: Easy Store Finder Demo. The source code for the demo is available here: Easy Store Finder Demo Source

References

Many thanks to the following sites for useful information in putting this tutorial together:
http://ben.milleare.com/2006/09/03/calculating-distance-with-latitude-and-longitude/
http://www.zcentric.com/blog/2007/03/calculate_distance_in_mysql_wi.html
http://www.petefreitag.com/item/622.cfm
http://www.douglaskarr.com/2007/09/15/calculate-distance/
http://www.pjenkins.co.uk/blog/index.php/2007/04/04/uk_post_code_distance_calculation/

Posted by admin in mysql, php, tutorials
17 comments