How to take screenshot of url with PHP

How to take screenshot of url with PHP

Here is an example and source code of how to take screenshot of url with php. I have taken this code from one of my projects. It is also able to handle https and optionally, follow through with redirects.

Requirements :
-PhantomJS standalone executable(.exe)
-PHP library for phantomjs

Setup :

  1. Follow the installation for PHP PhantomJS here
  2. Set the path to your phantomjs executable file in the code

    $client->getEngine()->setPath(__DIR__.’/bin/phantomjs.exe’);

    Note : You may have to rename /bin/phantomjs to /bin/phantomjs.exe

Additional features :
– customize width/height of screenshot
– support http and https
– follow redirects

 

require 'vendor/autoload.php';

use JonnyW\PhantomJs\Client;


function get_redirect_url($url)
{
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_HEADER, true);
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Set to true to make curl follow the url
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	$a = curl_exec($ch); 
	$url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); // This gets the last location/url after all the redirection has been followed through

	return $url;
}
function get_http_response_code($url)
{
	$ch = curl_init($url);
	curl_exec($ch);
	$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
	return $code;
}
function is_redirect($url) 
{
	$code = get_http_response_code($url);
	if (($code == 301) || ($code == 302)) {
		return true;
	}
	return false;
}



function screenshot($width, $height, $url, $filePath="file.jpg", $followRedirect=false)
{
        $path = pathinfo($filePath);
        $directory = $path['dirname'];

	if( $followRedirect && is_redirect($url) ) 
	{
		$redirectedUrl = get_redirect_url($url);
		echo "{$url} redirects to {$redirectedUrl} <br/>";
		$url = $redirectedUrl;
	}		

	// Ensure the path is writable to PhantomJS/PHP
	if( !is_writable($filePath) )
	{
		//echo "$directory of $filePath is not writable. Chmod-ing <br />";
		//return false;
	}

	$client = Client::getInstance();
	$client->getEngine()->setPath(__DIR__.'/bin/phantomjs.exe');
	// HTTPS support
	$client->getEngine()->addOption('--ssl-protocol=any');
	$client->getEngine()->addOption('--ignore-ssl-errors=true');
	$client->getEngine()->addOption('--web-security=false');

	$width  = $width ? $width : 1280;  // Note : Specifying a 800x600 may be too small and result in @media css determining
	$height = $height ? $height : 800; // it to be a mobile instead of desktop. Generally a 1280x800 should be good.
	$top    = 0;
	$left   = 0;


	//@see JonnyW\PhantomJs\Http\CaptureRequest
	$request = $client->getMessageFactory()->createCaptureRequest($url, "GET"); //('http://jonnyw.me', 'GET');
	$request->setOutputFile($filePath);
	$request->setViewportSize($width, $height);
	$request->setCaptureDimensions($width, $height, $top, $left);
	$request->setDelay(3); // Depends on how long it takes for the webpage to fully load. this vs setTimeout(x) ?
	$request->setTimeout(1000); // Not sure the diff between setDelay and setTimeout though...

	//@see JonnyW\PhantomJs\Http\Response 
	$response = $client->getMessageFactory()->createResponse();

	// Send the request
	$client->send($request, $response);
	
	return file_exists($filePath); // Check if screenshot exists
}

 

Enjoyed the content ? Share it with your friends !

DataTables filter by ip address

DataTables filter by ip address

I had to make a custom filter for ip address which accepted cidr notation (e.g /24). While there was the function to sort by ip at the time when i was doing it, a filter by ip address that accepted cidr or subnet masks function didn’t seem to have been implemented. I couldn’t find any publicly available solution online either, so i took some time to implement it. The solution is in php but can be easily ported to javascript/html if you wish

To get it to work on your own code, you will have to modify the 2 variables

var ipColNum = 0; // column number of your ip address

var tableId = “#results”; // table id that you want to attach datatables to

<!--jquery-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<!--datatables-->
<link rel='stylesheet' type='text/css' href='//cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css'/>
<script type='text/javascript' src='//cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js'></script>


<table id="results">
  <thead>
    <tr>
      <th>Ip Address</th>
      <th>Name</th>
      <th>Country</th>
    </tr>
  </thead>
  
  <tbody>
    <tr>
      <td>192.168.0.1</td>
      <td>abc</td>
      <td>abc country</td>
    </tr>
    <tr>
      <td>122.20.21.133</td>
      <td>xyz</td>
      <td>xyz country</td>
    </tr>
    <tr>
      <td>192.168.0.10</td>
      <td>john</td>
      <td>john country</td>
    </tr>
    <tr>
      <td>192.168.1.1</td>
      <td>sally</td>
      <td>sally country</td>
    </tr>
  </tbody>
</table>


<script>
    var table = null;
    var ipColNum = 0; // set the column number for the ip address
    var tableId = "#results";
    
    function getIpRangeFromAddressAndNetmask(str) {
      var part = str.split("/"); // part[0] = base address, part[1] = netmask
      var ipaddress = part[0].split('.');
      var netmaskblocks = ["0","0","0","0"];
      if(!/\d+\.\d+\.\d+\.\d+/.test(part[1])) {
        // part[1] has to be between 0 and 32
        netmaskblocks = ("1".repeat(parseInt(part[1], 10)) + "0".repeat(32-parseInt(part[1], 10))).match(/.{1,8}/g);
        netmaskblocks = netmaskblocks.map(function(el) { return parseInt(el, 2); });
      } else {
        // xxx.xxx.xxx.xxx
        netmaskblocks = part[1].split('.').map(function(el) { return parseInt(el, 10) });
      }
      var invertedNetmaskblocks = netmaskblocks.map(function(el) { return el ^ 255; });
      var baseAddress = ipaddress.map(function(block, idx) { return block & netmaskblocks[idx]; });
      var broadcastaddress = ipaddress.map(function(block, idx) { return block | invertedNetmaskblocks[idx]; });
      return [baseAddress.join('.'), broadcastaddress.join('.')];
    }

  function ip2long(IP) {
    var i = 0;
    IP = IP.match( /^([1-9]\d*|0[0-7]*|0x[\da-f]+)(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?(?:\.([1-9]\d*|0[0-7]*|0x[\da-f]+))?$/i );
    if (!IP) { return false; }
    IP[0] = 0;
    for (i = 1; i < 5; i += 1) {
      IP[0] += !!((IP[i] || '').length);
      IP[i] = parseInt(IP[i]) || 0;
    }
    IP.push(256, 256, 256, 256);
    IP[4 + IP[0]] *= Math.pow(256, 4 - IP[0]);
    if (IP[1] >= IP[5] || IP[2] >= IP[6] || IP[3] >= IP[7] || IP[4] >= IP[8]) { return false; }
    return IP[1] * (IP[0] === 1 || 16777216) + IP[2] * (IP[0] <= 2 || 65536) + IP[3] * (IP[0] <= 3 || 256) + IP[4] * 1;
  }

//https://www.jqueryscript.net/demo/DataTables-Jquery-Table-Plugin/examples/plug-ins/range_filtering.html
var ipFilter = function(searchValue) {
    $.fn.dataTable.ext.search.push(
        function( settings, data, dataIndex ) {
            console.log("srchValue" + searchValue);
            var ipRange = searchValue;
            var colIpAddr = data[0]; // use data for the age column
     				var range = getIpRangeFromAddressAndNetmask(ipRange);
            var min = ip2long(range[0]);
            var max = ip2long(range[1]);

            //console.log(ipRange);
            //console.log("min : " + min + " max : " + max);
            //console.log("chk : " + colIpAddr);

            var longIpAddr = ip2long(colIpAddr);
            
            if( longIpAddr >= min && longIpAddr <= max ) {
                return true;
            }
            return false;
        }
    );

    table.draw();
    $.fn.dataTable.ext.search.pop();
};

 

$(document).ready( function () {
    table = $(tableId).DataTable({
        responsive: true
    });

    if( !table ) {
        console.log("Failed to initialize DataTable()");
    } else {
   
        // Change filter algorithm when cidr notation detected
        $('.dataTables_filter input').unbind().keyup(function() 
        {
            var value = $(this).val();
            if (value.length==0) {
                table.search('').draw();
                return;
            }

            // Must have the format xxx.xxx.xxx.xxx/0-32 
            // Does not match any string without a '/<number>' at the back.
            if( /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))$/.test(value) ) {
                // We need to reset the table first, otherwise our filter won't work 
                // probably because it detects e.g 192.168.0.1/32 -> 192.168.0.1, 192.168.0.1/ , 192.168.0.1/3, 192.168.0.1/32. The earlier 2 has to results.
       
                table.search('').draw();
                ipFilter(value);
            } else {
                table.search(value).draw();
            }
        });
        
    }
} );


</script>

 

See it in action over at the JsFiddle : here¬†or below .You can test it out by putting a search value of “192.168.0.0/23” or any others of your choice

Enjoyed the content ? Share it with your friends !