Lassen Sie PHP '.' Nicht mehr ersetzen. Zeichen in $ _GET- oder $ _POST-Arrays?

76

Wenn ich PHP-Variablen mit .ihren Namen über $ _GET übergebe, ersetzt PHP sie automatisch durch _Zeichen. Zum Beispiel:

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

... gibt Folgendes aus:

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

... meine Frage lautet: Gibt es eine Möglichkeit, dies zu stoppen? Ich kann nicht für mein Leben herausfinden, was ich getan habe, um dies zu verdienen

Die PHP-Version, mit der ich arbeite, ist 5.2.4-2ubuntu5.3.

eLRuLL
quelle
.. Warum konvertierst du nicht einfach alle Punkte in eine Art Token, wie zum Beispiel in (~ # ~) und postest es dann? Wenn Sie die Vars erhalten, können Sie sie wieder zurückkonvertieren. Dies liegt daran, dass wir manchmal Unterstriche posten MÜSSEN. Und wir würden sie verlieren, wenn wir alle "_" in "." S ...
Fernando
In der Abrufabfrage selbst können Sie den Benutzernamen wie "concat (Vorname, '_', Nachname) als Benutzernamen angeben.
Kaspar Mary
@Kaspar Mary ... Die Datenbank ist so eingerichtet, dass sie den Benutzernamen und den Status der Spalten enthält. Die Benutzernamen werden als Vorname.Nachname gespeichert, sodass ich kein Concat in SQL verwenden kann, da sie bereits mit a verknüpft sind.
Rob
@Crisp Danke für den Kommentar! (at) Rob interessantes Problem
hek2mgl
Warum gibt es keinen Kommentar zum Löschen? :)
Chris Prince

Antworten:

66

Hier ist die Erklärung von PHP.net, warum es das tut:

Punkte in eingehenden Variablennamen

Normalerweise ändert PHP die Namen von Variablen nicht, wenn sie an ein Skript übergeben werden. Es ist jedoch zu beachten, dass der Punkt (Punkt, Punkt) kein gültiges Zeichen in einem PHP-Variablennamen ist. Schauen Sie sich den Grund an:

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

Der Parser sieht nun eine Variable mit dem Namen $ varname, gefolgt vom String-Verkettungsoperator, gefolgt vom Barestring (dh einem nicht zitierten String, der keinem bekannten Schlüssel oder reservierten Wörtern entspricht) 'ext'. Offensichtlich hat dies nicht das beabsichtigte Ergebnis.

Aus diesem Grund ist es wichtig zu beachten, dass PHP automatisch alle Punkte in eingehenden Variablennamen durch Unterstriche ersetzt.

Das ist von http://ca.php.net/variables.external .

Gemäß diesem Kommentar werden diese anderen Zeichen auch in Unterstriche umgewandelt:

Die vollständige Liste der Feldnamenzeichen, die PHP in _ (Unterstrich) konvertiert, lautet wie folgt (nicht nur Punkt):

  • chr (32) () (Leerzeichen)
  • chr (46) (.) (Punkt)
  • chr (91) ([) (offene eckige Klammer)
  • chr (128) - chr (159) (verschiedene)

Es sieht also so aus, als ob Sie daran festhalten , also müssen Sie die Unterstriche nach dem Vorschlag von dawnerd wieder in Punkte in Ihrem Skript konvertieren (ich würde jedoch nur str_replace verwenden .)

Jeremy Ruten
quelle
20
Dies ist eine großartige Erklärung für das Warum , beantwortet aber nicht die ursprüngliche Frage: "Gibt es eine Möglichkeit, es zum Stoppen zu bringen?" Andere Antworten unten geben eine Antwort auf die ursprüngliche Frage.
El Yobo
1
@ElYobo, @JeremyRuten; gute Erklärung warum? Ich benutze PHP 5.4 und PHP macht das immer noch. Ich würde auch gerne wissen, warum es noch nicht veraltet ist. Ich kann nur zwei Gründe dafür sehen; register_globals (veraltet seit 5.3) und der Einfachheit halber bei der manuellen Ausführung von Register-Globals (in diesem Fall sollte die Person, die dies tut, die Last tragen, Var-Namen zuzuordnen, wie sie es für IMO halten).
Spinkus
1
Abwärtskompatibilität nehme ich an? Guter Punkt, wenn Registerglobale den Weg des Dodos gehen, könnte diese seltsame "Funktionalität" ebenfalls gehen.
El Yobo
Mit PHP7 ritten Registerglobale bereits in den Sonnenuntergang, aber das Problem ist immer noch vorhanden.
Magallanes
59

Die Frage wurde schon lange beantwortet, aber es gibt tatsächlich eine bessere Antwort (oder Umgehung). Mit PHP können Sie den rohen Eingabestream bearbeiten , sodass Sie Folgendes tun können:

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

Dadurch erhalten Sie das Array $ _POST im Abfragezeichenfolgenformat in den angegebenen Zeiträumen.

Sie können es dann bei Bedarf analysieren (gemäß POSTer-Kommentar ).

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

Sehr nützlich für OpenID-Parameter, die beide '.' Enthalten. und '_', jeweils mit einer bestimmten Bedeutung!

crb
quelle
5
Damit dies mit GET-Parametern funktioniert, ersetzen Sie file_get_contents("php://input")durch $_SERVER['QUERY_STRING'].
Sarel Botha
Und Sie können das gleiche für Cookies tun mit$_SERVER['COOKIES']
Marcin
4
Dies ist ein guter Anfang, aber es gibt ein paar Probleme damit. Array-Werte werden nicht verarbeitet (z. B. wird foo.bar [] = blarg nicht als Array, sondern als skalare Variable mit dem Namen foo.bar [] angezeigt). Es hat auch viel Aufwand, da alle Werte erneut verarbeitet werden, unabhängig davon, ob sie einen Punkt enthalten oder nicht.
El Yobo
Siehe meine Lösung unten , die die Probleme mit der Implementierung von Rok behebt.
El Yobo
Aus irgendeinem Grund $ query_string = file_get_contents ('php: // input'); gibt eine leere Zeichenfolge für mich zurück.
Chris Prince
27

Hervorheben einer tatsächlichen Antwort von Johan in einem Kommentar oben - Ich habe gerade meinen gesamten Beitrag in ein Array der obersten Ebene eingewickelt, das das Problem vollständig umgeht, ohne dass eine umfangreiche Verarbeitung erforderlich ist.

In der Form, die Sie tun

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

anstatt

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

und im Post-Handler einfach auspacken:

$posdata = $_POST['data'];

Für mich war dies eine zweizeilige Änderung, da meine Ansichten vollständig vorlagen.

Zu Ihrer Information. Ich verwende Punkte in meinen Feldnamen, um Bäume mit gruppierten Daten zu bearbeiten.

Scipilot
quelle
4
Sehr elegante und praktische Lösung mit dem Nebeneffekt, dass Formulardaten in einem schönen Namensraum gehalten werden.
Robinmitra
1
Dies löst das Problem vollständig und hätte als Antwort akzeptiert werden müssen.
Brian Klug
20

Die Funktionsweise dieser Funktion ist eine nette Idee, die ich während meiner Sommerferien 2013 hatte.

Es ist standardkonform und bietet beispielsweise umfassende Array-Unterstützung a.a[x][b.a]=10. Es wird parse_str()hinter den Kulissen mit einer gezielten Vorverarbeitung verwendet.

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;
}

Und dann können Sie es je nach Quelle folgendermaßen anwenden:

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

Für PHP unter 5.4: Verwenden Sie base64_encodeanstelle von bin2hexund base64_decodeanstelle von hex2bin.

Rok Kralj
quelle
Danke dafür. Bitte aktualisieren Sie es auch für Deep Arrays a [2] [5], wenn Sie Zeit haben.
Johan
@ Joan, tiefe Arrays funktionieren. a[2][5]=10produziert array(1) { ["a"]=> array(1) { [2]=> array(1) { [5]=> string(2) "10" } } }.
Rok Kralj
1
Oh, ich habe es bekommen, es hat es tatsächlich getestet. PHP konvertiert keine Punkte usw. in Array-Indizes, nur die oberste Ebene des Array-Namens ist problematisch: php_touches_this [nochangeshere] [nochangeshere]. Toll. Vielen Dank.
Johan
Ich würde gerne Ihre Benchmarks sehen, da dies im Widerspruch zu den Tests steht, die ich vor einigen Monaten durchgeführt habe. Außerdem bin ich gerade auf die Situation gestoßen, in der ich Punkte in geposteten Dateifeldern verarbeiten muss, für die noch keine Antworten vorliegen. irgendwelche Ideen?
El Yobo
Sie werden sie früh genug sehen, haben momentan keine Zeit, aber Sie können Ihre präsentieren. * Für das Hochladen von Dateien ist ein mehrteiliger / Formulardatentyp erforderlich, der nicht an die Eingabe von php: // übergeben wird. Daher ist dies immer noch sehr hackisch zu tun. Siehe: stackoverflow.com/questions/1361673/get-raw-post-data
Rok Kralj
7

Dies liegt daran, dass ein Punkt ein ungültiges Zeichen im Namen einer Variablen ist, dessen Grund sehr tief in der Implementierung von PHP liegt, sodass es (noch) keine einfachen Korrekturen gibt.

In der Zwischenzeit können Sie dieses Problem umgehen, indem Sie:

  1. Zugriff auf die Rohdaten der Abfrage entweder php://inputfür POST-Daten oder $_SERVER['QUERY_STRING']für GET-Daten
  2. Verwenden einer Konvertierungsfunktion.

Die folgende Konvertierungsfunktion (PHP> = 5.4) codiert die Namen jedes Schlüssel-Wert-Paares in eine hexadezimale Darstellung und führt dann eine reguläre Darstellung durch parse_str(). Sobald dies erledigt ist, werden die hexadezimalen Namen wieder in ihre ursprüngliche Form zurückgesetzt:

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']);

Oder:

// handle posted data (this only works with application/x-www-form-urlencoded)
$data = parse_qs(file_get_contents('php://input'));
Jack
quelle
Was würde jedoch passieren, wenn dies für etwas anderes verwendet werden müsste, das gesendet wurde, und ich tatsächlich das _ in der Variablen benötige?
Rob
@Rob Ich habe die Ausgabe basierend auf Ihrer Frage hinzugefügt. es funktioniert wie erwartet, weil ich die Unterstriche nicht berühre.
Ja͢ck
Hinweis: Dies ist eine bearbeitete Lösung, die später meinen Code und meine Idee kopiert hat (siehe Änderungsprotokoll). Es sollte von den Moderatoren entfernt werden.
Rok Kralj
Anscheinend war es gut genug für Sie, die bin2hex()Idee von mir zu übernehmen. Können wir diese sinnlose Fehde einfach fallen lassen?
Ja͢ck
Nun, ich habe es einfach anstelle der Base64-Codierung ausgetauscht. Vorteil? Nichts, außer ein wenig Beschleunigung. Warum eine perfekte Lösung bearbeiten, um die einer anderen Person zu kopieren?
Rok Kralj
5

Dieser Ansatz ist eine geänderte Version von Rok Kraljs, jedoch mit einigen Optimierungen, um die Effizienz zu verbessern (vermeidet unnötige Rückrufe, das Codieren und Decodieren nicht betroffener Schlüssel) und um Array-Schlüssel korrekt zu handhaben.

Eine Übersicht mit Tests ist verfügbar und Feedback oder Vorschläge sind hier oder da willkommen.

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;                                              
        }                                                                      
    }                                                                          
}                                                                              
El Yobo
quelle
Boom, das hat perfekt für mich funktioniert, danke El Yobo / Rok. Verwendung in einem CodeIgniter 2.1.3-Projekt.
XRef
Ich würde beachten, wenn Werte eingehen, für die noch keine% 20-Entitäten vorhanden sind, wie z. B. 'Some Key = Some Value', lautet die Ausgabe dieser Funktion 'Some_Key = Some Value'. Vielleicht könnte der reguläre Ausdruck angepasst werden.
XRef
Der reguläre Ausdruck könnte angepasst werden, um nicht URL-codierte Leerzeichen parse_strabzufangen. Wenn Ihre Quelle jedoch noch nicht URL-codiert ist, treten wahrscheinlich andere Probleme auf, da die Behandlung Zeichenfolgen immer decodiert und codiert. Der Aufruf wird dann erneut URL-Code. Was versuchst du zu analysieren, das noch nicht codiert ist?
El Yobo
Danke für die Zuschreibung. Ich könnte jedoch warnen, dass Ihr Code möglicherweise schlechter abschneidet, da POSTs normalerweise nur einige hundert Bytes umfassen. Ich bevorzuge hier Einfachheit.
Rok Kralj
1
Haben Sie diese Benchmarks irgendwo aufgestellt? Ich bin gespannt, in welchen Szenarien es langsamer ist, da alles, was ich getestet habe, zwischen der gleichen Geschwindigkeit wie Ihrer und der doppelten Geschwindigkeit lag. Ich vermute, der Unterschied liegt in der Art der Dinge, an denen es getestet wurde :) Sie können meinem Kern leicht einige Timing-Checks hinzufügen, um zu sehen, wie es läuft. Warum vergleichen Sie Ihre nicht mit denselben Eingaben und veröffentlichen Sie Ergebnisse und Zeiten?
El Yobo
4

Der Grund dafür ist die alte Funktionalität von PHP register_globals. Das . Zeichen ist kein gültiges Zeichen in einem Variablennamen, daher wird es von PHP in einen Unterstrich umgewandelt, um die Kompatibilität sicherzustellen.

Kurz gesagt, es ist keine gute Praxis, Punkte in URL-Variablen zu machen.

Jeremy Privett
quelle
1
Es ist auch keine gute Idee, register_globals zu aktivieren. Tatsächlich sollte es jetzt, wenn möglich, sofort ausgeschaltet werden.
Dawnerd
1
register_globals ist tatsächlich deaktiviert, ebenso wie die Standardeinstellung in PHP5. > Die. Zeichen ist kein gültiges Zeichen in einem Variablennamen Leider möchte ich dies nicht als Variablennamen verwenden (ich behalte es als Schlüssel im $ _GET-Wörterbuch), daher fügt diese 'Nachdenklichkeit' in PHP keinen Wert hinzu :-(
Es spielt keine Rolle, ob register_globals aktiviert oder deaktiviert ist. PHP führt weiterhin die Ersetzungen durch.
Jeremy Privett
3

Wenn Sie nach einer Möglichkeit suchen , PHP buchstäblich dazu zu bringen, das Ersetzen von '.' Zeichen in $ _GET- oder $ _POST-Arrays. Eine Möglichkeit besteht darin, die PHP-Quelle zu ändern (und in diesem Fall ist dies relativ einfach).

WARNUNG: Das Ändern der PHP C-Quelle ist eine erweiterte Option!

Siehe auch diesen PHP-Fehlerbericht , der dieselbe Änderung vorschlägt.

Um zu erkunden, müssen Sie:

  • Laden Sie den C-Quellcode von PHP herunter
  • Deaktivieren Sie die .Ersatzprüfung
  • configure , machen und bereitstellen Ihre angepasste Version von PHP

Die Quellenänderung selbst ist trivial und beinhaltet das Aktualisieren von nur einer Hälfte einer Zeile in main/php_variables.c:

....
/* ensure that we don't have spaces or dots in the variable name (not binary safe) */
for (p = var; *p; p++) {
    if (*p == ' ' /*|| *p == '.'*/) {
        *p='_';
....

Hinweis: Im Vergleich zum Original || *p == '.' wurde auskommentiert


Beispielausgabe:

Bei einem QUERY_STRING von erzeugt das a.a[]=bb&a.a[]=BB&c%20c=ddAusführen <?php print_r($_GET);jetzt:

Array
((
    [aa] => Array
        ((
            [0] => bb
            [1] => BB
        )

    [c_c] => dd
)

Anmerkungen:

  • Dieser Patch behandelt nur die ursprüngliche Frage (er ersetzt das Ersetzen von Punkten, nicht von Leerzeichen).
  • Das Ausführen dieses Patches ist schneller als Lösungen auf Skriptebene, aber diese reinen .php-Antworten sind im Allgemeinen immer noch vorzuziehen (da sie das Ändern von PHP selbst vermeiden).
  • Theoretisch ist hier ein Polyfill-Ansatz möglich, der Ansätze kombinieren könnte - Testen Sie die Änderung des C-Levels mithilfe von parse_str()(falls nicht verfügbar) Rückgriff auf langsamere Methoden.
bescheiden
quelle
1
Sie sollten es jedoch niemals so machen, +1 für die Anstrengung.
Rok Kralj
2

Meine Lösung für dieses Problem war schnell und schmutzig, aber ich mag es immer noch. Ich wollte einfach eine Liste von Dateinamen veröffentlichen, die auf dem Formular überprüft wurden. Ich habe base64_encodedie Dateinamen innerhalb des Markups codiert und sie dann einfach dekodiert, base64_decodebevor ich sie verwendet habe.

Jason
quelle
2

Nachdem ich mir Roks Lösung angesehen habe, habe ich eine Version entwickelt, die die Einschränkungen in meiner Antwort unten, die von crb oben und die Lösung von Rok ebenfalls behandelt. Siehe meine verbesserte Version .


Die Antwort von @ crb oben ist ein guter Anfang, aber es gibt ein paar Probleme.

  • Es verarbeitet alles wieder auf, was übertrieben ist; Nur die Felder mit einem "." im Namen müssen wiederaufbereitet werden.
  • Es behandelt Arrays nicht auf die gleiche Weise wie die native PHP-Verarbeitung, z. B. für Schlüssel wie "foo.bar []".

Die folgende Lösung behebt diese beiden Probleme jetzt (beachten Sie, dass sie seit der ursprünglichen Veröffentlichung aktualisiert wurde). Dies ist ungefähr 50% schneller als meine Antwort oben in meinen Tests, behandelt jedoch keine Situationen, in denen die Daten denselben Schlüssel haben (oder ein Schlüssel, der gleich extrahiert wird, z. B. foo.bar und foo_bar, werden beide als foo_bar extrahiert).

<?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]);                                       
            }                                                                  
        }                                                                      
    }                                                                          
}                                                                              
El Yobo
quelle
-1. Warum? 1. Leerzeichen %20ist auch ein Sonderzeichen, das in Unterstriche umgewandelt wird. 2. Ihr Code stellt alle Daten vor, da preg_match_allalles gescannt werden muss, obwohl Sie sagen, dass Sie dies nicht tun. 3. Ihr Code schlägt bei Beispielen wie folgt fehl : a.b[10]=11.
Rok Kralj
Sie haben Recht mit dem Weltraum, danke. Meine Erklärung weist bereits darauf hin, dass mein Ansatz keine Arrays behandelt, daher bin ich mir nicht ganz sicher, warum Sie darauf hinweisen. preg_match_allmuss eine Zeichenfolge "verarbeiten", nicht alle nicht betroffenen Schlüssel und Werte extrahieren und erneut verarbeiten, damit Sie auch dort ein wenig aus der Bahn geraten. Das heißt, Ihr Ansatz mit parse_stringsieht aus wie ein interessanter Ansatz, der mit ein wenig Optimierung besser sein könnte :)
El Yobo
Sie sagen, Sie extrahieren nur betroffene Schlüssel, aber in Bezug auf die Rechenkomplexität nicht. Sie sagen, Sie hatten einen zufälligen Zugriff, um nur die betroffenen Schlüssel abzurufen, aber selbst wenn keine betroffenen Schlüssel vorhanden sind, müssen Sie auf den gesamten Speicher zugreifen. Wenn Sie einen Beitrag mit 100 Megadaten haben, spielt es keine Rolle, was Sie extrahieren. Beide Ansätze sind linear O(n). Tatsächlich verschlechtern Sie die Komplexität, indem Sie die oben beschriebene in_array()Funktion verwenden.
Rok Kralj
Ich schaue einmal durch die 100 Megas, teile sie nicht auseinander (was den Speicher sofort verdoppelt) und teile sie dann wieder auf (verdopple sie erneut), wie bei der Methode von crb, bei der ich dies auch verglichen habe. Die Big O-Notation berücksichtigt die Speichernutzung überhaupt nicht, und diese Implementierung wird in_arrayohnehin nicht verwendet . Wenn Sie einige Tests durchführen möchten, werden Sie feststellen, dass die oben genannten Schritte immer noch erheblich schneller sind. nicht O (n) gegen O (n ^ 2), aber ein linearer Ansatz kann immer noch schneller sein als ein anderer ... und dieser ist;)
El Yobo
Der andere große Vorteil dieses Ansatzes besteht darin, dass der Geschwindigkeitsvorteil am größten ist, wenn überhaupt keine Arbeit zu erledigen ist, dh wenn keine Schlüssel mit Punkten oder Leerzeichen versehen wurden. Dies bedeutet, dass es nur einen minimalen Overhead hat, wenn Sie es ablegen, um alle Anforderungen zu verarbeiten, da es fast keine Arbeit erledigt (eine Regex), anstatt alle Schlüssel mehrmals zu extrahieren und zu codieren.
El Yobo
0

Nun, die Funktion "getRealPostArray ()", die ich unten einbinde, ist keine schöne Lösung, aber sie verarbeitet Arrays und unterstützt beide Namen: "alpha_beta" und "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>

während var_dump ($ _ POST) erzeugt:

  '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 ()) erzeugt:

  '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)

Die Funktion für das, was es wert ist:

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;
}
ChrisNY
quelle
0

Mit crbs wollte ich das $_POSTArray als Ganzes neu erstellen , aber denken Sie daran, dass Sie immer noch sicherstellen müssen, dass Sie sowohl auf dem Client als auch auf dem Server korrekt codieren und decodieren. Es ist wichtig zu verstehen, wann ein Charakter wirklich ungültig und wirklich gültig ist . Darüber hinaus sollten Benutzer weiterhin und immer Client-Daten maskieren, bevor sie ausnahmslos mit einem Datenbankbefehl verwendet werden .

<?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);
?>

Ich empfehle, dies nur für Einzelfälle zu verwenden. Ich bin mir nicht sicher, welche negativen Punkte es hat, wenn Sie dies oben in Ihre primäre Header-Datei einfügen.

John
quelle
0

Meine aktuelle Lösung (basierend auf den Antworten des vorherigen Themas):

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']);
sasha-ch
quelle
Bitte fügen Sie eine Erklärung hinzu, die für alle hilfreich ist, die Ihre Antwort lesen.
Prafulla Kumar Sahu