How to resize an iframe to fit its content


I know. It's impossible, right? I mean, with cross-domain rules, you can't use javascript to determine the height of it's content, so it must be impossible.

WRONG. Now, we understand this solution may not be the most efficient, but it appears to be the only one that works "flawlessly".

Here's how it works:

1) Setup PhantomJS on your server. (Headless Webkit Browser)
2) Create a javascript file with the following contents (name it "pageHeight.js"):

if(phantom.args.length < 3 || phantom.args.length > 3) {
    console.log('Not all params are supplied.');
    phantom.exit(1);
}
else{
var page = new WebPage(),
address, delay, vwidth;
address = phantom.args[0];
delay = phantom.args[1];
vwidth = phantom.args[2];
if(vwidth == 320 || vwidth == 480 ){ 
page.settings.userAgent = 'Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16'; 
}
else if(vwidth == 768 || vwidth == 1024){ 
page.settings.userAgent = 'Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10'; 
}
page.viewportSize = { width: vwidth, height: '5' }; //minimum height
page.open(address, function (status) {
	if (status !== 'success') {
		console.log('Unable to load the address!');
		phantom.exit('1');
	} else {
		window.setTimeout(function () {
				console.log(page.evaluate(function() {
					var body = document.body,
					    html = document.documentElement;					
					return Math.max( body.scrollHeight, body.offsetHeight, 
					                       html.clientHeight, html.scrollHeight, html.offsetHeight );
				}));
				page.close()
				phantom.exit();
		}, delay);
	}
});
}

Basically this opens the page in a phantom js headless browser instance and grabs it's height based on the viewport width

3) Next create a PHP file in the same folder with the following (name it "pageHeight.php"):

<?php
/* This function runs mysqli_real_escape_string on a string, you'll need to tweak this to match your database function */
function escape($string){
	global $db;
	$string = mysqli_real_escape_string($db, $string);
	return $string;
}
/* This function escapes all $_GET variables */
function cleanGET(){
	foreach($_GET as $key=>$value){
	$clean[escape($key)] = escape($value);
	}
	return $clean;
}
/* This function checks a url to make sure it exists */
function domainExists($url) { 
$ch = curl_init($url); 
//cURL set options
//cURL options array set
$options = array(
    CURLOPT_URL => $url,              #set URL address
    CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13',  #set UserAgent to get right content like a browser
    CURLOPT_RETURNTRANSFER => true,         #redirection result from output to string as curl_exec() result
    CURLOPT_COOKIEFILE => 'cookies.txt',    #set cookie to skip site ads
    CURLOPT_COOKIEJAR => 'cookiesjar.txt',  #set cookie to skip site ads
    CURLOPT_FOLLOWLOCATION => true,         #follow by header location
    CURLOPT_HEADER => true,                 #get header (not head) of site
    CURLOPT_FORBID_REUSE => true,           #close connection, connection is not pooled to reuse
    CURLOPT_FRESH_CONNECT => true,          #force the use of a new connection instead of a cached one
    CURLOPT_SSL_VERIFYPEER => false         #can get protected content SSL
);
//set array options to object $curl
curl_setopt_array($ch, $options);
curl_exec($ch); 
$retcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); 
curl_close($ch);  if(empty($retcode) || $retcode > 400) { return false; } 
else { return true; } 
}
/* Get all $_GET variables and clean them */
$clean = cleanGET();
/* Set local vars */
$vwidth = $clean['vwidth'];
$delay = $clean['delay'];
/* Setup Defaults */
if(!is_numeric($delay) || $delay <= 0 || $delay > 3000){ $delay = '600'; }
if(!is_numeric($vwidth) || $vwidth < 300 || $vwidth > 2000){ $vwidth = '1200'; }
/* Cleanup the URL */
$requestedURL = html_entity_decode($clean['url']);
if(substr($requestedURL, 0, 4) != 'http'){ $requestedURL = 'http://'.$requestedURL; }
$requestedURL = rtrim(trim(strtolower($requestedURL)), '/');
/* Verify the URL Lead Somewhere Legit */
if(!domainExists($requestedURL)){ (create a function
	echo "URL failed to load.";
}
/* Run Phantomjs */
$command = "phantomjs --ignore-ssl-errors=true --cookies-file=cookies.txt pageHeight.js ".escapeshellarg($requestedURL)." $delay $vwidth";
/* Echo the results and exit */
echo exec($command); exit();
?>

4) Now, to the final part. Actual usage. To set the height of your iframe, simply call that PHP file with some $_GET variables. You'll NEED the URL of the webpage and the width of the viewport. Optionally, you may choose to change the delay after the page has been loaded before getting it's height.

Example Usage:

<iframe 
	src='http://flwebsites.biz' 
	style='
		width: 500px; 
		height: <?php echo file_get_contents('http://yourdomain.com/pageHeight.php?url='.urlencode('http://').'flwebsites.biz&vwidth=500&delay=2'); ?>px'
	></iframe>

If you are unable to get this working: We have set this up API style like above and would be willing to let you query our server for a low monthly cost OR for a fee, we could help you set it up on your server.




Shane Stebner

Author: Shane Stebner

Shane is a successful web-developer specializing in responsive design, and the open-source LAMP stack. Over the years, he's gained in-depth experience with Stripe, Twilio, PhantomJs, Authorize.net, PayPal, Facebook, Twitter, and many other plugins/APIs.


comments powered by Disqus