PHP – Validate JSON

Here’s what I did to validate if the JSON is valid. I found tutorials on using json_last_error(), but I found this approach to be much simpler.

$arr_license = json_decode($_POST['json_license'], true);
if(empty($arr_license))
  exit('{"ReturnType":"Error", "ReturnCode":"101", "ReturnMessage":"json_license must be a valid JSON string."}');
//-- Proceed from here with valid $arr_license

PHP API Framework supporting multiple functions and arguments

Here’s a scalable framework to make API’s that support multiple functions. Each function in turn has mandatory and/or optional parameters. The parameters are combined to create a hash for security and it’s dynamically generated based on the function definition.

<?
define('SECRET', 'p24gvszaox6a1b2c392uewkyhezyqwk9');

class ApiFuncs {
	const FileDownload			=	'file-download';
	const FileAdd				=	'file-add';
	const MailSend				=	'mail-send';
	const FoldersList			=	'folders-list';
	const LastModFileFromFolder		=	'getLastModFileFromFolder';
	const AllFilesFromFolder		=	'getAllFilesFromFolder';
}

$INPUT_PARAMS = array (
	ApiFuncs::FileDownload	=> array('mandatory' => array('fileId')),
	ApiFuncs::FileAdd	=> array('mandatory' => array('fileContent','fileName','folderId')),
	ApiFuncs::MailSend	=> array('mandatory' => array('csv_fileIds', 'to', 'subject'),
							'optional' => array('message', 'cc', 'bcc')),
	ApiFuncs::FoldersList	=> array('mandatory' => array('folderId')),
	ApiFuncs::LastModFileFromFolder	=> array('mandatory' => array('folderId'),
						'optional' => array('fileExtension')),
	ApiFuncs::AllFilesFromFolder	=> array('mandatory' => array('folderId'),
						'optional' => array('fileExtension')),
);

validate();

//**************************************
//-- API Functions
//**************************************

function validate() {
	global $_POST, $INPUT_PARAMS;
	try {
		if(!array_key_exists('function', $_POST) || !array_key_exists($_POST['function'], $INPUT_PARAMS)) {
			exit(json_encode(getSimpleDictResponse(ReturnType::Error, ReturnCode::InvalidFunction)));
		}
		$token_params = $INPUT_PARAMS[$_POST['function']]['mandatory'];
		foreach($token_params as $key => $value) {
			if(!array_key_exists($value, $_POST)) {
				exit(json_encode(getSimpleDictResponse(ReturnType::Error, ReturnCode::MissingApiParam, $value)));
			}
		}
	}
	catch(Exception $e){
		exit(json_encode(getSimpleDictResponse(ReturnType::Error, ReturnCode::InvalidAPICall, $e)));
	}
	
	validate_values();
	verify_token();
}

function validate_values() {
	global $_POST, $INPUT_PARAMS;
	switch($_POST['function']) {
		case ApiFuncs::FileDownload:
			if(!preg_match('/^\d+$/',$_POST['fileId'])) {
				exit(json_encode(getSimpleDictResponse(ReturnType::Error, ReturnCode::InvalidFileId, $_POST['fileId'])));
			}
			break;
		default:
			break;
	}
}

function verify_token() {
	global $_POST, $INPUT_PARAMS, $SECRET;
	$token_params = $INPUT_PARAMS[$_POST['function']]['mandatory'];
	$hash = "function=".$_POST['function'];
	foreach($token_params as $key => $value) {
		$hash .= $value.'='.$_POST[$value];
	}
	$hash .= "secret=".SECRET;
	if(getSHA1Token($hash) != $_POST['token']) {
		exit(json_encode(getSimpleDictResponse(ReturnType::Error, ReturnCode::InvalidToken)));
	}
}
?>

PHP Functions – Order of Arguments Matters

I had multiple optional arguments to a function and I was trying to bypass an argument that I didn’t need (which was in the middle). So I invoked the function with explicitly loading the optional argument that I needed but now I understood that PHP doesn’t like it. PHP will only take in arguments in order so unfortunately you’ll have to list all arguments in case you would like to miss any.

// Function definition:
function file_add($filePath, $fileName, $folderId = NULL, &$log = NULL) {
   ...
   ...
}

// This will NOT work:
file_add($tmp_file, $fileName, $log = $log);

// This will work:
file_add($tmp_file, $fileName, $folderId = NULL, $log = $log);

Hash (sha512) of public_key in PHP and Python

I had a public_key generated by open ssl that was used to create a hash for encryption in PHP. But I had a hard time converting the equivalent in Python because that’s where I wanted to go. But sooner rather than later, I figured that out. Covered both examples here:

PHP Code:

$public_key = '-----BEGIN PUBLIC KEY-----
abcdMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0wSUI+wSKOqvpm79kNslxOw3D
OLi76AEqsB5w/mQETdpOU0hTGHKNBBIO3ZVzTks3FUs+NCfHuG3bUYW3ss8OjV8f
klmeq9Xt9HgMHH51nBvBQnNJ14q7KB1onH5oBnLpIA3Yo0Xc9F0CHTiRYZzObhij
PdTycTAn5RYg3gzWQwIDAQAB
-----END PUBLIC KEY-----'
$hash = hash("sha512", $public_key);
echo "$hash\n";

Python Code: The key here is to have \n\ at each terminating line in the key. \n denotes end of line character and \ denotes concatenation of string.

import hashlib
public_key = '-----BEGIN PUBLIC KEY-----\n\
abcdMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0wSUI+wSKOqvpm79kNslxOw3D\n\
OLi76AEqsB5w/mQETdpOU0hTGHKNBBIO3ZVzTks3FUs+NCfHuG3bUYW3ss8OjV8f\n\
klmeq9Xt9HgMHH51nBvBQnNJ14q7KB1onH5oBnLpIA3Yo0Xc9F0CHTiRYZzObhij\n\
PdTycTAn5RYg3gzWQwIDAQAB\n\
-----END PUBLIC KEY-----'
m = hashlib.sha512()
m.update(public_key)
print m.hexdigest()

Postgres – Dump data as INSERT SQL Statements

I wanted to get data from a production database into my local machine that didn’t have the same users, schema, etc. I created a local table and then used the pg_dump to dump out data as insert statements – that helped me out. Here’s what I used to dump data as insert statements:

pg_dump -U user_name -h localhost -t table_name --data-only --column-inserts db_name > data_dump.sql

Docusign PHP API – Send document to recipient for signature

Using Docusign PHP API’s to send documents for signature.

// Input your info here:
$integratorKey = 'abcd-1234567-xxxx-xxxx-xxxx-xxxxxxxxxx';
$email = 'yourlogin@org.com';
$password = 'yourP@ssword';

$recipient_email = 'varun.verma@accellion.com';
$name = 'Varun Verma';
$document_name = 'order_form.pdf';

// construct the authentication header:
$header = "<DocuSignCredentials><Username>" . $email . "</Username><Password>" . $password . "</Password><IntegratorKey>" . $integratorKey . "</IntegratorKey></DocuSignCredentials>";

/////////////////////////////////////////////////////////////////////////////////////////////////
// STEP 1 - Login (to retrieve baseUrl and accountId)
/////////////////////////////////////////////////////////////////////////////////////////////////
$url = "https://demo.docusign.net/restapi/v2/login_information";
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("X-DocuSign-Authentication: $header"));

$json_response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

if ( $status != 200 ) {
	echo "error calling webservice, status is:" . $status;
	exit(-1);
}

$response = json_decode($json_response, true);
$accountId = $response["loginAccounts"][0]["accountId"];
$baseUrl = $response["loginAccounts"][0]["baseUrl"];
curl_close($curl);

//--- display results
echo "\naccountId = " . $accountId . "\nbaseUrl = " . $baseUrl . "\n";

/////////////////////////////////////////////////////////////////////////////////////////////////
// STEP 2 - Create an envelope with one recipient, one tab, one document and send!
/////////////////////////////////////////////////////////////////////////////////////////////////
$data = "{
  \"emailBlurb\":\"This comes from PHP\",
  \"emailSubject\":\"DocuSign API - Please Sign This Document...\",
  \"documents\":[
    {
      \"documentId\":\"1\",
      \"name\":\"".$document_name."\"
    }
  ],
  \"recipients\":{
    \"signers\":[
      {
        \"email\":\"$recipient_email\",
        \"name\":\"$name\",
        \"recipientId\":\"1\",
        \"tabs\":{
          \"signHereTabs\":[
            {
              \"anchorString\":\"Signature:\",
              \"anchorXOffset\":\"0\",
              \"anchorYOffset\":\"0\",
              \"documentId\":\"1\",
              \"pageNumber\":\"1\"
            }
          ]
        }
      }
    ]
  },
  \"status\":\"sent\"
}";  

$file_contents = file_get_contents($document_name);

$requestBody = "\r\n"
."\r\n"
."--myboundary\r\n"
."Content-Type: application/json\r\n"
."Content-Disposition: form-data\r\n"
."\r\n"
."$data\r\n"
."--myboundary\r\n"
."Content-Type:application/pdf\r\n"
."Content-Disposition: file; filename=\"order_form.pdf\"; documentid=1 \r\n"
."\r\n"
."$file_contents\r\n"
."--myboundary--\r\n"
."\r\n";

// *** append "/envelopes" to baseUrl and as signature request endpoint
$curl = curl_init($baseUrl . "/envelopes" );
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $requestBody);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
	'Content-Type: multipart/form-data;boundary=myboundary',
	'Content-Length: ' . strlen($requestBody),
	"X-DocuSign-Authentication: $header" )
);

$json_response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ( $status != 201 ) {
	echo "error calling webservice, status is:" . $status . "\nerror text is --> ";
	print_r($json_response); echo "\n";
	exit(-1);
}

$response = json_decode($json_response, true);
$envelopeId = $response["envelopeId"];

//--- display results
echo "Document is sent! Envelope ID = " . $envelopeId . "\n\n";