A string parameter is passed to the function – below are various samples of possible input data The function receives this data as a string, not an array, json or other data formats The function should parse the string and mask sensitive data. Sensitive data should be masked (replaced) with an Asterix (*) character. Sensitive data includes the fields below, but new sensitive fields should be easily added to the function as needed:
The credit card number
The credit card expiry date
The credit card CVV value
The function returns the parsed string in the same format that it was provided, but with the sensitive data now masked.
<?php
$testData1 = "[orderId] => 212939129
[orderNumber] => INV10001
[salesTax] => 1.00
[amount] => 21.00
[terminal] => 5
[currency] => 1
[type] => purchase
[avsStreet] => 123 Road
[avsZip] => A1A 2B2
[customerCode] => CST1001
[cardId] => 18951828182
[cardHolderName] => John Smith
[cardNumber] => 5454545454545454
[cardExpiry] => 1025
[cardCVV] => 100";
$testData2 = "Request=Credit Card.Auth Only&Version=4022&HD.Network_Status_Byte=*&HD.Application_ID=TZAHSK!&HD."
. "Terminal_ID=12991kakajsjas&HD.Device_Tag=000123&07."
. "POS_Entry_Capability=1&07.PIN_Entry_Capability=0&07.CAT_Indicator=0&07."
. "Terminal_Type=4&07.Account_Entry_Mode=1&07.Partial_Auth_Indicator=0&07.Account_Card_Number="
. "4242424242424242&07.Account_Expiry=1024&07.Transaction_Amount=142931&07."
. "Association_Token_Indicator=0&17.CVV=200&17.Street_Address=123 Road SW&17.Postal_Zip_Code=90210&17.Invoice_Number=INV19291";
$testData3 = '{
"MsgTypId": 111231232300,
"CardNumber": "4242424242424242",
"CardExp": 1024,
"CardCVV": 240,
"TransProcCd": "004800",
"TransAmt": "57608",
"MerSysTraceAudNbr": "456211",
"TransTs": "180603162242",
"AcqInstCtryCd": "840",
"FuncCd": "100",
"MsgRsnCd": "1900",
"MerCtgyCd": "5013",
"AprvCdLgth": "6",
"RtrvRefNbr": "1029301923091239",
}';
$testData4 = "<?xml version='1.0' encoding='UTF-8'?>
<Request>
<NewOrder>
<IndustryType>MO</IndustryType>
<MessageType>AC</MessageType>
<BIN>000001</BIN>
<MerchantID>209238</MerchantID>
<TerminalID>001</TerminalID>
<CardBrand>VI</CardBrand>
<CardDataNumber>5454545454545454</AccountNum>
<Exp>1026</Exp>
<CVVCVCSecurity>300</Exp>
<CurrencyCode>124</CurrencyCode>
<CurrencyExponent>2</CurrencyExponent>
<AVSzip>A2B3C3</AVSzip>
<AVSaddress1>2010 Road SW</AVSaddress1>
<AVScity>Calgary</AVScity>
<AVSstate>AB</AVSstate>
<AVSname>JOHN R SMITH</AVSname>
<OrderID>23123INV09123</OrderID>
<Amount>127790</Amount>
</NewOrder>
</Request>";
$parseNew = array("name", "amt", "amount"); //some optional fields to parse
//this function will take a provided string, $data, and replace all credit card information including 16-digit numbers, expiry dates and 3-digit CVV numbers.
//$parseNew is an optional field to parse other sensitive information that matches the type of information entered into $parseNew, such as the transaction amount.
//if the strings in $parseNew matches any field in the data given, then that data will be parsed as well
//assign each piece of given test data to a variable for each to be passed into helcimTest
function helcimTest($data, $parseNew) {
$lines = explode("
", $data); //split data by new lines into an array
if (count($lines) == 1) { //if there aren't any new lines, then periods are used
$lines = explode(".", $data); //different splits can also be added with another if, like a ,
//print_r($lines);
}
for ($currLine = 0; $currLine < count($lines); $currLine++) { //loop through the lines and check for credit card information keywords as well as if theres any matches in $parseNew
$nonos = array("cvv", "exp", "expiry", "expire", "CVV", "Exp"); //keywords of default fields to be parsed, credit card numbers need to be searched for differently
$nonos = array_merge($nonos, $parseNew); //take optional parse data types and add it to array of default credit card data types
//checking credit card number first
$cardPos = strpos($lines[$currLine], "card"); //find "card" as part of Card Number
if ($cardPos === false) {
$cardPos = strpos($lines[$currLine], "Card");
}
if ($cardPos > 0) { //if "card" is in the line, we check if "number" is also
$numberPos = strpos($lines[$currLine], "Number");
if ($numberPos === false) {
$numberPos = strpos($lines[$currLine], "number");
}
if ($numberPos > 0) {
$matches = array();
preg_match_all('!\d+!', $lines[$currLine], $matches); //grabs all numbers in the line and throws them in an array
$numberLength = 0;
$digits = $matches[0]; //unpack array inside matches array
for ($i = 0; $i < count($digits); $i++) {
if (strlen($digits[$i]) == 16) {
$theNumber = $digits[$i];
$numberLength = strlen($digits[$i]);
}
}
if ($numberLength == 16) { //when all of these things are true then this number is definitely a credit card number
$lines[$currLine] = str_replace($theNumber, "****************", $lines[$currLine]);
//print_r($lines);
}
}
}
//credit card number check complete
//now to check for everythign else
for ($i = 0; $i < count($nonos); $i++) {
$currNono = $nonos[$i]; //current type of data we are looking to parse
if(strpos($lines[$currLine], $currNono) > 0){ //check to see if current parsing field exists on current line
preg_match_all("/\d+\.\d+|\d+|[A-Za-z]+/", $lines[$currLine], $matches);
$sensData = $matches[0]; //unpack array from wihtin another array
print_r($sensData);
for($f = 0; $f < count($sensData); $f++){ //if we find any fields we want to parse
if (strcmp($sensData[$f], $currNono) == true && $f+1 != count($sensData)){
$hash = str_repeat("*", strlen($sensData[$f+1]));
$lines[$currLine] = str_replace($sensData[$f+1], $hash, $lines[$currLine]);
}
}
}
}
}
print_r($lines);
}
echo "Data set 1:
"; //print results
helcimTest($testData1, $parseNew);
echo "Data set 2:
";
helcimTest($testData2, $parseNew);
echo "Data set 3:
";
helcimTest($testData3, $parseNew);
echo "Data set 4:
";
helcimTest($testData4, $parseNew);
The output appears as such, some of the values are correctly parsed, and some feel totally random. The first part of the function handles the credit card number alone, which is consistently parsed correctly, it's when the function reaches its bottom half that the patterns I've laid out just don't make any sense when compared to the results:
Data set 1:
Array
(
[0] => amount
[1] => 21.00
)
Array
(
[0] => cardExpiry
[1] => 1025
)
Array
(
[0] => cardCVV
[1] => 100
)
Array
(
[0] => [orderId] => 212939129
[1] => [orderNumber] => INV10001
[2] => [salesTax] => 1.00
[3] => [amount] => 21.00
[4] => [terminal] => 5
[5] => [currency] => 1
[6] => [type] => purchase
[7] => [avsStreet] => 123 Road
[8] => [avsZip] => A1A 2B2
[9] => [customerCode] => CST1001
[10] => [cardId] => 18951828182
[11] => [cardHolderName] => John Smith
[12] => [cardNumber] => ****************
[13] => [cardExpiry] => ****
[14] => [cardCVV] => ***
)
Data set 2:
Array
(
[0] => Account
[1] => Expiry
[2] => 1024
[3] => 07
)
Array
(
[0] => Request=Credit Card
[1] => Auth Only&Version=4022&HD
[2] => Network_Status_Byte=*&HD
[3] => Application_ID=TZAHSK!&HD
[4] => Terminal_ID=12991kakajsjas&HD
[5] => Device_Tag=000123&07
[6] => POS_Entry_Capability=1&07
[7] => PIN_Entry_Capability=0&07
[8] => CAT_Indicator=0&07
[9] => Terminal_Type=4&07
[10] => Account_Entry_Mode=1&07
[11] => Partial_Auth_Indicator=0&07
[12] => Account_Card_Number=****************&07
[13] => Account_******=****&**
[14] => Transaction_Amount=142931&07
[15] => Association_Token_Indicator=0&17
[16] => CVV=200&17
[17] => Street_Address=123 Road SW&17
[18] => Postal_Zip_Code=90210&17
[19] => Invoice_Number=INV19291
)
Data set 3:
Array
(
[0] => CardExp
[1] => 1024
)
Array
(
[0] => CardCVV
[1] => 240
)
Array
(
[0] => {
[1] => "MsgTypId": 111231232300,
[2] => "CardNumber": "****************",
[3] => "CardExp": ****,
[4] => "CardCVV": ***,
[5] => "TransProcCd": "004800",
[6] => "TransAmt": "57608",
[7] => "MerSysTraceAudNbr": "456211",
[8] => "TransTs": "180603162242",
[9] => "AcqInstCtryCd": "840",
[10] => "FuncCd": "100",
[11] => "MsgRsnCd": "1900",
[12] => "MerCtgyCd": "5013",
[13] => "AprvCdLgth": "6",
[14] => "RtrvRefNbr": "1029301923091239",
[15] => }
)
Data set 4:
Array
(
[0] => Exp
[1] => 1026
[2] => Exp
)
Array
(
[0] => CVVCVCSecurity
[1] => 300
[2] => Exp
)
Array
(
[0] => CurrencyExponent
[1] => 2
[2] => CurrencyExponent
)
Array
(
[0] => AVSname
[1] => JOHN
[2] => R
[3] => SMITH
[4] => AVSname
)
Array
(
[0] => <?xml version='1.0' encoding='UTF-8'?>
[1] => <Request>
[2] => <NewOrder>
[3] => <IndustryType>MO</IndustryType>
[4] => <MessageType>AC</MessageType>
[5] => <BIN>000001</BIN>
[6] => <MerchantID>209238</MerchantID>
[7] => <TerminalID>001</TerminalID>
[8] => <CardBrand>VI</CardBrand>
[9] => <CardDataNumber>****************</AccountNum>
[10] => <***>1026</***>
[11] => <CVVCVCSecurity>***</***>
[12] => <CurrencyCode>124</CurrencyCode>
[13] => <****************>*</****************>
[14] => <AVSzip>A2B3C3</AVSzip>
[15] => <AVSaddress1>2010 Road SW</AVSaddress1>
[16] => <AVScity>Calgary</AVScity>
[17] => <AVSstate>AB</AVSstate>
[18] => <*******>**** * *****</*******>
[19] => <OrderID>23123INV09123</OrderID>
[20] => <Amount>127790</Amount>
[21] => </NewOrder>
[22] => </Request>
)