What do to when encountering the shell_exec() error in Windows environment

Well, I’m back with this week, but with a different tutorial to address an overlooked error.  We’re going to answer a few questions for those of you that use a Windows development environment.

I’m surprise this issue has not surfaced before now.  Nevertheless, I had the pleasure of engaging a Pastor from the CCB Tutorials community (that’s right, this community) about a few tutorials *not working* (oh no!).

He and I hopped on a quick GoToMeeting, so that I could size up the issue and be certain that it was not a simple fix.

And what do you know! Using Windows 10 and XAMP, he executed code from both Part II and Part III of how to search for an individual, and was presented the following error:

error: shell_exec() curl command failed

Honestly, this error never registered with me because I’m a Mac user 90% of the time. In fact, it took me roughly 3 hours to think long and hard about the error encountered in our GoToMeeting session.

Again, he stated that he could get Part I to execute, but not Part II and III. The light bulb should have gone off for me at that moment, but it didn’t at the time.

However, my light bulb did come on hours later. I realized that the code used for creating reusable functions was primarily focused on Linux/Unix dev enivronments.

Ole’ pesky Windows not wanting to play fair. Truth be told, its completely my fault for not providing both methods in the code, which is why I’m writing this tutorial today. Let’s get started with how to remedy this issue.

Determine which environment is running

The first thing we’ll do is determine which environment you’re running by creating a PHP function that can be reused and included inside of the general.php.

So, crack open a text editor and let’s begin by opening the general.php file in the includes directory. You’ll want to name this function devEnvironment.

Once successfully created, then define debug as a variable and make the value equal to 0. Now create an if statement using the debug variable. Inside the if statement, echo both the php_uname method and PHP_OS method.

Both are built-in php methods for returning the description of operating system PHP is running on, having a long description and a short description respectively. Now close the if statement.

This block of code you just created is used to print the operating system PHP is running on when the debug variable is equal to 1.

Okay now we’re ready for the final if else statement.  This statement uses both strotoupper and substr to determine if the PHP_OS is equal to WIN string.

Simply put, if it’s WIN, then return the string WIN, short for Windows. If not, then return the string LIN, short for Linux.

<?PHP

// this function returns either WIN or LIN based on the development environment operating system
function devEnvironment(){

/* Some possible outputs:
Linux localhost 2.4.21-0.13mdk #1 Fri Mar 14 15:08:06 EST 2003 i686
Linux

FreeBSD localhost 3.2-RELEASE #15: Mon Dec 17 08:46:02 GMT 2001
FreeBSD

Windows NT XN1 5.1 build 2600
WINNT
*/

// to have output echo to web broswer, change debug to 1
$debug = 0;

if($debug){
    echo php_uname();
    echo PHP_OS;
}

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
    return 'WIN';
} else {
    return 'LIN';
}

}

?>

 

Restructuring ccbDetails function in general.php based on development environment

Quickly, I’m not covering the ins and outs of making the curl call, so you’ll have to look back at Part I and Creating a reusable function for CCB API calls tutorials for in-depth description. Be sure to read both tutorials and pay close attention to their code comments to learn what’s happening.

To restructure your current ccbDetails function, define a devEnv variable and set it equal to the newly created devEnvironment function (see last section).

Make this code addition after the line of code that checks to be sure we have apiUsername, apiPassword and baseAPIUrl variables properly defined.

Now it’s time to define the query_string, url and objData variables as we did in the previous tutorial.

After the objData variable has been defined, create an if else statement that checks to see if the devEnv variable IS NOT equal to the string WIN.

Simply put, we want the first section of this if else statement to run if the environment it’s executing in is not Windows.

In the if section of code, place the previous ccbDetails function’s if posttype statement and output variable.

In the else section of this if statement, place the if posttype statements, query_header, curl call statements, output variable and curl_close statements. Then close the if else statement.

Remaining is the logic to check that there is still output. The only change with the output if else statement is checking for the operating system once more to indicate which error message, whether Windows or Linux, should be displayed to web browser.

Return the response_object and all should be well (*fingers crossed*).  Save the file, and we’re ready to test.

<?PHP


// ccbDetails function to post to and get data from CCB using PHP/CURL
function ccbDetails($posttype,$paramdata,$servdata=NULL){

// set global variables
global $apiUsername, $apiPassword, $baseAPIUrl;

// set error checking of global variables. if any are empty, die on the spot and display error message to web browser
if (!$apiUsername || !$apiPassword || !$baseAPIUrl) die('Error: CCB API details missing.');

// before we go too far here... let's make sure you make the right call based on your development environment
$devEnv = devEnvironment();
	
// remember http_build_query, well it's back
$query_string = http_build_query($paramdata);

$service_string = '';

if(!empty($servdata))
    $service_string = http_build_query($servdata);

// this is the get url variable consisting of baseAPIUrl, ?, and our data fields built as an URL encoded string
$url = $baseAPIUrl.'?'.$query_string;
$objData = '';

if(!empty($servdata))
    $objData = $service_string;


// if not a windows environment
if($devEnv != 'WIN'){

// this means that the environment is a Linux / Unix / MAC
// this is the post url variable
if($posttype == 'post'){
 
    $url = $baseAPIUrl.'?'.$service_string;
    $objData = $query_string;
 
}
 
// time to make PHP/CURL call using shell_exec command and CCB API curl
$output = shell_exec('curl -k -u '.$apiUsername.':'.$apiPassword.' -d "'.$objData.'" "'.$url.'"');
 

} else {

// this means that the environment is a Windows
// this statement will replace the url variable if the second argument posttype is set to post
if($posttype == 'post') 
    $url = $baseAPIUrl.'?'.$service_string;

// set get header value to array 0
$query_header = array('0');

/*
// when making a post call, you'll need to set the $query_header array with Accept, Connection and Content-type Headers
if($posttype == 'post'){

    $query_header[] =array();
    $query_header[] = 'Accept: image/gif, image/x-bitmap, image/jpeg, image/pjpeg';
    $query_header[] = 'Content-type: application/x-www-form-urlencoded;charset=UTF-8';
    $query_header[] = 'Connection: Keep-Alive';

} */

// Read up more on the curl_setopt options here: 
// now we're ready to initiate the curl call using the $ch variable
$ch = curl_init();

// basic authentication
curl_setopt($ch,CURLOPT_HTTPAUTH, CURLAUTH_BASIC);

// and don't forget that we need user credentials when making a CCB API call using PHP/CURL
curl_setopt($ch,CURLOPT_USERPWD, $apiUsername . ':' . $apiPassword);

// simply return the transfer as a string when set to one
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); 

// set CURLOPT_CONNECTTIMEOUT to 5 seconds to wait before trying to reconnect
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,5);

// since CCB API using https, we set the CURLOPT_PORT to 443
curl_setopt($ch,CURLOPT_PORT, 443);

// don't verify ssl certificate
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0); 

// do verify ssl common hostname match
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,2); 

// we set the CURLOPT_URL using the $url variable created in previous steps
curl_setopt($ch,CURLOPT_URL,$url);

// header for either get or post
curl_setopt($ch, CURLOPT_HTTPHEADER, $query_header);

// if posttype is post, set the CURLOPT_POST to true using 1
if($posttype == 'post')  
    curl_setopt($ch,CURLOPT_POST,1); 

// if posttype is post, set the CURLOPT_POSTFIELDS using the $query_string variable
if($posttype == 'post') 
    curl_setopt($ch,CURLOPT_POSTFIELDS, $query_string); 

// now we're ready to execute the $ch variable and return the content
$output = curl_exec($ch);

// time to close the connection to free up resources
curl_close($ch);

}

// output then let's start additional logic to parse and display output to web browser; if not output response, then error and die.
if($output){

$response_object = ''; // reset $response_object
 
$response_object = new SimpleXMLElement($output); // transform to XML
 
} else {

    $response_object = 'WINDOWS Error: curl_exec() command failed.';
    if($devEnv != 'WIN')
        $response_object = 'LINUX Error: shell_exec() command failed.';

    die($response_object);

}

return $response_object;
}

?>

And that’s it! You’ve now remedied the shell_exec() error in a Windows environment

Your code should now execute with ease. Should it not, then please do not hesitate to send me an email or use the contact form on the Contact page.

Related Posts

Subscribe and receive the following...

  • Inside CCB tips and tricks
  • Instant CCB tutorial alerts and updates
  • CCB How To's, Videos, Webinars and more...