Shane Chism

Facebook Picture Overlay Script


Social media has provided a new and powerful way for grassroots movements to gain viral momentum, allowing the average person to potentially rival multi-million dollar advertising campaigns. With this script, web developers can now incorporate this approach in their own applications.

This script accepts an uploaded photo, which is then re-sized to Facebook's maximum dimensions. Then, an overlay image (as provided by you, the developer) is copied onto the image. This image is then saved to your web server and provided for users to download.

This script has been known by a few names in the past, most notably of which the Facebook Picture Tagging Script.


This code should be implemented in two main parts. You need an uploader page (uploader.php and uploader.html), and a success page (success.php). I've provided examples below.

Directory Structure:

In addition, you need to have a directory structure which includes a resource folder ($fbt->resourcesFolder) that contains the overlay image, and a processed folder ($fbt->processedFolder) in which finished images will be saved (CHMOD/set permissions appropriately).

<html xmlns="">

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Sample Uploader Page</title>


	<h2>Facebook Tagger</h2>

	<!-- Enctype MUST be multipart/form-data for file upload -->
	<form action="uploader.php" method="post" enctype="multipart/form-data">
    	<!-- For ease-of-use sake I like to put error messages on the same page as uploads -->
        <!-- Alternatively, you can code your website to display errors wherever you like -->
    	<?php @print( $fbtOutput ); ?>
    	Please upload your picture (JPEG or JPG format):<br />
    	<input type="file" name="picture_upload" />
        <br /><br />
        <input type="submit" name="submit" value="Tag me!" />
	<br /><hr />
    <i>For help and further explanations, see the <a href="">documentation</a>.</i>




# Check to see if the form has been submitted or not:
if( !isset( $_POST['submit'] ) ){
	# Form has not been submitted, show our uploader form and stop the script
	require_once( "uploader.html" );
	# Form has been submitted, begin processing data
	# Include the function file then call it with the uploaded picture:
	# TIP: The "../../ portion is a relative path. You will need to change this
	#      path to fit your website's directory structure.
	require_once( 'FacebookPicOverlay.php' );
	# Create the FacebookTagger object using our upload value given to us by uploader.html
	$fbt = new FacebookPicOverlay();
	# Let's say we're using this script to do an image overlay. Let's invoke the
	# overlay method, which will then return the image file relative to the resources
	# folder (ex: will return resources/processed/imagename.jpg).
	try {
		$image = $fbt->overlay( $_FILES['picture_upload'] );
	}catch( Exception $e ){
		print( "<b>Oops!</b> " . $e->getMessage() );
		print( "<br /><br /><a href=\"javascript:history.go(-1)\">Please go back and try again</a>" );
	# This will delete all images created more than two days ago (by default).
	# This is helpful in keeping our processed folder at a reasonable file size.
	require_once( "success.html" );

# That's all, folks!

<html xmlns="">

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Congratulations, you're tagged! (Sample Uploader Success Page)</title>


	<h2>Tagging Success!</h2>

	<div style="margin: 0px auto; text-align: center;">
        <b>Here's your freshly tagged image:</b><br /><br />
        To save, right click the image and select "Save Image As," "Save Link As," or "Save Picture As." Then, save it to your desktop!<br /><br />
        <!-- As we saw in uploader.php, $image is the path to the image beginning at the resources directory. -->
        <!-- In order to show our image I will need to create the first part of the link. In this case it just starts at the domain name. -->
       	<img src="<?php echo( 'http://' . $_SERVER['SERVER_NAME'] . '/path_to_resources_folder/' . $image ); ?>" alt="Facebook Picture" /><br /><br />
        <!-- $_SERVER['PHP_SELF'] is a PHP Superglobal basically pointing the link back to this PHP page -->
        Why not <a href="<?php echo( $_SERVER['PHP_SELF'] ); ?>">tag another</a>?
    <br /><hr />
    <i>For help and further explanations, see the <a href="">documentation</a>.</i>





string $rootPath
Path to the directory containing the resources and processed folders.

string $resourcesFolder
Resources folder name.

string $processedFolder
Processed folder name (where images are saved to).

int $fbWidth (and) int $fbHeight
These give the maximum dimensions of a profile picture as viewed on a Facebook profile page. Modify these values if the dimensions change.

string $overlay
File name of the image to overlay onto uploaded images. Must be a PNG file. Must be placed in the resources folder.

int $offset
Overlay image is, by default, placed at the very bottom of the image. A negative offset value will raise the overlay image, a positive one will lower it.

boolean $throwExceptions
If a user caused error is detected (i.e. wrong file type), the script must issue a fatal error. If true, it will throw an Exception which must be caught in your uploader page. If false, $FacebookPicOverlay->overlay() will return false, and $FacebookPicOverlay->error will contain the error message.

int $maxFileSize
In megabytes, the maximum file size to accept before rejecting the file as too large.
Important Note: PHP and Apache have its own upload limitations. If 20 MB (default) is greater than those limits, the script will automatically fail.

int $quality
The percentage of image quality (Range: 0 - 100). The higher the number the greater the quality, but the larger the file size.


public __construct()
Initializes script and checks configuration.

public overlay( $uploadedImage )
This is the script's main method, doing the processing and overlay. It accepts a single parameter $uploadedImage which should be a $_FILE resource (e.g. $fbt->overlay( $_FILES['picture_upload'] )).

Returns $image, containing a path including the processed folder and finished image's name.

public maintenance( $timestamp = NULL )
Deletes all files in the processed folder that were created before $timestamp. Defaults to two days ago.

See it in Action

Try overlaying pictures yourself using the demo (tagged photos last one hour):
Click here to view the demo.


FacebookPicOverlay.php - v2.1.0
View Plain   Download Code
 * Facebook Picture Overlay Script
 * Version: 2.1.0
 * Coded by: Shane Chism <>
 * Updates:
 * Distributed under the GNU Public License
/** \brief Facebook Picture Overlay Script
 * Allows for image overlay to uploaded files based on Facebook's standards
 * @author Shane Chism <>
class FacebookPicOverlay {
	// --------------------------------------------------
	// --------------------------------------------------
	// Modify the values in this section according to
	// your own needs. Pay close attention to your
	// directory structure.
	# Path to the directory containing the resources and processed folders:
	var $rootPath    		= "";
	# Resources folder name:
	# (default: "resources/")
	var $resourcesFolder   = "resources/";      	
	# Folder you would like the processed images saved to:
	# (default: "resources/processed/")
	var $processedFolder	= "resources/processed/";
	# Set the maximum height and width of the Facebook profile picture here:
	# (default: 200 x 600) -- Facebook may have changed them after this script was released
	var $fbWidth 	= 200;
	var $fbHeight	= 600;
	# Overlay image filename and extension (must be placed in the resources folder):
	# (default: "overlay.png")
	var $overlay     = "overlay.png";
	# Overlay offset from bottom. This will change based on your overlay image.
	# 0 means your overlay image will be placed on the direct bottom of the image,
	# Negative numbers bring the image up, positive ones push it down:
	# (default: 0)
	var $offset = 0;
	# Throw Exceptions?
	# true = User errors will generate an Exception() error
	# false = User errors will return overlay as false, and save error to $this->error
	var $throwExceptions = true;
	// --------------------------------------------------
	// --------------------------------------------------
	// --------------------------------------------------
	// You can fine tune the tagger to your needs,
	// though these options can remain the same and your
	// tagging should still work.
	# Maximum image size allowed for upload (in MB):
	# (default: 20)
	var $maxFileSize	= 20;
	# Save images at this quality (percentage):
	# (smaller quality has a smaller file size but looks worse)
	# (default: 100)
	var $quality 		= 100;
	# Save images in this file format:
	# (options: "jpg", "jpeg", "JPG", "JPEG")
	# (default: "jpg")
	var $extension 		= "jpg";
	// --------------------------------------------------
	var $uploaded, $uploadedInfo, $error;
	function __construct(){
	private function checkConfig(){
		if( substr( $this->resourcesFolder, 1 ) == '/' )
			$this->resourcesFolder = substr( $this->resourcesFolder, 1, ( strlen( $this->resourcesFolder ) - 1 ) );
		if( substr( $this->resourcesFolder, -1 ) != '/' )
			$this->resourcesFolder .= "/";
		if( substr( $this->processedFolder, 1 ) == '/' )
			$this->processedFolder = substr( $this->processedFolder, 1, ( strlen( $this->processedFolder ) - 1 ) );
		if( substr( $this->processedFolder, -1 ) != '/' )
			$this->processedFolder .= "/";
		if( !file_exists( $this->rootPath . $this->resourcesFolder ) )
			$this->printErr( "The resources folder path you have specified is invalid. Please check it and try again (configuration section: <code>\$rootPath</code> and <code>\$resourcesFolder</code>)." );
		if( !file_exists( $this->rootPath . $this->processedFolder ) )
			$this->printErr( "The processed folder path you have specified is invalid. Please check it and try again (configuration section: <code>\$rootPath</code> and <code>\$processedFolder</code>)." );
		$overlay = $this->rootPath . $this->resourcesFolder . $this->overlay;
		if( !file_exists( $overlay ) )
			$this->printErr( "The \"overlay\" image you specified in the configuration section (<code>\$overlay</code>) does not exist. Please correct and try again." );
		$overlaySize = getimagesize( $overlay );
		if( $overlaySize[0] > $this->fbWidth || $overlaySize[1] > $this->fbHeight )
			$this->printErr( "Your overlay image is larger than Facebook will allow on a profile picture (max is " . $this->fbWidth . "w X " . $this->fbHeight . "h)." );
	private function printErr( $text ){
		die( "<h3>FBT Error:</h3> " . $text );
	private function throwErr( $err ){
		$this->error = $err;
		if( $this->throwExceptions )
			throw new Exception( $err );

	# Places your overlay image on the picture and returns the hyperlink
	public function overlay( $uploaded ){
		$this->uploaded = $uploaded;
		$overlay = $this->rootPath . $this->resourcesFolder . $this->overlay;
		$overlaySize = getimagesize( $overlay );
		if( empty( $this->uploaded ) || $uploaded['size'] < 1 ){
			$this->throwErr( "You have not chosen an image to upload!" );
			return false;
		$this->uploadedInfo = getimagesize( $this->uploaded['tmp_name'] );
		if( $this->uploaded['size'] > ( $this->maxFileSize * 1000000 ) || filesize( $this->uploaded['tmp_name'] ) > ( $this->maxFileSize * 1000000 ) ){
			$this->throwErr( "The file you have chosen to upload is too big." );
			return false;
		if( $this->uploadedInfo['mime'] != "image/jpeg" && $this->uploadedInfo['mime'] != "image/jpg" ){
			$this->throwErr( "The file you have chosen to upload is the wrong file type. Please choose a JPG or JPEG file only." );
			return false;
		$new = array();
		$new[0] = $this->fbWidth;	
		$new[1] = ( $new[0] * $this->uploadedInfo[1] ) / $this->uploadedInfo[0];
		if( ( $new[1] + $overlaySize[1] ) > $this->fbHeight )
			$canvasH = $this->fbHeight;
			$canvasH = $new[1];
		$src = imagecreatefromjpeg( $this->uploaded['tmp_name'] );
		$tmp = imagecreatetruecolor( $new[0], $canvasH );
		imagecopyresampled( $tmp, $src, 0, 0, 0, 0, $new[0], $new[1], $this->uploadedInfo[0], $this->uploadedInfo[1] );
		imagealphablending( $tmp, true );
		$overlayRes = imagecreatefrompng( $overlay );
			$filename = time() . "-processed.jpg";
			$file = $this->rootPath . $this->processedFolder . $filename;
		}while( file_exists( $file ) );
		imagecopy( $tmp, $overlayRes, 0, ( ( $new[1] + $this->offset ) - $overlaySize[1] ), 0, 0, $overlaySize[0], $overlaySize[1] );
		imagejpeg( $tmp, $file, $this->quality );
		if( !file_exists( $file ) )
			$file = $this->rootPath . $this->resourcesFolder . $this->oops;
		imagedestroy( $src );
		imagedestroy( $tmp );
		imagedestroy( $overlayRes );
		return ( $this->processedFolder . $filename );
	# Deletes all files in the processed folder that were created before $timestamp
	# Defaults to 2 days ago
	public function maintenance( $timestamp = NULL ){
		if( $timestamp == NULL )
			# Defaults to 2 days ago
			$timestamp = strtotime( "-2 days" );
		if( $timestamp > time() )
			$this->printErr( "You are trying to perform maintenance on files created in the future. This is beyond the script's abilities, please install a time machine to continue." );
		if( $handle = opendir( $this->rootPath . $this->processedFolder ) ){
			while( false !== ( $filename = readdir( $handle ) ) ){
				if( substr( $filename, ( -1 * ( 1 + strlen( $this->extension ) ) ) ) == ( "." . $this->extension ) ){

					$file = $this->rootPath . $this->processedFolder . $filename;
					if( filectime( $file ) < $timestamp )
						@unlink( $file );
			closedir( $handle );
			$this->printErr( "Unable to access the processed folder. Check your <code>\$rootPath</code> and <code>\$processedFolder</code> settings in the configuration section." );


JUNE 23 2011