dongzhang2150 2010-10-18 23:17
浏览 70
已采纳

PHP:如何快速将key = value文件拆分为关联数组

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
business=paypal@example.com
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
payer_email=bob@example.com
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
receiver_email=paypal@example.com
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' => 'paypal@example.com',
    '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:

Benchmark 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("
", "", "
"), '&', $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("
", '&', $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("
", $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("
", 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("
", 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("
", 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("
", 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
business=paypal@business.example.com
charset=windows-1252
custom=
first_name=Alice
handling_amount=0.00
invoice=AF000001
item_name=Stuffed bear
item_number=BEAR05
last_name=Foobar
mc_currency=USD
mc_fee=2.00
mc_gross=20.00
payer_email=alice.foobar@example.com
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
receiver_email=paypal@example.com
receiver_id=8Y670ENTB8BY6
residence_country=USD
shipping=0.00
tax=0.00
transaction_subject=Bear
txn_id=1PH815997L239283J
txn_type=web_accept",

        "FAIL
Error: 4003",

        "INVALID",
    );
}

If anyone has any further tips for improvement, please let me know :)

  • 写回答

6条回答 默认 最新

  • doutan8601 2010-10-18 23:35
    关注

    This is how I'd do it in 5 lines:

    // Is this a successful post?
    if( substr($paypal, 0, 7) == 'SUCCESS')
    {
        $paypal = substr_replace($paypal, '', 0, 7);
        $paypal = str_replace(array("
    ", "", "
    "), '&', $paypal);
        parse_str($paypal, $response_array);
    }
    

    Check to see if the postback $paypal is successful, and if it is remove the first line, replace newlines with & then run it through parse_str, sorted. Output is in $response_array ready to rock.

    Same problem as Amber, though, where NULL is shown as ''.

    Edit: Also, a caveat: If the array key has any special characters in it (for some strange reason, maybe a .) it is converted to an _.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(5条)

报告相同问题?

悬赏问题

  • ¥15 #MATLAB仿真#车辆换道路径规划
  • ¥15 java 操作 elasticsearch 8.1 实现 索引的重建
  • ¥15 数据可视化Python
  • ¥15 要给毕业设计添加扫码登录的功能!!有偿
  • ¥15 kafka 分区副本增加会导致消息丢失或者不可用吗?
  • ¥15 微信公众号自制会员卡没有收款渠道啊
  • ¥100 Jenkins自动化部署—悬赏100元
  • ¥15 关于#python#的问题:求帮写python代码
  • ¥20 MATLAB画图图形出现上下震荡的线条
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘