When you send a PDT transaction ID back to paypal, you get back a list of transaction data. It has SUCCESS on the first line, and then a list of key=value pairs. One pair per line. For example:
SUCCESS
[email protected]
charset=windows-1252
custom=
first_name=Alice
handling_amount=0.00
invoice=NN0005
item_name=Bear
item_number=BEAR05
last_name=Foobar
mc_currency=SEK
mc_fee=13.00
mc_gross=250.00
[email protected]
payer_id=UC9DXVX7GRSTN
payer_status=unverified
payment_date=09:08:06 Oct 18, 2010 PDT
payment_fee=
payment_gross=
payment_status=Completed
payment_type=instant
protection_eligibility=Ineligible
quantity=1
receipt_id=2479-2605-1192-2880
[email protected]
receiver_id=8Y670ENTB8BY6
residence_country=NO
shipping=0.00
tax=0.00
transaction_subject=Bear
txn_id=1PH815997L239283J
txn_type=web_accept
What is a good, quick and clean way to check if the first line equals SUCCESS and then convert this into an associative array? I am able to do it, and it works, but I'm curious if there are better or cleaner ways of doing it cause what I end up with isn't always that nice. Notice that some of the keys don't have any value as well.
So, what I would like to end up with is essentially:
array(
'business' => '[email protected]',
'charset' => 'windows-1252',
'custom' => NULL,
'first_name' => Alice,
// And so on
);
The order doesn't matter.
Update: Thanks for great suggestions! Testing them out now. Splitting the string into separate lines is also part of my problem by the way. Forgot to specify that. See that some has taken that into account and some don't. It can have an impact, since certain methods needs to first split into lines and then the pairs, while others can just eat the whole thing in one piece.
Update: I should also have mentioned that having empty ones end up as NULL would be a bonus, but probably not a requirement. They don't do that in my version either and it doesn't really matter that much.
Benchmark results
Got curious to what I should choose here, so I benchmarked how I should do different parts. Had various ideas myself, got some from here and other places as well. When I had found the fastest I could manage, I created a benchmark and put it to the test against all of the answers so far. For the ones that had skipped the splitting or the checking for success I added an explode
and a strpos
check accordingly. I also added urldecode to all the solutions as well, except @dynamism who tackled that so nicely. Anyways, here are the results:
The benchmark was run using the codebench Kohana 3 module. Here is the benchmark code:
<?php defined('SYSPATH') or die('No direct script access.');
/**
* Test various methods of checking for SUCCESS
*
* @package PayPal
* @category PDT
* @author Torleif Berger
*/
class Bench_ProcessPDT extends Codebench
{
public $description = 'Various ways of checking that a string starts with SUCCESS';
public $loops = 100000;
public function bench_mine($subject)
{
if(strpos($subject, 'SUCCESS') === 0)
{
$subject = urldecode(substr($subject, 7));
preg_match_all('/^([^=]++)=(.*+)/m', $subject, $result, PREG_PATTERN_ORDER);
$result = array_combine($result[1], $result[2]);
return array(count($result), array_shift($result), array_shift($result));
}
return FALSE;
}
// http://stackoverflow.com/questions/3964219/3964308#3964308
public function bench_dynamism_substr($subject)
{
if(substr($subject, 0, 7) == 'SUCCESS')
{
$subject = substr_replace($subject, '', 0, 7);
$subject = str_replace(array("\n", "\r", "\r\n"), '&', $subject);
parse_str($subject, $result);
return array(count($result), array_shift($result), array_shift($result));
}
return FALSE;
}
// http://stackoverflow.com/questions/3964219/3964308#3964308
public function bench_dynamism_strpos($subject)
{
if(strpos($subject, 'SUCCESS') === 0)
{
$subject = substr_replace($subject, '', 0, 7);
$subject = str_replace("\r\n", '&', $subject);
parse_str($subject, $result);
return array(count($result), array_shift($result), array_shift($result));
}
return FALSE;
}
// http://stackoverflow.com/questions/3964219/3964520#3964520
public function bench_mellowsoon($subject)
{
$subject = urldecode($subject);
$lines = explode("\r\n", $subject);
$lines = array_map('trim', $lines);
$status = array_shift($lines);
if($status == 'SUCCESS')
{
$result = array();
foreach($lines as $line)
{
list($key, $value) = explode('=', $line, 2);
$result[$key] = $value;
}
return array(count($result), array_shift($result), array_shift($result));
}
return FALSE;
}
// http://stackoverflow.com/questions/3964219/3964265#3964265
public function bench_amber($subject)
{
if(strpos($subject, 'SUCCESS') === 0)
{
$subject = explode("\r\n", urldecode($subject));
array_shift($subject); // Remove is empty
$result = array();
foreach($subject as $line)
{
$bits = explode('=', $line);
$field_name = array_shift($bits);
$field_contents = implode('=', $bits);
$result[$field_name] = $field_contents;
}
return array(count($result), array_shift($result), array_shift($result));
}
return FALSE;
}
// http://stackoverflow.com/questions/3964219/3964366#3964366
public function bench_GigaWatt($subject)
{
if(strpos($subject, 'SUCCESS') === 0)
{
$subject = explode("\r\n", urldecode($subject));
$result = array();
foreach($subject as $line)
{
if (strpos($line, "=") === FALSE)
continue;
list($var, $value) = explode("=", trim($line));
$result[$var] = empty($value) ? NULL : $value;
}
return array(count($result), array_shift($result), array_shift($result));
}
return FALSE;
}
// http://stackoverflow.com/questions/3964219/3964366#3964366
public function bench_GigaWatt2($subject)
{
if(strpos($subject, 'SUCCESS') === 0)
{
$subject = explode("\r\n", urldecode($subject));
$result = array();
foreach($subject as $line)
{
if (strpos($line, "=") === FALSE)
continue;
list($var, $value) = explode("=", trim($line));
$result[$var] = $value;
}
return array(count($result), array_shift($result), array_shift($result));
}
return FALSE;
}
// http://stackoverflow.com/questions/3964219/3964323#3964323
public function bench_dvhh($subject)
{
if(strpos($subject, 'SUCCESS') === 0)
{
$subject = explode("\r\n", urldecode($subject));
$result = array();
foreach($subject as $line)
{
$lineData = preg_split("/\s*=\s*/", $line);
if(count($lineData) == 2)
{
$result[$lineData[0]] = $lineData[1];
}
}
return array(count($result), array_shift($result), array_shift($result));
}
return FALSE;
}
public $subjects = array
(
"SUCCESS\r\[email protected]\r\ncharset=windows-1252\r\ncustom=\r\nfirst_name=Alice\r\nhandling_amount=0.00\r\ninvoice=AF000001\r\nitem_name=Stuffed bear\r\nitem_number=BEAR05\r\nlast_name=Foobar\r\nmc_currency=USD\r\nmc_fee=2.00\r\nmc_gross=20.00\r\[email protected]\r\npayer_id=UC9DXVX7GRSTN\r\npayer_status=unverified\r\npayment_date=09:08:06 Oct 18, 2010 PDT\r\npayment_fee=\r\npayment_gross=\r\npayment_status=Completed\r\npayment_type=instant\r\nprotection_eligibility=Ineligible\r\nquantity=1\r\nreceipt_id=2479-2605-1192-2880\r\[email protected]\r\nreceiver_id=8Y670ENTB8BY6\r\nresidence_country=USD\r\nshipping=0.00\r\ntax=0.00\r\ntransaction_subject=Bear\r\ntxn_id=1PH815997L239283J\r\ntxn_type=web_accept",
"FAIL\r\nError: 4003",
"INVALID",
);
}
If anyone has any further tips for improvement, please let me know :)