cPanel Blog

cPanel

JSON vs. XML in LivePHP

Bookmark and Share
user-pic

A while back, Matt Dees blogged about our upcoming change to LivePHP in 11.28. Specifically, he mentions the use of JSON. In this article I will illustrate, in brief, why this change was made. The decision process, as you'll see, wasn't exactly straight forward, but a solid compromise.

This is a very common question on the cPanel forums. Many times 'XYZ' is adding a particular DNS zone or creating a MySQL database. In this blog post, we'll go through the basics of script hooks and make a post hook that utilizes the XML-API to achieve 'XYZ.'

More Details About DB Mapping

Bookmark and Share
user-pic

As mentioned in A General Overview of Database Mapping , DB Mapping is available with the launch of cPanel 11.25.1. Let’s recap what DB Mapping is and then we can chew on the details:

  • DB Mapping is core code in 11.25.1
  • DB Mapping exposes DB Prefixing behaviors
  • DB Mapping provides an interface for importing non-cPanel accounts

 

Creating cPanel CGI Scripts

Bookmark and Share
user-pic

cPanel and CGI

One of the most flexible ways of working within cPanel is by creating CGI applications.  Of course, this isn’t the most efficient method, however sometimes efficiency isn’t your best bet when you’re in a rush.  You can use a standard CGI script within cPanel, you are limited by our APIs, such as what perl version to use.

First thing to note, is that these CGI scripts  have to be placed in /usr/local/cpanel/base/3rdparty/ with normal CGI permissions (have to be executable by the user, cannot be globally writable, etc).  Once placed here it can be accessed via $IP:2083/3rdparty/scriptnamed.cgi.  If you place them anywhere else within the cPanel document root, they will be offered up for download rather than executable.

When these CGI scripts are executed, they are executed as the user, so limited permissions apply.

What if you want to actually access cPanel’s APIs from within this CGI script?  What do you do?  There are a few different ways of handling this.  First you can use the JSON API if you just want to handle the interaction via javascript (you’re already authenticated, why not?).  The other option is using the Cpanel::XML module to make XML-API calls without the HTTP interface at all.  With the introduction of XML API’s Fast Mode we included a function called cpanel_fast_exec.  This is essentially a perl interface into API1 and API2 that can be accessed outside of cPanel.  The data passed into this is the same as the parameters used inside of fast mode.  For example, if you wanted to get a list of email accounts, you would call the following:

my $xml = Cpanel::XML::cpanel_exec_fast(
        {
                'cpanel_xmlapi_module' => 'Email',
                'cpanel_xmlapi_func' => 'listpopswithdisk',
        }
);

$xml = XMLin($xml);



Now $xml is a hash reference containing all the information returned by the call.

To download the example of this in use, click here. 

API basics and how to call API1 functions

Bookmark and Share
user-pic

I have been noticing several people challenged with calling cPanel functions via our various ways of hooking into our APIs. Unfortunately, this isn't as cut and dry as just calling a function within a programming language.  Various factors, such as whether the call is being made from within cPanel or from a remote system, affect how this needs to be done.

To help you understand this, I will begin covering these topics in a series of posts on cPanel's various functions and how they work. In this first post of the series, I will discuss the basics of cPanel's APIs, and how to call API1 functions.

The basics

Before we can even begin going over how to call cPanel's API functions, we need to discuss the various API types.

For the most part, cPanel's API is divided into two sub-systems; API1 and API2. The difference between these is in how they are called and how they return data.

API1 will normally print data to the cPanel interface.  This works well when the functions are called via cpanel tags (covered later in this article), but won't return much useful data when called via the XML API, livePHP or CGI scripts. 

API2, on the other hand, is a much more robust system, capable of returning complex data structures that can be parsed into templates contained within a cp tag. API2 calls, as they do actually return data, will always return relevant information when called via the XML API, livePHP or CGI scripts.

One of my favorite features of API2 is that it uses named-based parameters that translate well into URL parameters.



Calling API1 functions

API1 functions can be called via a tag. As previously mentioned, these print data to the cPanel interface. cpanel tags use the following format:


<cpanel Module="function( params )">



So, if you wanted to call Ftp::ftpservername(), which is used to print out which FTP server is being used, it would be called with the following syntax:

<cpanel Ftp="ftpservername()">

Now, you will not want all functions to actually display data. For example, Mysql::adddb is generally something that you do not want printing data, for security reasons. Instead you want to check for error handling.

Any data being printed from this function can be suppressed in the browser via HTML comments, like so:

<!--Module="function()"-->


Sending input to the API1 function

So, in order to pass data to an API function, we will need a way to pull in the data.

Inside of cPanel's HTML parsing, we have access to certain variables. The main variables that you need to be aware of are $FORM and $CPERROR.

$FORM is merely a variable that is populated with either GET or POST data passed to the page from the browser. This variable is how cPanel passes data around from page to page. To access it, you call the $FORM variable the same way that you would call a hash in Perl ($FORM{'element'}).

So, for example, if you had a page called add_mysql_db that was passed the following: 


add_mysql_db.html?db=dbname


It would contain the following:


<cpanel Mysql="addb( $FORM{'db'} )">

The <cpanelif> tag

Along with the cpanel tag, there is also support for some really basic logic within this system, via the <cpanelif> tag. This tag allows for checking of basic boolean logic to see if a variable is set; if true, it will send whatever is contained between the <cpanelif> tags to the browser.  <cpanelif> tags cannot be nested in any way.

To call cpanelif, you will do something like the following:

<cpanelif $VAR{''}>

HTML CODE HERE

</cpanelif>

This is useful when you want to display an error message within cPanel's interface.  These are populated into the $CPERROR{$context} variable. 

Unfortunately, context is defined on the back-end on a per-module basis, so generally $context will be the same as whatever module you are calling.  In the case of our previous MySQL example, if we wanted to check for an error message, we would want to do the following:


    <cpanel Mysql="adddb( $FORM{'db'} )">

    <cpanelif $CPERROR{'mysql'}>

      ERROR: $CPERROR{'mysql'}

    </cpanelif>

Of course, you would want to also want to do !$CPERROR{'mysql'} around any success messages to make sure you don't end up with "ERROR: errormsg This was successful".

These are the basics of how to call API1 via .html files. You can always use the XML API to call these functions as well, but because this is API1, you may not get any useful data.

 

Using WHM remote authentication

Bookmark and Share
user-pic

One thing that I have noticed while working with other people developing software that interacts with WHM’s XML API is that they always use basic HTTP authentication. It is okay to use basic authentication, but it is held to the same security restrictions in place for people using browsers. When working with cPanel in a remote fashion, having to work around these restrictions is unnecessary. Inside of our DNS clustering system, we developed a solution for just this problem called WHM Remote Access Keys or “WHM auth”.

The way that WHM auth works is by passing a key inside of the HTTP headers to cpsrvd (cPanel’s HTTP daemon). Your access key can be accessed and regenerated via Setup Remote Access Keys in WHM, or viewed via the file system at ~/.accesshash. These work both for root and resellers with support for cPanel users coming in the future.

When sending a WHM auth header to WHM, you’ll need to add the following as an HTTP header:


Authorization: WHM $user:$hash

where $hash is your access hash, stripped of all new lines.

When working with this functionality inside of scripts, it’s generally easiest to use an HTTP library for adding these headers. For example, if you wanted to use WHM auth inside of PHP & curl, you would simply add the following to the curl object before query:

$hash = “81a ….. 0af”;		# Set up the Hash
$hash = preg_replace(‘(/r|/n)’, “”, $hash); # Strip newlines from the hash
$auth_header[0] = “Authorization: WHM $username:$hash”; # set up the Header Array
$curl_setopt($curl, CURLOPT_HTTPHEADER, $auth_header); # tell curl to use the header array

Of course, not everyone wants to use PHP for handling remote interactions, and I personally would not feel proper discussing how to authenticate to WHM without talking about Perl and LWP.

As always with Perl, there is more than one way to do it, so we will simply discuss the most simple. When calling LWP’s get function, you simply make the second argument a hash named “Authorization” with a value of something similar to

WHM $user:$hash.
my $access_hash = “81a … 0af”;	# set up the accesshash
$access_hash =~ s/(\n|\r)//g;	# Remove newlines from the accesshash
my $auth_string = “WHM $user:$access_hash”;	# create the authentication string
$response = $lwp->get( $url, Authorization => $auth_string ); # send auth header with req

At this point, you can treat $response like a normal HTTP::Response object.