2010-10-18 107 views
0

當您將PDT交易ID發回貝寶時,您將返回交易數據列表。它在第一行有SUCCESS,然後是鍵=值對列表。每行一對。例如:PHP:如何快速將密鑰=值文件分割爲關聯數組

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 

什麼是檢查第一行是否等於SUCCESS然後將其轉換爲關聯數組的好方法,快速而乾淨的方法?我能夠做到這一點,但它很有用,但我很好奇,如果有更好或更乾淨的做法,導致我最終結果並不總是那麼好。請注意,某些鍵也沒有任何值。

所以,我想直到結束本質是:

array(
    'business' => '[email protected]', 
    'charset' => 'windows-1252', 
    'custom' => NULL, 
    'first_name' => Alice, 

    // And so on 

); 

的順序並不重要。

更新:感謝您的偉大建議!現在測試它們。順便把字符串拆分成不同的行也是我的問題的一部分。忘了說明一下。看到有些人已經考慮到了這一點,有些則沒有。它可以產生影響,因爲某些方法需要首先分割成線條,然後再分割成兩條線,而另一些方法則可以將整個東西整體分割。

更新:我還應該提到,有空的結束爲NULL將是一個獎金,但可能不是必需的。他們在我的版本中也沒有這樣做,這並不重要。


基準測試結果

得到了好奇,我應該選擇這裏什麼,所以我爲基準我應該怎麼做不同的部分。我自己有各種各樣的想法,也從這裏和其他地方得到了一些。當我找到了我能夠管理的最快速度時,我創建了一個基準並針對迄今爲止的所有答案進行了測試。對於跳過分裂或成功檢查的人,我添加了一個explodestrpos相應的檢查。我還爲所有的解決方案添加了urldecode,除了@dynamism,他們很好地解決了這個問題。不管怎麼說,這裏的結果:

Benchmark results

基準是使用codebench 模塊運行。下面是基準代碼:

<?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", 
    ); 
} 

如果任何人有任何改進的進一步的建議,請讓我知道分開:)

+1

PHP將把「」和NULL作爲大多數操作是相同的,所以這不是什麼可擔心的。 – mellowsoon 2010-10-19 00:26:05

+0

是的,只是不要使用完全匹配('==='),它應該是好的。 – tonyhb 2010-10-19 00:30:07

回答

0

這是我怎麼會做它在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顯示爲''

編輯:另外,一個警告:如果數組鍵有任何特殊字符(由於某種奇怪的原因,可能是.)它會轉換爲_

+0

現在* *很有趣......在一百萬年內不會有這樣的東西:p – Svish 2010-10-19 01:17:36

+0

哦,這也照顧了urldecoding。已經忘記了這一點。好吧:) – Svish 2010-10-19 01:45:13

+1

'strpos($ subject,'SUCCESS')=== 0'比substr($ paypal,0,7)更快=='SUCCESS'' – Svish 2010-10-19 01:51:46

2

分裂出去的第一線,檢查它,然後用它來抓取休息:

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

之後$fields將是您尋求的數組。 (一個注意:響應中沒有值的項目將具有''而不是NULL。)

+1

通過使用2作爲explode()的第三個參數,即爆炸('=',$ line,2),你可以截取幾行代碼。這可以防止字符串被分成兩個以上的部分。 – mellowsoon 2010-10-19 00:24:59

0

使用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

從php.net - >如果你不需要正則表達式的力量,你可以選擇像explode()或str_split()那樣更快(儘管更簡單)的選擇。 – mellowsoon 2010-10-19 00:23:00

+0

@mellowsoon:有時正則表達式可能會更快,但很有可能不會在這種情況下,不會... – Svish 2010-10-19 01:29:41

0

下面的工作:

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

您是第一個將空值設置爲NULL的好主意:)如果線條具有空值,則不應跳過線條。另外,你應該爲爆炸極限加2。 – Svish 2010-10-19 01:55:27

0

添加我的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

這裏是一個更復雜的解決方案:

//$result=the result from paypal 
parse_str(str_replace(PHP_EOL,'&',$result),$result); 
var_dump($result); 
相關問題