2010-05-28 29 views
5

Tôi đã gặp sự cố hôm nay khi tôi chuyển một khóa có giá trị được đặt thành một mảng trống đến http_build_query(). Ví dụ:http_build_query bỏ qua khóa nếu giá trị là một mảng trống. Làm thế nào đây không phải là một lỗi?

$args = array("foo", "bar", array(), "baz"); 
$qs = http_build_query($args); 
echo $qs; // outputs 0=foo&1=bar&3=baz, I expected 0=foo&1=bar&2=&3=baz 

Đây là vấn đề đối với tôi, vì tôi chuyển một số dữ liệu đến API nội bộ qua http và tôi cần phải kéo tất cả các đối số ở phía bên kia.

Vâng, tôi đã giải quyết vấn đề này và đưa ra báo cáo lỗi sau: http://bugs.php.net/bug.php?id=50407. Câu trả lời ngắn gọn từ quản trị viên là "Không cài đặt giống như cài đặt trống. Không có lỗi".

Ai đó có thể giải thích cho tôi tại sao đây không phải là lỗi không? Có ai có bất kỳ ý tưởng cho một workaround, ngoài việc hack què của thiết lập một giá trị tùy ý ở một bên và giải thích giá trị đó như là một giá trị sản phẩm nào trên khác?

EDIT

Dưới đây là lý do tại sao tôi nghĩ rằng đó là một lỗi:

$args = array("foo", "bar", array(), "baz"); 
$qs = http_build_query($args); 
parse_str($qs, $query); 
echo ($args == $query); // false, I expect it to be true 

Tôi đoán có lẽ đó là ngây thơ của tôi để xem xét parse_str()http_build_query() là nghịch đảo của nhau.

Tôi đang đăng giải pháp "lame hack" hiện tại của mình dưới dạng câu trả lời bên dưới.

+0

Vì vậy, bạn sẽ nói rằng API của bạn sẽ mù quáng tin tưởng vào dữ liệu đến thông qua HTTP không có xác nhận? Nghe có vẻ thú vị ... –

+2

không có vẻ như anh ấy nói bất cứ điều gì liên quan đến những gì sẽ xảy ra với dữ liệu bên trong API. – Johrn

+3

@Col. Shrapnel: Đó là một bước nhảy vọt. Anh ta chỉ muốn có thể truyền một biến với một giá trị rỗng. – webbiedave

Trả lời

2

Ai đó có thể giải thích cho tôi tại sao đây là không phải là lỗi?

Về mặt kỹ thuật, tôi không nghĩ nó nên được gắn nhãn lỗi. Thay vào đó, nó chỉ là cách họ thiết kế các chức năng để hành xử, cho dù những người khác không đồng ý với quyết định đó hay không.

API của bạn chỉ có thể kiểm tra với if (empty($_POST['2']))

+0

Tôi vừa chỉnh sửa câu hỏi của mình với một số chi tiết khác về lý do tại sao tôi nghĩ đó là một lỗi. – jsdalton

+0

Tôi không thấy mã được thêm vào của bạn định nghĩa lại nó như một lỗi. Đó là một quyết định hành vi mà bạn, và nhiều người khác, không đồng ý với. – webbiedave

+0

Đủ công bằng. "Lỗi" có lẽ là sự lựa chọn sai từ. Đó là một quyết định thiết kế kém IMO, bởi vì tôi tin rằng các chức năng mã hóa và giải mã dữ liệu sẽ không thể đảo ngược (nếu có thể ít nhất). – jsdalton

0

Đây là "què hack" hiện tại của tôi giải quyết. Lưu ý tôi phải giải thích cho khả năng của mảng lồng nhau, vì vậy ví dụ của tôi mảng ban đầu là hơi khác với những gì tôi đã đăng trong câu hỏi:

$args = array("foo", "bar", array("red", "blue", array(), "green"), "baz"); 
$original_array = $args; // save it to compare later 
function replace_empty_array_with_fake_string(&$value, $key) { 
    if (is_array($value)) { 
     if (empty($value)) { 
      $value = 'array()'; 
     } else { 
      array_walk($value, 'replace_empty_array_with_fake_string'); 
     } 

    } 
} 
array_walk($args, 'replace_empty_array_with_fake_string'); 
$qs = http_build_query($args); 

// convert the query string back to an array, this would happen on the "other side" 
parse_str($qs, $query); 
function replace_fake_string_with_empty_array(&$value, $key) { 
    if ($value == 'array()') { 
     $value = array(); 
    } 
    if (is_array($value)) { 
     array_walk($value, 'replace_fake_string_with_empty_array'); 
    } 
} 
array_walk($query, 'replace_fake_string_with_empty_array'); 
echo ($original_array == $query); // true 

Có lẽ tôi có thể đưa ra một chuỗi tùy ý hơn "array() "để sử dụng làm trình giữ chỗ.

Lame, tôi biết.

+0

Sẽ ngắn hơn để chỉ reimplement http_build_query. Tôi đã giới thiệu http_build_str() từ phần mở rộng pecl_http. Nhưng điều đó cũng không có tác dụng. – mario

+0

bất kỳ cơ thể nào biết sự khác biệt giữa http_build_query và http_build_str ?? –

1

Tôi đã thực hiện lại http_build_query để để trống đối tượng/mảng trong chuỗi truy vấn được trả lại (có dấu '='). Tôi đã cải tiến nó một chút từ các chức năng mặc định là tốt, vì vậy tất cả-trong-tất cả:

  • Duy trì đối tượng trống và mảng
  • Thay đổi enc_type mặc định để RFC3986 (liên quan đến lứa tuổi)
  • thêm một lý lẽ tách giá trị khóa (khả năng ghi đè mặc định '=')
  • Loại bỏ các chỉ số số cho cặp khóa-giá trị bằng số lập chỉ mục

tôi đã không kiểm tra này trong một môi trường sản xuất (không có ý tưởng về perfor mance hoặc lỗi), và nó không được tối ưu hóa, nhưng được đánh vần rất tốt.

function buildQuery($input,$numeric_prefix='', 
     $arg_separator='&',$enc_type=2, 
     $keyvalue_separator='=',$prefix='') { 
    if (is_array($input)) { 
     $arr = array(); 
     foreach ($input as $key => $value) { 
      $name = $prefix; 
      if (strlen($prefix)) { 
       $name .= '['; 
       if (!is_numeric($key)) { 
        $name .= $key; 
       } 
       $name .= ']'; 
      } else { 
       if (is_numeric($key)) { 
        $name .= $numeric_prefix; 
       } 
       $name .= $key; 
      } 
      if ((is_array($value) || is_object($value)) && count($value)) { 
       $arr[] = buildQuery($value,$numeric_prefix, 
         $arg_separator,$enc_type, 
         $keyvalue_separator,$name); 
      } else { 
       if ($enc_type === 2) { 
        $arr[] = rawurlencode($name) 
         .$keyvalue_separator 
         .rawurlencode($value?:''); 
       } else { 
        $arr[] = urlencode($name) 
         .$keyvalue_separator 
         .urlencode($value?:''); 
       } 
      } 
     } 
     return implode($arg_separator,$arr); 
    } else { 
     if ($enc_type === 2) { 
      return rawurlencode($input); 
     } else { 
      return urlencode($input); 
     } 
    } 
} 

Ví dụ:

$arr = array(
     'hello' => 'world', 
     'colors' => array('red','green','blue'), 
     'emptyArr' => array(), 
     'nested' => array(
      'empty' => array(), 
      'fruits' => array('orange','banana','apple'), 
      'curly' => 'sue', 
      'assoc' => array('a'=>'alpha','b'=>'bravo','c'=>'charlie') 
     ) 
    ); 

echo buildQuery($arr); 

Đầu ra: hello=world&colors%5B%5D=red&colors%5B%5D=green&colors%5B%5D=blue&emptyArr=&nested%5Bempty%5D=&nested%5Bfruits%5D%5B%5D=orange&nested%5Bfruits%5D%5B%5D=banana&nested%5Bfruits%5D%5B%5D=apple&nested%5Bcurly%5D=sue&nested%5Bassoc%5D%5Ba%5D=alpha&nested%5Bassoc%5D%5Bb%5D=bravo&nested%5Bassoc%5D%5Bc%5D=charlie Tôi hy vọng điều này tìm thấy một người nào đó tốt.

0

Bạn chỉ có thể đi bộ params truy vấn, nếu mảng trống rỗng, sử dụng "[]" thay vào đó, như thế này:

function walkCriteria(&$criteria) { 
    array_walk($criteria, function (&$val) { 
     if ($val === []) { 
      $val = "[]"; 
     } else if (is_array($val)) { 
      walkCriteria($val); 
     } 
    }); 
} 

Không sử dụng array_walk_recursive. Vì nó sẽ đi bộ thành mảng trống và không làm gì cả.

Các vấn đề liên quan