Putting it all together in a way that can be used by your local PHP scripts
I've mentioned a few bits and pieces and those with the time to disect it all will be able to stop here. However nothing works better than a good fully-featured example. Examples can be copied and seen to work and then modified for the task at hand.
Our example uses three scripts:
1. the root script, i.e. the one that runs as root as does the things you otherwise can't
2. the calling script, i.e. Accounting.php.inc, the one that gets the root script to do something
3. the controlling script, i.e. the one that forms part of your website and which uses Accounting.php.inc to do things
Let's see all these three scripts, including their locations and how they're used.
1. the root script
Location:
/usr/local/cpanel/whostmgr/docroot/3rdparty/example/example.php
Ownership/permissions:
/usr/local/cpanel/whostmgr/docroot/3rdparty/example - root:root 0755
/usr/local/cpanel/whostmgr/docroot/3rdparty/example/example.php - root:root 0644
Contents:
PHP Code:
<?php
// Limit access to 'root'
if ($_SERVER['REMOTE_USER'] != "root") {
echo "You are not root";
exit();
}
// Try and open /etc/localdomains
$fp = @fopen("/etc/localdomains", "r");
if (!fp) {
echo "Failed to read /etc/localdomains";
exit();
}
// Read /etc/localdomains
$s_localdomains = fread($fp, filesize("/etc/localdomains"));
fclose($fp);
// Output content for the benefit of the calling script
echo $s_localdomains;
// Exit for neatness
exit();
?>
2. the calling script
Location:
/home/example/lib/whm.php
Ownership/permissions:
example:example 0644
i.e. standard 'normal user' ownership for phpsuexec environments and pretty standard permissions
Uploading the script normally via a standard FTP client should give you the desired ownwership and permissions, so there's no need to specifically set these.
Contents:
PHP Code:
<?php
// Include dependencies
require_once('accesshash.php'); // Contains definitions and values for $host, $user, $accesshash and $usessl
require_once('Accounting.inc.php'); // This would be a local copy, but the original could also be used
function whmListDomains($host,$user,$accesshash,$usessl) {
// Get list of domains in /etc/localdomains
$s_domains = whmreq("/3rdparty/webignition/listdomains.php",$host,$user,$accesshash,$usessl);
if ($cpanelaccterr != "") {
return;
}
// Get domains into an array and trim
return explode("\n", trim($s_domains));
}
?>
Notes:
In my implementation, I renamed $host and $user to $whm_host and $whm_user. With a variable named $user, I encountered problems when calling the above function from the controlling script. Whatever the reason, it was messing around with the PHP session I was using to store the data of the user of my site who was logged in and doing things. I then renamed $host to $whm_host for consistency, although a variable named $host presented no technical issues.
3. the controlling script
Location:
/home/example/public_html/controller.php
Ownership/permissions:
example:example 0644
i.e. standard 'normal user' ownership for phpsuexec environments and pretty standard permissions
Uploading the script normally via a standard FTP client should give you the desired ownwership and permissions, so there's no need to specifically set these.
Contents:
PHP Code:
<?php
// Include dependencies
require_once('whm.php');
function accountDomainTaken($s_domain)
{
// Check for domains on the server
global $host;
global $user;
global $accesshash;
global $usessl;
$a_domains = whmListDomains($host,$user,$accesshash,$usessl);
return in_array($s_domain, $a_domains);
}
/*
Include plenty of code here for generating a string containing the representation of a domain name.
In reality, this would most likely come from user input and should be severly sanitised!
/*
$domain = "example.com";
if (accountDomainTaken($domain)) {
echo "The domain name ".$domain." is already in use on this server";
} else {
echo "The domain name ".$domain." is free to use";
}
?>
A brief summary of the above process
1. A user, through a web interface, enters a domain name and the data is passed to the controlling script
2. The controlling script makes use of the calling script and uses the calling script's function to check if a domain name is taken
3. The calling script uses remote access features to call the root script that retrieves the useful data from a file otherwise inaccessible to the user 'example'
Omissions and errors
The above PHP coding is a severly butchered-down form of what I am actually using. Through removing the forest to reveal only a couple of trees, I may have pruned the odd branch off that should not have been.
Therefore don't take the above PHP code as absolute as it may not be. It's just an example. Copy the idea, not the code.
That said, I'll correct my own typing errors if people are kind enough to point them out.
Conclusions (what have actually done here?)
The above ideas, presented in the rough chronological order in which they were developed, should hopefully have demonstrated how we can solve the problem defined at the beginning.
A certain level of prior knowledge is required to build such scripts securely, and I'll leave the curiosities of this to you. The root script does include the line if ($_SERVER['REMOTE_USER'] != "root") only as a means to demonstrate that some form of security is required. This level of security is for example purposes and minimal at best. Please make it better for your needs.
Regardless of the level of PHP knowledge required, the principles should be clearly explained so that you should at least have an understanding of how the process runs even if you don't fully understand what the PHP scripts themselves do. The principle is the good thing, the code is not. Once you have the principle, the code will follow.
What do if it doesn't work for you
Please please please don't simply try and PM me or even post for help. Sit down, look through what you've done and use whatever debugging process you prefer to find the cause of the problem. You won't learn anything if you are spoon-fed.
Some problems may arise due to inaccuracies in this HOW TO. However, the code may be inaccurate but the principle is sound. Again, follow the principle and not the code.
Nevertheless if you do have problems and can't figure out why, please don't PM me for help. I simply don't have time! Please do post problems and if I have the time I'll see what I can make of them, as will others.