Automagic WEBP images for osCommerce

You want to optimise your site for Google and when checking Page Speed Insights you’re penalized for not Serving images in next-gen formats.

What this basically means is that you’re not serving images in webp format. The problem with this, is that not all browsers support webp. Every one will support jpg, png, gif, bmp so it seems unfair to be penalized for not using a webp. But that’s Google for you, and if you want to rank in their search queries (who doesn’t?) it makes good sense to follow their guidelines.

So, this is what we did for a clients osCommerce webstore.

Does the Browser Support webp?

At the time of writing, Chrome does, Opera does, Firefox does, Safari does not, nor does Edge. Detecting browsers is not always reliable, but there is a work around. The http_accept header will contain the text “image/webp” if the browser supports webp. So we will use this to determine using the strpos function. We’ll use this to define a constant as true or false. So in the osCommerce file catalog/includes/configure.php add the following to the end (just before the closing ?> tag)

 /* webp support */
	if( strpos ( $_SERVER['HTTP_ACCEPT'], 'image/webp' ) !== false ) {
		define( 'WEBPSUPPORTED', true );
	} else {	
		define( 'WEBPSUPPORTED', false );
	}
	define( 'WEBPIMAGEQUALITY', 65 ); // Sets image quality for WEBP conversion
	define( 'WEBPFORCECREATE', false); // Set to true if you want to force recreation of webpimages. Used if you change quality setting etc.

What this does is check to see if the text ‘image/webp’ is in the header, if so, set the constant WEBPSUPPORTED to true, or else set it to false. We can use this constant throughout the program to determine whether to present a webp or the default file. There are two other constants, WEBPIMAGEQUALITY which determines the quality level of the created image, and WEBPFORCECREATE which is used to create a new webp image even if one already exists. The reason for this is you may want to change the quality level and hence rewrite the already created webps. If so, then set this to true.

Create a webp image.

PHP can actually create PHP images on the fly, so we’re going to make use of this very feature. What we’ll do is when the osCommerce function tep_image is called, if the broswer supports webp we will create a webp image and serve that image instead. However, in order to reduce server loading, if the image has already been created, then don’t recreate it, just change the requested image to the webp image.

In catalog/includes/functions/html_output.php, find function tep_image and add in $src = webpconvert( $src ); so it looks something like.

 // The HTML image wrapper function
  function tep_image($src, $alt = '', $width = '', $height = '', $parameters = '', $responsive = true, $bootstrap_css = '') {
    if ( (empty($src) || ($src == DIR_WS_IMAGES)) && (IMAGE_REQUIRED == 'false') ) {
      return false;
    }
	
	$src = webpconvert( $src ); // Convert to webp (see function for details)

Now add the function webpconvert to the end of the file (before the closing ?> tag)

  function webpconvert( $image ) {
	  
	  $imageInfo = pathinfo( $image );
	  
	  // If the browser doesn't support webp, or it is a webp, or if it can't be found then just return the image
	  if( WEBPSUPPORTED == false || strtolower( $imageInfo['extension'] ) == 'webp' || !file_exists( $image )) return $image;
	  
	  $webpFilename = substr( $image, 0, -1-strlen( $imageInfo['extension'] )) . '.webp';
	  
	  // If the webp image has already been created then exit now
	  // Unless a force create is set.
	  
	  if( file_exists( $webpFilename ) && WEBPFORCECREATE == false ) return $webpFilename;
	  
	  // Create the webp image
	  $resource = imagecreatefromstring( file_get_contents( $image ) );
	  
	  // If the resource can't be created, return with the original file
	  if( !$resource ) {
		  return $image;
	  }
	  
	  $webpimage = imagewebp( $resource, $webpFilename, WEBPIMAGEQUALITY );
	  imagedestroy( $resource );
	  
	  // Make sure that if the image wasn't created then return the original.
	  if( $webpimage ) {
		  return $webpimage;
	  }
	  else {		  
		  return $image;
	  }
  }

Discovered Issues

The code works a treat and converts the jpg and png files admirably on the fly. One issue is that the program execution moves on before the image has been converted and saved. This means that on first page load the webp image is asked for but is not found. A refresh or another visit to that page results in the image now displaying correctly.

Another, more serious error is that we occasionally got a fatal error:

PHP Fatal error: Paletter image not supported by webp

Which turned out to be happening only with one png image. The image file would be created and then the fatal error would stop program execution. So a webp file is in existence but is zero bytes long. As a result the program would no longer crash but the image would not be found either. We suspect this is some issue with that particular png image.

A bit of an oddball is that we discovered that Edge does in fact display webp images, but the http header suggests it does not. No real workaround for this at this time.

Other Uses

In some modules we don’t use the tep_image wrapper and instead either display the image directly, or use it in css as a background image. To be able to use webp we can just call the function directly. For example:

<div style="
  border:10px solid #ccc; 
  border-radius:25px; 
  background:url(<?php echo webpconvert( DIR_WS_IMAGES.'image.jpg'); ?>); 
  background-size:contain; 
  background-repeat:no-repeat; 
  font-size:1.5em; text-align:center;">

Contents

</div>

Next we’ll be doing something for WordPress. Watch this space,

Leave a Reply

Your email address will not be published. Required fields are marked *