PHP: Как быстро разбить файл ключ = значение на ассоциативный массив - PullRequest
0 голосов
/ 19 октября 2010

Когда вы отправляете идентификатор транзакции PDT обратно в PayPal, вы получаете список данных транзакции.В первой строке указывается SUCCESS, а затем список пар ключ = значение.Одна пара на линию.Например:

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

Что такое хороший, быстрый и чистый способ проверить, равна ли первая строка УСПЕХУ, а затем преобразовать ее в ассоциативный массив?Я могу сделать это, и это работает, но мне любопытно, есть ли лучшие или более чистые способы сделать это, потому что то, что я получаю, не всегда так приятно.Обратите внимание, что некоторые ключи также не имеют никакого значения.

Итак, я хотел бы закончить по существу:

array(
    'business' => 'paypal@example.com',
    'charset' => 'windows-1252',
    'custom' => NULL,
    'first_name' => Alice,

    // And so on

);

Порядок не имеет значения.

Обновление: Спасибо за отличные предложения!Тестирую их сейчас.Кстати, разделение строки на отдельные строки также является частью моей проблемы.Забыл уточнить это.Видите, что некоторые приняли это во внимание, а некоторые нет.Это может оказать влияние, поскольку некоторые методы должны сначала разбиваться на строки, а затем пары, в то время как другие могут просто съесть все это одним куском.

Обновление: Я также должен был упомянуть, что наличие пустых в конечном итоге NULL будет бонусом, но, вероятно, не обязательным требованием.Они не делают этого и в моей версии, и это не имеет большого значения.


Результаты тестов

Мне стало интересно, что я должен выбрать здесь, поэтомуЯ показал, как я должен делать разные части.У меня были разные идеи, я получил их отсюда и в других местах.Когда я нашел самый быстрый способ управления, я создал эталонный тест и проверил его на соответствие всем ответам.Для тех, кто пропустил разбиение или проверку на успех, я добавил проверки explode и strpos соответственно.Я также добавил urldecode ко всем решениям, кроме @dynamism, который так хорошо с этим справился.В любом случае, вот результаты:

Benchmark results

Тест был выполнен с использованием модуля codebench Kohana 3 .Вот эталонный код:

<?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\nbusiness=paypal@business.example.com\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\npayer_email=alice.foobar@example.com\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\nreceiver_email=paypal@example.com\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",
    );
}

Если у кого-нибудь есть какие-либо дополнительные советы по улучшению, пожалуйста, дайте мне знать:)

Ответы [ 6 ]

2 голосов
/ 19 октября 2010

Разделите первую строку отдельно, проверьте ее, а затем используйте эту команду, чтобы взять остальные:

foreach($response_lines as $line) {
    $bits = explode('=', $line);
    $field_name = array_shift($bits);
    $field_contents = implode('=', $bits);
    $fields[$field_name] = $field_contents;
}

После чего $fields будет массив, который вы ищете. (Одно примечание: элементы без значения в ответе будут иметь '' вместо NULL.)

0 голосов
/ 19 октября 2010

Вот более сложное решение:

//$result=the result from paypal
parse_str(str_replace(PHP_EOL,'&',$result),$result);
var_dump($result);
0 голосов
/ 19 октября 2010

Добавление 2 моих центов, потому что некоторые из опубликованных решений слишком умны или не на 100% правильны.

$lines = explode("\n", $paypal_response);
$lines = array_map('trim', $lines);
$status = array_shift($lines);
if ($status != 'SUCCESS') {
    // Transaction was not successful
}
$values = array();
foreach($lines as $line) {
    list($key, $value) = explode('=', $line, 2);
    $values[$key] = $value;
}
0 голосов
/ 19 октября 2010

Будет работать следующее:

foreach($response as $line) {
    if (strpos($line, "=") === FALSE) { continue; }   // Skip the line if there's no assignment action going on.
    list($var, $value) = explode("=", trim($line));   // Get the parts on either side of the "=".
    $result[$var] = (empty($value) ? NULL : $value);  // Assign the value to the result array, making the value NULL if it's empty.
}
0 голосов
/ 19 октября 2010

использование http://www.php.net/manual/en/function.preg-split.php

foreach($lines as $line) {
    $lineData = preg-split("\s*=\s*",$line);
    if(count($lineData)==2) {
         $result[$lineData[0]] = $lineData[1];
    }
}
0 голосов
/ 19 октября 2010

Вот как я бы сделал это в 5 строк:

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

Проверьте, успешен ли постбэк $paypal, и если он удаляет первую строку, замените символы новой строки на & затем запустить его через parse_str, отсортировано.Выходные данные находятся в $response_array, готовом к работе.

Та же проблема, что и у Амбер, где NULL отображается как ''.

Редактировать: Также предостережение: Если массивВ ключе есть какие-либо специальные символы (по какой-то странной причине, может быть, .), он преобразуется в _.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...