Get Website Screenshots Using PHP

I was given a task the other day to go through a client's directory and generate a screenshot of each listing's external website. I wasn't sure if it was possible, but it seemed like a fun challenge, so I went out and did a bit of research. Turns out, it is possible. And, even better, it's pretty simple. Here's what to do:

One of the PHP functions we're going to be using, imagegrabwindow, only works on machines running Windows. My client's server runs Linux, so I set this up to run on my local computer using XAMPP. Unfortunately, if you don't have Windows either on your local machine or your server, this won't work for you.

There are two files that we're going to create, screenshot.php and start_screenshot.php. The first creates and outputs the screenshot image and the second file saves that image to the specified location. Note: Part of the reason I split these up was because I was hoping to run start_screenshot.php from my server and save the files there without having to copy them over. But, due to security restrictions on accessing localhost, I wasn't able to get that to work. I kept getting the following error: "[function.fopen]: failed to open stream: Connection refused". If you know of a way to get around that, please comment below.

Here is the code for screenshot.php:

<?php

//update these variables based on the dimensions of your local IE window:
$crop = true; //set this to false if you don't want image cropped
$crop_top = 97; //in pixels
$crop_right = 26; //pay attention to scrollbars
$crop_bottom = 49; //pay attention to scrollbars
$crop_left = 9;

//grab variables from the query string
$url = trim(strip_tags(urldecode($_GET['url'])));
if (!$url) { die('Error! No URL.'); }
$height = intval(@$_GET['height']);
if (!$height) { $height = 800; }
$width = intval(@$_GET['width']);
if (!$width) { $width = 1000; }
$resized_width = intval($_GET['resized_width']);

//open up a new Internet Explorer window and go to the specified URL
$browser = new COM("InternetExplorer.Application");
$handle = $browser->HWND;
$browser->Visible = true;
$browser->Width = $width;
$browser->Height = $height;
$browser->Navigate($url);

//wait for it to finish loading
while ($browser->Busy) {
	com_message_pump(4000);
}
sleep(5); //give it an extra 5 seconds to load images, videos, etc.

//take snapshot
$im = imagegrabwindow($handle);

//close down Internet Explorer
$browser->Quit();

//check to be sure the image exists
if (!$im) { die('Error! Image could not be created!'); }

//crop the image to get rid of menu, scrollbars, etc.
if ($crop) {
	$new_width = $width - $crop_left - $crop_right;
	if ($new_width < 1) { die('Error! Crop width cannot be less than 1 pixel!'); }
	$new_height = $height - $crop_top - $crop_bottom;
	if ($new_height < 1) { die('Error! Crop height cannot be less than 1 pixel!'); }
	$im2 = imagecreatetruecolor($new_width, $new_height);
	imagecopy($im2, $im, 0, 0, $crop_left, $crop_top, $new_width, $new_height) or die('Error! Could not crop image.');
	imagedestroy($im); //destroy the original
	$image = 'im2';
} else { $image = 'im'; }

//resize the image
if ($resized_width) {
	$new_width = $resized_width;
	$new_height = round(( $new_width / imagesx($$image) ) * imagesy($$image));
	$im3 = imagecreatetruecolor($new_width,$new_height);
	imagecopyresized ($im3, $$image, 0, 0, 0, 0, $new_width, $new_height, imagesx($$image), imagesy($$image)) or die('Error! Could not resize image.');
	imagedestroy($$image); //destroy the original
	$image = 'im3';
}

//display the image, then destroy it
header('Content-Type: image/jpeg');
imagejpeg($$image);
imagedestroy($$image);

?>

I stuck a bunch of comments in there, so hopefully it's fairly self-explanatory. And, here's the second file, start_screenshot.php:

<?php

//set these variables
$url = 'http://twitter.com/inkplant'; //the URL you want to take a screen shot of
$image_filename = 'snapshots/twitter.jpg'; //where you want to save the image (needs to be a jpg in this example)
$width = 1000; //in pixels
$height = 800; //in pixels
$screenshot_url = 'http://localhost/dev/screenshot.php'; //the full address of the file we just created
$resized_width = 300; //if you want to shrink the image, set this to a value in pixels.  otherwise, set it to false

//now we connect to the screenshot script
$full_url = $screenshot_url.'?url='.urlencode($url).'&width='.$width.'&height='.$height.'&resized_width='.$resized_width;
$handle = fopen($full_url, "rb") or die("Error! Couldn't open URL."); //open in binary mode
$output = stream_get_contents($handle);
fclose($handle);
if (!$output) { die('Error! Output was not generated!'); }

//save the returned image
$fp = fopen($image_filename, 'w') or die('Error! Could not open image file!');
fwrite($fp, $output) or die('Error! Could not write image file!');
fclose($fp);

//finally, display your new image
echo '<p><img src="'.$image_filename.'" /><br />'.$image_filename.'</p>';

?>

So, when I opened up http://localhost/dev/start_screenshot.php in my browser, it displayed this lovely image:

@inkplant on Twitter

There are a couple known limitations with this... There's no check to see that the page actually did load. There might be away to do that within the COM class, but I couldn't find it. Also, sometimes the 5 second delay I stuck on there isn't enough for everything on the page to finish loading. You might want to extend it.

Finally, a security warning: According to the documentation on the Navigate method, you can use it to open any URL or file on your computer, so be careful with security issues on this and don't leave it this open on a server or anywhere someone malicious could reach it!


Comments

Loading…

This post was published on May 13th, 2011 by Robert James Reese in the following categories: PHP and Windows. Before using any of the code or other content in this post, you must read and agree to our terms of use.