phpdreams

Easy cPanel Stats

If you use or administer a cPanel server, you probably know that you must be logged in to cPanel to view the output from the AWStats program. Well, if you'd like those stats to be viewed by others - like the boss, etc. - then you must grant them access. This can be VERY dangerous as you can imagine. Well I put together a handy script to show those stats without requiring they login.

With just two simple parts, we'll essentially display the stats information by proxy from cPanel using PHP's cURL Library to pull the data from cPanel and display it from the folder of your choice.

First we'll start with the access info:

<?php
// username and password used to grant access to view stats pages
$username = "statlogin";
$password = "statpass";

// domain name (including subdomain) that you want stats for
$site = "mydomain.com";

// whm/cpanel hostname
$server = "server1.hostdomain.com";

// cpanel usename and password
$cpanelusername = "mydomain";
$cpanelpassword = 'cOoLpAsS';
?>

The $username and $password entries will be used to perform simple HTTP Authentication to allow access to the page only to those whom you wish to see it. You could of course add set it up with a more robust authentication system via database, etc., but I'll leave that to you.

The $site variable is the domain name (minus the 'www.') of the site you want stats for. However if you have a subdomain like 'forums.mydomain.com', then that's what should be entered as AWStats will create separate stats for each subdomain.

The $server variable is the hostname of the cPanel server, not necessarily your domain.

The $cpanelusername and $cpanelpassword are the credentials you use to access cPanel for the domain you want stats for.

Now we'll look at the code that does the real work:

<?php
require ('config.php');

// check for valid auth user
if (!isset($_SERVER['PHP_AUTH_USER']) || $_SERVER['PHP_AUTH_USER'] != $username || $_SERVER['PHP_AUTH_PW'] != $password) {
	header('WWW-Authenticate: Basic realm="Site Statistics"');
	header('HTTP/1.0 401 Unauthorized');
	echo 'Authorization Required.';
	exit;
} else {
	// only processed if we have a valid user

	if (isset($_REQUEST['image'])) {
		// if an image is requested, we only need the filename
		$request = $_REQUEST['image'];
	} else {
		// otherwise we build our query to cPanel
		$request = 'awstats.pl?';

		// if we're not requesting a specific frame,
		// we don't have our site set yet, so add that info
		if(empty($_REQUEST['framename'])) {
			$request .= "config=$site&ssl=&lang=en";
		}
		$request .= $_SERVER['QUERY_STRING'];

		// just used to simplify the test later
		$notImage = TRUE;
	} // end if image

	$Curl = curl_init();

	curl_setopt($Curl, CURLOPT_SSL_VERIFYPEER, 0);
	curl_setopt($Curl, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt($Curl, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($Curl, CURLOPT_URL, "https://$server:2083/".$request);
	curl_setopt($Curl, CURLOPT_USERPWD, $cpanelusername.':'.$cpanelpassword);

	$Output = curl_exec($Curl);

	if (curl_errno($Curl) > 0) {
		echo 'Curl Error: ' . curl_error($Curl);
		curl_close($Curl);
		exit;
	}

	curl_close($Curl);

	if($notImage) {
		// let's do some parsing to replace paths with ones that work with our proxy script
		if (empty($_REQUEST['framename']) || $_REQUEST['framename'] == 'index') {
			$Output = str_replace('src="', 'src="'.$_SERVER['PHP_SELF'].'?', $Output);
		} else {
			$Output = str_replace('src="/', 'src="'.$_SERVER['PHP_SELF'].'?image=', $Output);
		}

		$Output = str_replace('<form', '<form method="get"', $Output);
		$Output = str_replace('action="', 'action="'.$_SERVER['PHP_SELF'].'?', $Output);
		$Output = str_replace('href="', 'href="'.$_SERVER['PHP_SELF'].'?', $Output);
		$Output = str_replace('href="'.$_SERVER['PHP_SELF'].'?https://', 'href="https://', $Output);
		$Output = str_replace('awstats.pl?', '', $Output);
	} // end if notImage

	echo $Output;
} // end if valid user
?>

First of course we will require our config.php file which contains all the appropriate login and server info.

Then on line 5, we check to see if we have appropriate HTTP_Auth credentials. If not, lines 6-9 will prompt for a login by issuing the appropriate http header.

Now we must determine if we're retrieving either an image or HTML output from AWStats. For an image, we've assigned an 'image=' tag to our requests, so we can make our determination based on that. For an image, we simply request the image filename. However if we're retrieving HTML, we'll need to massage the data a bit prior to outputting it.

We're using the cURL library to retrieve the AWStats output from cPanel. We're going to use the secure connection to cPanel via the default port of 2083. I chose to do this because some hosts only allow cPanel access via SSL...myself included. So unless the cPanel default ports have been changed, this should work just fine. Since by default cPanel sets up a self-signed certificate for the SSL connection, we must tell cURL to ignore any potential certificate issues. This is done on lines 33 & 34. Next we tell cURL that we want it to return what it finds. Then we feed it our username & password for cPanel and let it do its thing!

The code from lines 50-61 modifies any image or file paths so that they'll work with our proxy script.

Once we've done all that, we're ready to output what we have. It's not an overly complicated process, but it works really well to grant access to your stats without the potential consequences you may find if you give somebody the 'keys to the kingdom' so to speak.

Note: I haven't gone through any real efforts to secure this script other than the basic HTTP_Auth mechanism. A malicious user with the login/pass could potentially feed other input to cPanel which does a LOT via GET requests, so it would be best to share this with only users you fully trust. My primary reason for posting this was to share some ideas and a novel workaround for a potentially sticky issue.

blog comments powered by Disqus

What is PHP Dreams?

My name is Bill "Sir William" Wheeler. I am a freelance web developer specializing in PHP & MySQL with a healthy amount of HTML, CSS & JavaScript (jQuery FTW!) thrown in for good measure. I put this site together to share my thoughts and findings with others. I hope to have something for novices and advanced programmers alike.

Bookmark and Share
Follow Me on Twitter
MODx CMS/F