The WebP Mime Type

Information about the WebP content type, and how we might handle webp images in PHP.

20373 views
d

By. Jacob

Edited: 2021-03-18 07:21

Mime Type of webp images.

The content-type (aka. Mime Type) used for WebP images is image/webp, and the standard file extension is .webp.

WebP is a modern image format that offers superior compression to png and jpg, which helps to more quickly load web pages.

The webp format is supported by most modern browsers, and recently Apple's Safari browser also started supporting webp, this happened with the release of iOS 14 on September 16, 2020.

A typical header response for a webp file may look like this:

HTTP/1.1 200 OK
content-type: image/webp
content-length: 22454

To deliver a image/webp content-type from PHP:

header('content-type: image/webp');
echo $image_data;
exit();

Delivering alternative formats for clients

Older browsers do not support webp, and Apple only started supporting it in iOS 14. Additionally, some social media websites might also not support webp.

Facebook and Twitter both do support webp, but LinkedIn does not yet support it. When a link is shared on these sites an image snippet is usually shown along with the link — but the image is only displayed if the site supports the format. This is just something to keep in mind if you plan on switching.

We can sometimes solve these problems by delivering an alternative format to clients that do not understand the webp format; this can be done either by converting the images, or using the HTML picture element.

Note. You can use Beamtic's file handler class to do this, as it will automatically convert, and redirect .webp images to .jpg. It will even redirect to .avif for clients that supports it.

Using the picture element

The picture element allows us to include multiple images, and have the client automatically pick whichever is supported.

In practice, this will look like:

<picture>
  <source srcset="/path/to/file/some-file-name.webp" type="image/webp">
  <source srcset="/path/to/file/some-file-name.jpg" type="image/jpeg"> 
  <img src="/path/to/file/some-file-name.jpg" alt="If your browser does not support the picture element.">
</picture>

The image contained in the img element will be displayed if the picture element is not supported.

Converting webp to jpg

If a client supports the webp format, the accept header will contain image/webp; to check for the string we may use strpos (or str_contains in PHP8):

if (false == strpos($_SERVER['HTTP_ACCEPT'], 'image/webp')) {
  echo '<b>image/webp</b> is not supported by your client!';
  exit();
}

Of course, this is not going to be enough to deliver an alternative format; to do that we will also need to convert the image.

Note. Converting images can be done with the GD library, which you may need to install manually since it does not come with PHP.

To also convert the image, we can use the below code:

$img = imagecreatefromwebp('/path/to/file/some-file-name.webp');

// Convert the file to jpg with 80% quality
imagejpeg($img, null, 80);
imagedestroy($img);
exit();

The above would output the file directly to the client, on the same requested URL.

This is bad for the user experience, since the file will have incorrect file extension. It works because the file type is determined by the mime type rather than the file extension in the URL — it just tends to confuse users.

A better solution is to save the image, and then redirect to the saved (converted) version.

If we instead want to save it, we should change the second parameter of the imagejpeg function:

imagejpeg($img, '/path/to/file/some-file-name.jpg', 80);

Then, if the client does not support webp, we may redirect the client to the new file:

if (false == strpos($_SERVER['HTTP_ACCEPT'], 'image/webp')) {
  header('Location: https://example.com/images/some-file-name.jpg', false, 307);
}

Regardless of the method you use, there is no guarantee it will work with all services. Browser support tends to be good for both methods, but a "snippet crawler" might not follow a redirect, as seems to be the case with LinkedIn.

Why use a 307 redirect?

When an image is redirected, a client should automatically request the alternative resource.

A 307 redirect is temporary, which I think makes it a good candidate for delivering alternative resources. You can remove the redirect once there is more broad support for webp. Presumably web services and browsers that still does not support webp, will, at some point, be updated, and our redirect will no longer be needed.

Unfortunately, some services have incomplete support for the HTTP protocol, and they will simply not follow a redirect. As of 2021, an example of this is LinkedIn's "preview crawler". LinkedIn does not support webp, and it also refuses to accept jpeg images with .webp extension. In fact, it appears to flat out not request .webp files, so a redirect also will not work.

These inconsistencies makes it very difficult to support services that does not accept a webp file.

What is the best solution

A redirect is the best solution, because you avoid confusing users by delivering images with the wrong file extension.

Delete unneeded files

Remember to delete the .jpg version of the files once they are no longer needed, to do this we may use a command from terminal. Before running the below command, try running it without -delete to get a list of found files:

find [/path/to/directory] -type f -iname '*.jpg' -or -iname '*.jpeg' -delete

Links

  1. Downloading and Installing WebP - developers.google.com

Tell us what you think:

  1. In this Tutorial, it is shown how to redirect all HTTP requests to a index.php file using htaccess or Apache configuration files.
  2. How to create a router in PHP to handle different request types, paths, and request parameters.
  3. Tutorial on how to use proxy servers with cURL and PHP
  4. When using file_get_contents to perform HTTP requests, the server response headers is stored in a reserved variable after each successful request; we can iterate over this when we need to access individual response headers.
  5. How to effectively use variables within strings to insert bits of data where needed.

More in: PHP Tutorials