Yêu cầu PHP ngừng thay thế '.' ký tự trong mảng $ _GET hoặc $ _POST?


76

Nếu tôi chuyển các biến PHP với .tên của chúng qua $ _GET PHP sẽ tự động thay thế chúng bằng các _ký tự. Ví dụ:

<?php
echo "url is ".$_SERVER['REQUEST_URI']."<p>";
echo "x.y is ".$_GET['x.y'].".<p>";
echo "x_y is ".$_GET['x_y'].".<p>";

... xuất ra như sau:

url is /SpShipTool/php/testGetUrl.php?x.y=a.b
x.y is .
x_y is a.b.

... câu hỏi của tôi là: có cách nào để tôi có thể dừng việc này lại không? Cả đời tôi không thể tìm ra được những gì tôi đã làm để xứng đáng với điều này

Phiên bản PHP tôi đang chạy là 5.2.4-2ubuntu5.3.


.. Tại sao bạn không chuyển đổi tất cả các dấu chấm thành một số loại mã thông báo, chẳng hạn như (~ # ~) và sau đó đăng nó? Khi nhận được các vars, sau đó bạn có thể chuyển đổi chúng trở lại .. Điều này là do đôi khi chúng tôi CẦN đăng dấu gạch dưới .. và chúng tôi sẽ mất chúng nếu chuyển đổi lại tất cả "_" thành "." S ...
Fernando

Từ truy vấn khi truy xuất riêng của mình, bạn có thể concate các user_name như "concat (firstname, '_', lastname) như user_name.
Kaspar Mary

@Kaspar Mary ... cơ sở dữ liệu được thiết lập để có tên người dùng và trạng thái cột và tên người dùng được lưu trữ dưới dạng firstname.lastname, vì vậy tôi không thể sử dụng bất kỳ concat nào trong sql vì chúng giống nhau được kết hợp với a.
Rob

@Crisp Cảm ơn đã nhận xét! (at) Rob thú vấn đề
hek2mgl

Tại sao không có một bình luận xóa? :)
Chris Prince

Câu trả lời:


66

Đây là lời giải thích của PHP.net về lý do tại sao nó làm được điều đó:

Dấu chấm trong tên biến đến

Thông thường, PHP không thay đổi tên của các biến khi chúng được chuyển vào một tập lệnh. Tuy nhiên, cần lưu ý rằng dấu chấm (dấu chấm, dấu chấm đầy đủ) không phải là ký tự hợp lệ trong tên biến PHP. Để biết lý do, hãy nhìn vào nó:

<?php
$varname.ext;  /* invalid variable name */
?>

Bây giờ, những gì trình phân tích cú pháp nhìn thấy là một biến có tên $ varname, theo sau là toán tử nối chuỗi, theo sau là chuỗi trống (tức là chuỗi chưa được trích dẫn không khớp với bất kỳ khóa hoặc từ dành riêng nào đã biết) 'ext'. Rõ ràng, điều này không có kết quả dự kiến.

Vì lý do này, điều quan trọng cần lưu ý là PHP sẽ tự động thay thế bất kỳ dấu chấm nào trong tên biến đến bằng dấu gạch dưới.

Đó là từ http://ca.php.net/variables.external .

Ngoài ra, theo nhận xét này, các ký tự khác được chuyển đổi thành dấu gạch dưới:

Danh sách đầy đủ các ký tự tên trường mà PHP chuyển đổi thành _ (dấu gạch dưới) như sau (không chỉ dấu chấm):

  • chr (32) () (dấu cách)
  • chr (46) (.) (chấm)
  • chr (91) ([) (dấu ngoặc vuông mở)
  • chr (128) - chr (159) (khác nhau)

Vì vậy, có vẻ như bạn đang mắc kẹt với nó, vì vậy bạn sẽ phải chuyển đổi dấu gạch dưới trở lại thành dấu chấm trong tập lệnh của mình bằng cách sử dụng đề xuất của dawnerd ( Mặc dù vậy, tôi chỉ sử dụng str_replace .)


20
Đây là một lời giải thích tuyệt vời về lý do tại sao , nhưng không trả lời câu hỏi ban đầu là "có cách nào để khiến nó dừng lại"; các câu trả lời khác bên dưới cung cấp câu trả lời cho câu hỏi ban đầu.
El Yobo

1
@ElYobo, @JeremyRuten; giải thích tốt về lý do tại sao? Tôi đang sử dụng PHP 5.4 và PHP vẫn đang làm điều này. Tôi cũng muốn biết tại sao nó vẫn chưa bị phản đối. Tôi chỉ có thể thấy hai lý do để giữ nó; register_globals (không được dùng nữa kể từ 5.3) và để thuận tiện trong việc ~ thực hiện những gì mà các cầu đăng ký thực hiện theo cách thủ công (trong trường hợp đó, người thực hiện việc đó sẽ phải ánh xạ các tên var sao cho phù hợp với IMO).
semisecure

1
Tôi giả sử khả năng tương thích ngược? Điểm tốt, với các toàn cầu đăng ký hoạt động theo cách của dodo, "chức năng" kỳ lạ này có thể hoạt động tương tự.
El Yobo

Với php7, đăng ký toàn cầu đã đi vào hoàng hôn nhưng vấn đề vẫn còn.
magallanes

59

Câu hỏi đã được trả lời từ lâu, nhưng thực sự có một câu trả lời tốt hơn (hoặc giải quyết vấn đề). PHP cho phép bạn ở luồng đầu vào thô , vì vậy bạn có thể làm điều gì đó như sau:

$query_string = file_get_contents('php://input');

sẽ cung cấp cho bạn mảng $ _POST ở định dạng chuỗi truy vấn, các dấu chấm như chúng phải như vậy.

Sau đó, bạn có thể phân tích cú pháp nếu bạn cần (theo nhận xét của POSTer )

<?php
// Function to fix up PHP's messing up input containing dots, etc.
// `$source` can be either 'POST' or 'GET'
function getRealInput($source) {
    $pairs = explode("&", $source == 'POST' ? file_get_contents("php://input") : $_SERVER['QUERY_STRING']);
    $vars = array();
    foreach ($pairs as $pair) {
        $nv = explode("=", $pair);
        $name = urldecode($nv[0]);
        $value = urldecode($nv[1]);
        $vars[$name] = $value;
    }
    return $vars;
}

// Wrapper functions specifically for GET and POST:
function getRealGET() { return getRealInput('GET'); }
function getRealPOST() { return getRealInput('POST'); }
?>

Rất hữu ích cho các tham số OpenID, chứa cả hai '.' và '_', mỗi cái có một ý nghĩa nhất định!


5
Để làm cho điều này hoạt động với các tham số GET thay thế file_get_contents("php://input")bằng $_SERVER['QUERY_STRING'].
Sarel Botha

Và bạn có thể làm tương tự cho các tập tin cookie sử dụng$_SERVER['COOKIES']
Marcin

4
Đây là một khởi đầu tốt, nhưng có một số vấn đề với nó. Nó không xử lý các giá trị mảng (ví dụ: foo.bar [] = blarg sẽ không kết thúc dưới dạng mảng, nó sẽ kết thúc dưới dạng một biến vô hướng được gọi là foo.bar []). Nó cũng có rất nhiều chi phí vì nó xử lý lại tất cả các giá trị, bất kể có khoảng thời gian trong đó hay không.
El Yobo

Xem giải pháp của tôi bên dưới , giải pháp này khắc phục các vấn đề với việc triển khai Rok.
El Yobo

Vì lý do nào đó $ query_string = file_get_contents ('php: // input'); trả về một chuỗi trống cho tôi.
Chris Prince

27

Làm nổi bật một câu trả lời thực tế của Johan trong một bình luận ở trên - Tôi chỉ gói toàn bộ bài đăng của mình trong một mảng cấp cao nhất giúp loại bỏ hoàn toàn vấn đề mà không cần xử lý nặng.

Trong hình thức bạn làm

<input name="data[database.username]">  
<input name="data[database.password]">  
<input name="data[something.else.really.deep]">  

thay vì

<input name="database.username"> 
<input name="database.password"> 
<input name="something.else.really.deep">  

và trong trình xử lý bài đăng, chỉ cần mở nó ra:

$posdata = $_POST['data'];

Đối với tôi, đây là một sự thay đổi hai dòng, vì quan điểm của tôi hoàn toàn là khuôn mẫu.

FYI. Tôi đang sử dụng dấu chấm trong tên trường của mình để chỉnh sửa cây dữ liệu được nhóm.


4
Thực sự là một giải pháp rất thanh lịch và thiết thực, với lợi ích phụ là giữ cho dữ liệu biểu mẫu có vị trí riêng biệt.
robinmitra

1
Điều này hoàn toàn giải quyết được vấn đề và lẽ ra câu trả lời đã được chấp nhận.
Brian Klug

20

Hoạt động của chức năng này là một ý tưởng tuyệt vời mà tôi đã đưa ra trong kỳ nghỉ hè năm 2013 của mình.

Ví dụ, nó tuân thủ các tiêu chuẩn và có hỗ trợ mảng sâu a.a[x][b.a]=10. Nó sử dụng parse_str()hậu trường với một số xử lý trước được nhắm mục tiêu.

function fix($source) {
    $source = preg_replace_callback(
        '/(^|(?<=&))[^=[&]+/',
        function($key) { return bin2hex(urldecode($key[0])); },
        $source
    );

    parse_str($source, $post);

    $result = array();
    foreach ($post as $key => $val) {
        $result[hex2bin($key)] = $val;
    }
    return $result;
}

Và sau đó bạn có thể áp dụng nó như thế này, tùy thuộc vào nguồn:

$_POST   = fix(file_get_contents('php://input'));
$_GET    = fix($_SERVER['QUERY_STRING']);
$_COOKIE = fix($_SERVER['HTTP_COOKIE']);

Đối với PHP dưới 5,4: sử dụng base64_encodethay vì bin2hexbase64_decodethay vì hex2bin.


Cám ơn vì cái này. Vui lòng cập nhật nó cho mảng sâu a [2] [5] nếu bạn có thời gian.
Johan

@Johan, mảng sâu có tác dụng. a[2][5]=10sản xuất array(1) { ["a"]=> array(1) { [2]=> array(1) { [5]=> string(2) "10" } } }.
Rok Kralj

1
Ồ, tôi hiểu rồi, đúng là có, chỉ cần thử nghiệm thôi. Php không chuyển đổi các dấu chấm, v.v. bên trong chỉ mục mảng, chỉ có cấp cao nhất của tên mảng là gặp vấn đề: php_touches_this [nochangeshere] [nochangeshere]. Tuyệt quá. Cảm ơn.
Johan

Tôi muốn xem điểm chuẩn của bạn, vì điều đó mâu thuẫn với thử nghiệm mà tôi đã thực hiện vài tháng trước. Ngoài ra, tôi vừa gặp phải tình huống mà tôi cần xử lý các dấu chấm trong các trường tệp đã đăng, chưa có câu trả lời; bất kỳ ý tưởng?
El Yobo

Bạn sẽ sớm thấy chúng, hiện tại không có thời gian, nhưng bạn có thể giới thiệu chúng. * Tệp tải lên yêu cầu kiểu dữ liệu đa phần / biểu mẫu, kiểu dữ liệu này không được chuyển tới php: // input. Do đó, điều này vẫn còn rất khó làm. Xem: stackoverflow.com/questions/1361673/get-raw-post-data
Rok Kralj

7

Điều này xảy ra bởi vì một dấu chấm là một ký tự không hợp lệ trong tên của một biến, lý do nằm rất sâu trong việc triển khai PHP, vì vậy không có cách sửa chữa dễ dàng (chưa).

Trong thời gian chờ đợi, bạn có thể giải quyết vấn đề này bằng cách:

  1. Truy cập dữ liệu truy vấn thô thông qua php://inputdữ liệu POST hoặc $_SERVER['QUERY_STRING']dữ liệu GET
  2. Sử dụng một chức năng chuyển đổi.

Hàm chuyển đổi dưới đây (PHP> = 5.4) mã hóa tên của mỗi cặp khóa-giá trị thành một biểu diễn thập lục phân và sau đó thực hiện một quy tắc parse_str(); sau khi hoàn thành, nó sẽ hoàn nguyên các tên hệ thập lục phân trở lại dạng ban đầu:

function parse_qs($data)
{
    $data = preg_replace_callback('/(?:^|(?<=&))[^=[]+/', function($match) {
        return bin2hex(urldecode($match[0]));
    }, $data);

    parse_str($data, $values);

    return array_combine(array_map('hex2bin', array_keys($values)), $values);
}

// work with the raw query string
$data = parse_qs($_SERVER['QUERY_STRING']);

Hoặc là:

// handle posted data (this only works with application/x-www-form-urlencoded)
$data = parse_qs(file_get_contents('php://input'));

điều gì sẽ xảy ra nếu điều này cần được sử dụng cho một thứ khác đã được gửi qua và tôi thực sự cần _ trong biến?
Rob

@Rob Tôi đã thêm đầu ra dựa trên câu hỏi của bạn; nó hoạt động như mong đợi, vì tôi không chạm vào dấu gạch dưới.
Ja͢ck

Lưu ý: Đây là một giải pháp đã được chỉnh sửa, sau này đã sao chép mã và ý tưởng của tôi (xem nhật ký thay đổi). Nó nên được loại bỏ bởi những người kiểm duyệt.
Rok Kralj

Rõ ràng là đã đủ tốt để bạn tiếp thu bin2hex()ý tưởng từ tôi, vậy chúng ta có thể xóa bỏ mối thù vô nghĩa này không?
Ja͢ck

Chà, tôi vừa đổi nó thay cho mã hóa base64. Lợi ích? Không có gì, ngoài một chút tăng tốc. Tại sao phải chỉnh sửa một giải pháp hoàn hảo tốt để sao chép của người khác?
Rok Kralj

5

Cách tiếp cận này là một phiên bản đã thay đổi của Rok Kralj's, nhưng với một số điều chỉnh để hoạt động, nhằm cải thiện hiệu quả (tránh các lệnh gọi lại, mã hóa và giải mã không cần thiết trên các khóa không bị ảnh hưởng) và xử lý chính xác các khóa mảng.

Có sẵn ý chính với các bài kiểm tra và mọi phản hồi hoặc đề xuất đều được hoan nghênh ở đây hoặc ở đó.

public function fix(&$target, $source, $keep = false) {                        
    if (!$source) {                                                            
        return;                                                                
    }                                                                          
    $keys = array();                                                           

    $source = preg_replace_callback(                                           
        '/                                                                     
        # Match at start of string or &                                        
        (?:^|(?<=&))                                                           
        # Exclude cases where the period is in brackets, e.g. foo[bar.blarg]
        [^=&\[]*                                                               
        # Affected cases: periods and spaces                                   
        (?:\.|%20)                                                             
        # Keep matching until assignment, next variable, end of string or   
        # start of an array                                                    
        [^=&\[]*                                                               
        /x',                                                                   
        function ($key) use (&$keys) {                                         
            $keys[] = $key = base64_encode(urldecode($key[0]));                
            return urlencode($key);                                            
        },                                                                     
    $source                                                                    
    );                                                                         

    if (!$keep) {                                                              
        $target = array();                                                     
    }                                                                          

    parse_str($source, $data);                                                 
    foreach ($data as $key => $val) {                                          
        // Only unprocess encoded keys                                      
        if (!in_array($key, $keys)) {                                          
            $target[$key] = $val;                                              
            continue;                                                          
        }                                                                      

        $key = base64_decode($key);                                            
        $target[$key] = $val;                                                  

        if ($keep) {                                                           
            // Keep a copy in the underscore key version                       
            $key = preg_replace('/(\.| )/', '_', $key);                        
            $target[$key] = $val;                                              
        }                                                                      
    }                                                                          
}                                                                              

Boom này đã làm việc hoàn hảo cho tôi, cảm ơn El Yobo / Rok. Sử dụng nó trong dự án CodeIgniter 2.1.3.
xref

Tôi sẽ lưu ý nếu các giá trị không có% 20 thực thể đã có sẵn, chẳng hạn như 'Some Key = Some Value' thì đầu ra của hàm này là 'Some_Key = Some Value', có thể regex có thể được điều chỉnh?
xref

Regex có thể được điều chỉnh để bắt các khoảng trống chưa được mã hóa url ... nhưng nếu nguồn của bạn chưa được mã hóa url, thì có thể sẽ xảy ra các vấn đề khác, vì việc xử lý luôn giải mã và mã hóa các chuỗi, sau đó lệnh parse_strgọi sẽ lại urldecode. Bạn đang thử phân tích cú pháp chưa được mã hóa là gì?
El Yobo

Cảm ơn vì đã ghi công. Mặc dù vậy, tôi có thể cảnh báo rằng mã của bạn có thể hoạt động kém hơn, vì POST thường chỉ có vài trăm byte. Tôi thích sự đơn giản hơn ở đây.
Rok Kralj

1
Bạn đã nhận được những điểm chuẩn ở đâu đó? Tôi muốn xem nó chậm hơn trong những trường hợp nào, vì mọi thứ mà tôi đã thử nghiệm đều dao động giữa tốc độ như tốc độ của bạn và nhanh gấp đôi. Tôi nghi ngờ sự khác biệt là ở loại thứ mà nó đã được thử nghiệm :) Bạn có thể dễ dàng thêm một số kiểm tra thời gian vào ý chính của tôi để xem nó diễn ra như thế nào, tại sao không so sánh của bạn với cùng một kết quả và thời gian đầu vào và bài đăng?
El Yobo

4

Lý do điều này xảy ra là do chức năng register_globals cũ của PHP. Các . ký tự không phải là một ký tự hợp lệ trong một tên biến, vì vậy PHP sẽ đặt nó vào dấu gạch dưới để đảm bảo có tính tương thích.

Tóm lại, không phải là một phương pháp hay để thực hiện các dấu chấm trong các biến URL.


1
Bạn cũng không nên bật register_globals. Trên thực tế, nó nên được tắt ngay bây giờ nếu có thể.
dawnerd 16-08

1
register_globals thực tế bị tắt, cũng như mặc định trong PHP5. > Các. ký tự không phải là ký tự hợp lệ trong một tên biến Rất tiếc, tôi không muốn sử dụng nó làm tên biến (tôi giữ nó làm khóa trong từ điển $ _GET), vì vậy 'sự chu đáo' này trong PHP không thêm giá trị :-( ah cũng ...

Không quan trọng nếu register_globals đang bật hay tắt. PHP vẫn thực hiện các thay thế.
Jeremy Privett 16/09/08

3

Nếu tìm kiếm bất kỳ cách để theo nghĩa đen có được PHP để ngăn chặn thay thế '' các ký tự trong mảng $ _GET hoặc $ _POST, thì một trong những cách như vậy là sửa đổi mã nguồn của PHP (và trong trường hợp này nó tương đối đơn giản).

CẢNH BÁO: Sửa đổi mã nguồn PHP C là một tùy chọn nâng cao!

Cũng xem báo cáo lỗi PHP này đề xuất sửa đổi tương tự.

Để khám phá, bạn cần phải:

  • tải xuống mã nguồn C của PHP
  • vô hiệu hóa .kiểm tra thay thế
  • ./configure , tạo và triển khai phiên bản PHP tùy chỉnh của bạn

Bản thân sự thay đổi nguồn là không đáng kể và chỉ liên quan đến việc cập nhật một nửa của một dòng trong main/php_variables.c:

Lưu ý: so với bản gốc || *p == '.' đã được bình luận


Đầu ra mẫu:

đã cho QUERY_STRING trong tổng số a.a[]=bb&a.a[]=BB&c%20c=dd, <?php print_r($_GET);hiện đang chạy tạo ra:

Mảng
(
    [aa] => Mảng
        (
            [0] => bb
            [1] => BB
        )

    [c_c] => đ
)

Ghi chú:

  • bản vá này chỉ giải quyết câu hỏi ban đầu (nó dừng thay thế dấu chấm, không phải dấu cách).
  • chạy trên bản vá này sẽ nhanh hơn so với các giải pháp cấp tập lệnh, nhưng những câu trả lời .php thuần túy nói chung vẫn được ưu tiên hơn (vì chúng tránh thay đổi chính PHP).
  • về lý thuyết, phương pháp polyfill có thể thực hiện được ở đây và có thể kết hợp các phương pháp - kiểm tra sự thay đổi ở mức C bằng cách sử dụng parse_str()và (nếu không có) dự phòng cho các phương pháp chậm hơn.

1
Tuy nhiên, bạn không nên làm như vậy bao giờ, hãy +1 cho nỗ lực.
Rok Kralj

2

Giải pháp của tôi cho vấn đề này rất nhanh chóng và bẩn thỉu, nhưng tôi vẫn thích nó. Tôi chỉ muốn đăng một danh sách các tên tệp đã được kiểm tra trên biểu mẫu. Tôi đã từng base64_encodemã hóa các tên tệp trong phần đánh dấu và sau đó chỉ cần giải mã nó base64_decodetrước khi sử dụng chúng.


2

Sau khi xem xét giải pháp của Rok, tôi đã đưa ra một phiên bản giải quyết những hạn chế trong câu trả lời của tôi bên dưới, crb ở trên và giải pháp của Rok. Xem phiên bản cải tiến của tôi .


Câu trả lời của @ crb ở trên là một khởi đầu tốt, nhưng có một vài vấn đề.

  • Nó xử lý lại mọi thứ, quá mức cần thiết; chỉ những trường có dấu "." trong tên cần được xử lý lại.
  • Nó không thể xử lý các mảng theo cách giống như cách xử lý PHP gốc, ví dụ: đối với các khóa như "foo.bar []".

Giải pháp bên dưới giải quyết cả hai vấn đề này ngay bây giờ (lưu ý rằng nó đã được cập nhật kể từ lần đăng ban đầu). Điều này nhanh hơn khoảng 50% so với câu trả lời của tôi ở trên trong thử nghiệm của tôi, nhưng sẽ không xử lý các trường hợp dữ liệu có cùng một khóa (hoặc một khóa được trích xuất giống nhau, ví dụ foo.bar và foo_bar đều được trích xuất dưới dạng foo_bar).

<?php

public function fix2(&$target, $source, $keep = false) {                       
    if (!$source) {                                                            
        return;                                                                
    }                                                                          
    preg_match_all(                                                            
        '/                                                                     
        # Match at start of string or &                                        
        (?:^|(?<=&))                                                           
        # Exclude cases where the period is in brackets, e.g. foo[bar.blarg]
        [^=&\[]*                                                               
        # Affected cases: periods and spaces                                   
        (?:\.|%20)                                                             
        # Keep matching until assignment, next variable, end of string or   
        # start of an array                                                    
        [^=&\[]*                                                               
        /x',                                                                   
        $source,                                                               
        $matches                                                               
    );                                                                         

    foreach (current($matches) as $key) {                                      
        $key    = urldecode($key);                                             
        $badKey = preg_replace('/(\.| )/', '_', $key);                         

        if (isset($target[$badKey])) {                                         
            // Duplicate values may have already unset this                    
            $target[$key] = $target[$badKey];                                  

            if (!$keep) {                                                      
                unset($target[$badKey]);                                       
            }                                                                  
        }                                                                      
    }                                                                          
}                                                                              

-1. Tại sao? 1. Dấu cách %20cũng là một ký tự đặc biệt được chuyển đổi thành dấu gạch dưới. 2. Mã của bạn xử lý trước tất cả dữ liệu, vì preg_match_allphải quét mọi thứ, mặc dù bạn nói rằng bạn không làm như vậy. 3. Mã của bạn không thành công ở những ví dụ như thế này: a.b[10]=11.
Rok Kralj

Bạn nói đúng về không gian, cảm ơn. Lời giải thích của tôi đã chỉ ra rằng cách tiếp cận của tôi không xử lý các mảng, vì vậy tôi không chắc tại sao bạn lại chỉ ra điều đó. preg_match_allphải "xử lý" một chuỗi, chứ không phải trích xuất và xử lý lại tất cả các khóa và giá trị không bị ảnh hưởng, vì vậy bạn cũng hơi chệch hướng ở đó. Điều đó nói rằng, cách tiếp cận của bạn với parse_stringvẻ ngoài như một cách tiếp cận thú vị mà, với một chút tinh chỉnh, có thể là tốt hơn :)
El Yobo

Bạn nói rằng bạn chỉ giải nén các khóa bị ảnh hưởng, nhưng xét về độ phức tạp tính toán thì bạn không làm như vậy. Bạn đang nói như bạn có một số loại truy cập ngẫu nhiên để chỉ tìm nạp các khóa bị ảnh hưởng, nhưng ngay cả khi không có khóa bị ảnh hưởng nào hiện diện, bạn phải truy cập toàn bộ bộ nhớ. Nếu bạn có một bài đăng với 100 megs dữ liệu, bạn trích xuất nội dung gì không quan trọng, cả hai cách tiếp cận đều tuyến tính , O(n). Trên thực tế, bạn đang làm cho độ phức tạp trở nên tồi tệ hơn, bằng cách sử dụng in_array()hàm, như đã chỉ ra ở trên.
Rok Kralj

Tôi đang xem qua 100megs một lần, không phải tách nó ra (điều này ngay lập tức tăng gấp đôi bộ nhớ), sau đó lại chia nhỏ (nhân đôi một lần nữa) như trong phương pháp của crb mà tôi cũng đang so sánh điều này. Ký hiệu Big O hoàn toàn không tính đến việc sử dụng bộ nhớ và cách triển khai này cũng không sử dụng in_array. Ngoài ra, nếu bạn quan tâm đến việc chạy một số thử nghiệm, bạn sẽ nhận thấy rằng phần trên vẫn nhanh hơn đáng kể; không O (n) vs O (n ^ 2), nhưng một cách tiếp cận tuyến tính vẫn có thể được nhanh hơn so với khác ... và điều này là;)
El Yobo

Ưu điểm chính khác mà cách tiếp cận này có là lợi thế về tốc độ là lớn nhất khi không có công việc nào phải thực hiện, tức là khi không có khóa nào được cung cấp dấu chấm hoặc dấu cách; điều này có nghĩa là nó có chi phí tối thiểu nếu bạn thả nó vào để xử lý tất cả các yêu cầu, vì nó hầu như không hoạt động (một regex), so với giải nén và mã hóa tất cả các khóa nhiều lần.
El Yobo

0

Chà, hàm mà tôi đưa vào bên dưới, "getRealPostArray ()", không phải là một giải pháp hay, nhưng nó xử lý các mảng và hỗ trợ cả hai tên: "alpha_beta" và "alpha.beta":

  <input type='text' value='First-.' name='alpha.beta[a.b][]' /><br>
  <input type='text' value='Second-.' name='alpha.beta[a.b][]' /><br>
  <input type='text' value='First-_' name='alpha_beta[a.b][]' /><br>
  <input type='text' value='Second-_' name='alpha_beta[a.b][]' /><br>

trong khi var_dump ($ _ POST) tạo ra:

  'alpha_beta' => 
    array (size=1)
      'a.b' => 
        array (size=4)
          0 => string 'First-.' (length=7)
          1 => string 'Second-.' (length=8)
          2 => string 'First-_' (length=7)
          3 => string 'Second-_' (length=8)

var_dump (getRealPostArray ()) tạo ra:

  'alpha.beta' => 
    array (size=1)
      'a.b' => 
        array (size=2)
          0 => string 'First-.' (length=7)
          1 => string 'Second-.' (length=8)
  'alpha_beta' => 
    array (size=1)
      'a.b' => 
        array (size=2)
          0 => string 'First-_' (length=7)
          1 => string 'Second-_' (length=8)

Chức năng, cho những gì nó có giá trị:

function getRealPostArray() {
  if ($_SERVER['REQUEST_METHOD'] !== 'POST') {#Nothing to do
      return null;
  }
  $neverANamePart = '~#~'; #Any arbitrary string never expected in a 'name'
  $postdata = file_get_contents("php://input");
  $post = [];
  $rebuiltpairs = [];
  $postraws = explode('&', $postdata);
  foreach ($postraws as $postraw) { #Each is a string like: 'xxxx=yyyy'
    $keyvalpair = explode('=',$postraw);
    if (empty($keyvalpair[1])) {
      $keyvalpair[1] = '';
    }
    $pos = strpos($keyvalpair[0],'%5B');
    if ($pos !== false) {
      $str1 = substr($keyvalpair[0], 0, $pos);
      $str2 = substr($keyvalpair[0], $pos);
      $str1 = str_replace('.',$neverANamePart,$str1);
      $keyvalpair[0] = $str1.$str2;
    } else {
      $keyvalpair[0] = str_replace('.',$neverANamePart,$keyvalpair[0]);
    }
    $rebuiltpair = implode('=',$keyvalpair);
    $rebuiltpairs[]=$rebuiltpair;
  }
  $rebuiltpostdata = implode('&',$rebuiltpairs);
  parse_str($rebuiltpostdata, $post);
  $fixedpost = [];
  foreach ($post as $key => $val) {
    $fixedpost[str_replace($neverANamePart,'.',$key)] = $val;
  }
  return $fixedpost;
}

0

Sử dụng crb's, tôi muốn tạo lại $_POSTtoàn bộ mảng mặc dù hãy nhớ rằng bạn vẫn phải đảm bảo rằng bạn đang mã hóa và giải mã chính xác cả ở máy khách và máy chủ. Điều quan trọng là phải hiểu khi nào một ký tự thực sự không hợp lệ và nó thực sự hợp lệ . Ngoài ra, mọi người vẫn nên và luôn thoát khỏi dữ liệu khách trước khi sử dụng nó với bất kỳ lệnh cơ sở dữ liệu nào mà không có ngoại lệ .

<?php
unset($_POST);
$_POST = array();
$p0 = explode('&',file_get_contents('php://input'));
foreach ($p0 as $key => $value)
{
 $p1 = explode('=',$value);
 $_POST[$p1[0]] = $p1[1];
 //OR...
 //$_POST[urldecode($p1[0])] = urldecode($p1[1]);
}
print_r($_POST);
?>

Tôi khuyên bạn chỉ nên sử dụng cái này cho những trường hợp riêng lẻ, tôi không chắc về những điểm tiêu cực của việc đặt cái này ở đầu tệp tiêu đề chính của bạn.


0

Giải pháp hiện tại của tôi (dựa trên các câu trả lời chủ đề hiện tại):

function parseQueryString($data)
{
    $data = rawurldecode($data);   
    $pattern = '/(?:^|(?<=&))[^=&\[]*[^=&\[]*/';       
    $data = preg_replace_callback($pattern, function ($match){
        return bin2hex(urldecode($match[0]));
    }, $data);
    parse_str($data, $values);

    return array_combine(array_map('hex2bin', array_keys($values)), $values);
}

$_GET = parseQueryString($_SERVER['QUERY_STRING']);

xin vui lòng thêm một số giải thích sẽ hữu ích cho tất cả những người sẽ đọc câu trả lời của bạn.
Prafulla Kumar Sahu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.