Resize an iFrame's height to fit it's contents
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, I 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: I have set this up API style like above and would be willing to let you query my server for a low monthly cost OR for a fee, I could help you set it up on your server.
Written by Shane Stebner
Related protips
1 Response
I realize this is ridiculous for production, but I challenged myself to see if I could come up with a solution.