Ich stehe vor einem Problem, wenn ein entfernter Webclient mit langsamer Verbindung keine vollständige POST-Anfrage mit multipart/form-data
Inhalt senden kann, aber PHP verwendet noch teilweise empfangene Daten, um $_POST
-Array aufzufüllen. Daher kann ein Wert in $_POST
-Array unvollständig sein und mehr Werte können fehlen. Ich habe versucht, dieselbe Frage in Apache-Liste zuerst und bekam eine Antwort , dass Apache den Anfragetext nicht zwischenspeichert und ihn als PHP an das PHP-Modul weiterleitet
riesiger Klecks.
Hier ist meine Beispiel-POST-Anfrage:
%Vor% Sie können sehen, dass Content-Length
ist 10000
Bytes, aber ich sende nur eine var a=A
.
Das PHP-Skript ist:
%Vor%Der Webserver wartet ungefähr 10 Sekunden auf den Rest meiner Anfrage (aber ich sende nichts) und gibt dann diese Antwort zurück:
%Vor% Hier ist meine Frage: Wie kann ich in PHP verifizieren, dass die Postanfrage vollständig empfangen wurde? $_SERVER['CONTENT_LENGTH']
würde 10000
aus dem Anfrage-Header anzeigen, aber gibt es eine Möglichkeit, die tatsächliche Länge des Inhalts zu überprüfen?
Ich vermute, dass der Remote-Client eigentlich ein Browser mit HTML-Seite ist. Ansonsten lass es mich wissen und ich werde versuchen, meine Lösung anzupassen.
Sie können das Feld <input type="hidden" name="complete">
(zum Beispiel) als den letzten Parameter hinzufügen. in PHP
überprüfen Sie zuerst, ob dieser Parameter vom Client gesendet wurde. Wenn dieser Parameter gesendet wird, können Sie sicher sein, dass Sie alle Daten erhalten haben.
Nun bin ich nicht sicher, ob die Reihenfolge der Parameter gemäß RFC (sowohl HTML als auch HTTP) erhalten bleiben muss. aber ich habe einige Variationen ausprobiert und ich habe gesehen, dass die Reihenfolge in der Tat eingehalten wurde.
Bessere Lösung wird sein, berechnen (auf der Client-Seite) Hash der Parameter und senden Sie ihn als einen anderen Parameter. So können Sie absolut sicher sein, dass Sie die gesamten Daten erhalten haben. Aber das klingt kompliziert ...
Soweit ich weiß, gibt es keine Möglichkeit zu überprüfen, ob die Größe des empfangenen Inhalts mit dem Wert des Headers Content-Length
übereinstimmt, wenn Sie multipart/form-data
als Content-Type
verwenden, weil Sie den rohen Inhalt nicht erhalten können.
1) Wenn Sie Content-Type
(z. B. application/x-www-form-urlencoded
) ändern können, können Sie php://input
lesen, das den unformatierten Inhalt der Anfrage enthält. Die Größe von php://input
sollte mit Content-Length
übereinstimmen (vorausgesetzt, der Wert von Content-Length
ist korrekt). Wenn es eine Übereinstimmung gibt, können Sie $_POST
verwenden, um den verarbeiteten Inhalt (reguläre Postdaten) zu erhalten. Lies über php://input
hier .
2) Oder Sie können die Daten auf dem Client serialisieren und als text/plain
senden. Der Server kann die Größe wie oben beschrieben überprüfen. Der Server muss den empfangenen Inhalt deserialisieren, um damit arbeiten zu können. Und wenn der Client einen Hash der serialisierten Daten generiert und diese in einem Header (zB X-Content-Hash
) mitschickt, kann der Server auch einen Hash erzeugen und prüfen, ob er mit dem im Header übereinstimmt. Sie müssen den Hash nicht überprüfen und können zu 100% sicher sein, dass der Inhalt korrekt ist.
3) Wenn Sie Content-Type
nicht ändern können, benötigen Sie etwas anderes als die Größe, um den Inhalt zu überprüfen. Der Client könnte einen zusätzlichen Header (etwas wie X-Form-Data-Fields
) verwenden, um die Felder / Schlüssel / Namen des von Ihnen gesendeten Inhalts zu summieren. Der Server könnte dann prüfen, ob alle in der Kopfzeile genannten Felder im Inhalt vorhanden sind.
4) Eine andere Lösung wäre, dass der Client einen vordefinierten Schlüssel / Wert als letzten Eintrag im Inhalt hat. Etwas wie:
%Vor%Der Server kann überprüfen, ob dieses Feld im Inhalt vorhanden ist, wenn dies der Fall ist, muss der Inhalt vollständig sein.
update
Wenn Sie binäre Daten übergeben müssen, können Sie Option 1 nicht verwenden, können aber weiterhin Option 2 verwenden:
Der Client kann base64
die binären Einträge codieren, die Daten serialisieren (mit jeder beliebigen Technik), einen Hash der serialisierten Daten generieren, den Hash als Header und die Daten als Body senden.
Der Server kann einen Hash des empfangenen Inhalts generieren, den Hash mit dem im Header überprüfen (und eine Nichtübereinstimmung melden), den Inhalt deserialisieren, base64
die Binäreinträge dekodieren.
Das ist ein bisschen mehr Arbeit, als einfach multipart/form-data
zu verwenden, aber der Server kann mit einer 100% igen Garantie verifizieren, dass der Inhalt der gleiche ist wie der, den der Client gesendet hat.
In Bezug auf Formularwerte, die aufgrund von Konnektivitätsproblemen vollständig fehlen, können Sie einfach überprüfen, ob sie festgelegt sind:
%Vor%Für die großen Formulardaten (z. B. ein Bildupload) können Sie die Größe der empfangenen Datei mit
überprüfen %Vor%Eine einfache Lösung verwendet möglicherweise JavaScript, um die Dateigröße auf der Clientseite zu berechnen und diesen Wert als verdeckte Eingabe beim Senden des Formulars an das Formular anzufügen. Sie erhalten die Dateigröße in JS mit etwas wie
%Vor%Referenz: Validierung der Größe von JavaScript-Dateiuploads
Wenn die Eingabe des versteckten Formulars beim Hochladen der Datei der Größe der hochgeladenen Datei entspricht, wurde die Anfrage nicht durch Probleme mit der Netzwerkverbindung unterbrochen.
Ich würde auch empfehlen, einen hidden
-Wert zu verwenden, oder Hashing wie MeNa erwähnt. (Das Problem besteht darin, dass einige Algorithmen anders als Plattformen implementiert sind, so dass sich Ihr CRC32 in js von einem CRC32 in PHP unterscheidet. Aber mit einigen Tests sollten Sie in der Lage sein, einen kompatiblen zu finden)
Ich werde vorschlagen, symmetrische Verschlüsselung zu verwenden, nur für die Tatsache, dass es eine Option ist. (Ich glaube nicht, dass es schneller ist als Hashing). Verschlüsselung bietet neben Vertraulichkeit auch Integrität, d. ist diese empfangene Nachricht diejenige, die gesendet wurde.
Obwohl Streamcipher sehr schnell sind, können Blockcipher wie AES auch sehr schnell sein, aber das hängt von Ihrem System, den verwendeten Sprachen usw. ab (auch hier bedeuten verschiedene Implementierungen, dass nicht alle Verschlüsselungen gleich sind)
Wenn Sie die Nachricht nicht entschlüsseln können (oder es zu einem verzerrten Chaos kommt), war die Nachricht unvollständig.
Aber ernsthaft , verwenden Sie Hashing. Hasse den POST auf dem Client, überprüfe zuerst die Länge des Hashs auf dem Server. (Einige?) Hashes sind feste Länge, wenn also die Länge nicht übereinstimmt, ist es falsch. Hash-Hash für den empfangenen POST und Vergleich mit dem POST-Hash. Wenn Sie dies über den gesamten POST in einer bestimmten Reihenfolge tun (so dass jede Neuanordnung rückgängig gemacht wird), ist der Overhead minimal.
All dies setzt voraus, dass Sie die Post-Nachricht nicht überprüfen können, um zu sehen, ob Felder fehlen und is_set == True, length & gt; 0,! Leer () ...
Ich denke, was Sie suchen, ist $ HTTP_RAW_POST_DATA , das wird Ihnen das geben echte POST-Länge und dann können Sie es mit $ _SERVER ['CONTENT_LENGTH'] vergleichen.
Ich glaube nicht, dass es möglich ist, die ursprüngliche Inhaltsgröße von $ _REQUEST superglobal zu berechnen, zumindest für mehrteilige / Formulardatenanforderungen.
Ich würde Ihrer HTTP-Anfrage einen benutzerdefinierten Header mit allen parameter = Wert-Hash hinzufügen, der serverseitig überprüft werden soll. Header werden sicher ankommen, so dass Ihr Hash-Header immer da ist. Stellen Sie sicher, dass Parameter in der gleichen Reihenfolge verknüpft werden, da andernfalls der Hashwert anders ist. Achten Sie auch auf Codierung, muss auf Client und Server identisch sein.
Wenn Sie Apache konfigurieren können, können Sie einen vhost mit mod_proxy hinzufügen, der so konfiguriert ist, dass er auf einem anderen vhost auf demselben Server als Proxy fungiert. Dies sollte unvollständige Anfragen filtern. Beachten Sie, dass Sie auf diese Weise 2 Sockets pro Anfrage verschwenden. Behalten Sie also die Ressourcennutzung im Auge, wenn Sie so denken.
Eine andere Lösung, die nützlich sein könnte ... Wenn die Verbindung von der anderen Seite langsam ist, entfernen Sie einfach das Limit für die Ausführung des Posts.
%Vor%Und Sie werden sicher sein, dass die Lochpostdaten gesendet werden.
Wenn das Berechnen der Inhaltslänge nicht sinnvoll ist, könnten Sie wahrscheinlich die vom Client gesendeten Daten signieren.
Unter Verwendung von JavaScript serialisieren Sie die Formulardaten in einer vernünftig vernünftigen Art und Weise in eine JSON-Zeichenfolge oder ein Äquivalent (d. h. sortieren Sie sie nach Bedarf), bevor Sie sie übergeben. Hash diese Zeichenfolge mit einem oder zwei recht schnellen Algorithmen (z. B. crc32, md5, sha1), und fügen Sie diese zusätzlichen Hash-Daten zu dem, was als Signatur gesendet werden soll.
Entfernen Sie auf dem Server diese zusätzlichen Hash-Daten aus der $ _POST-Anfrage und wiederholen Sie die gleiche Arbeit in PHP. Vergleichen Sie die Hashes entsprechend: Nichts geht in der Übersetzung verloren, wenn die Hashes übereinstimmen. (Verwenden Sie zwei Hashwerte, wenn Sie das winzige Risiko, falsch positive Ergebnisse zu erhalten, aufheben möchten.)
Ich wette, dass es ein vernünftiges Mittel gibt, etwas Ähnliches für Dateien zu tun, z.B. ihren Namen und ihre Größe in JS holen und diese zusätzlichen Informationen zu den Daten hinzufügen, die signiert werden.
Dies hängt etwas mit dem zusammen, was einige PHP-Frameworks tun, um Manipulationen an Sitzungsdaten zu vermeiden, wenn diese in clientseitigen Cookies verwaltet und gespeichert werden. Daher finden Sie wahrscheinlich im späteren Kontext leicht verfügbaren Code .
Ursprüngliche Antwort:
Soweit mir bekannt ist, besteht der Unterschied zwischen dem Senden einer GET- oder einer POST-Anfrage mehr oder weniger auf Mengen, die etwas wie:
senden %Vor%vs Senden von etwas wie:
%Vor%Sie können also für jeden Teil die Länge berechnen und diese gegen die Länge überprüfen, die durch den Inhalt-Länge-Header angekündigt wird.
$_FILES
Einträge haben ein praktisches Größenfeld, das Sie direkt verwenden können. $_POST
data die gesandte Abfragezeichenfolge neu und berechnen Sie deren Länge. Zu beachtende Punkte:
var[]=foo&var[]=baz
vs var[0]=foo&var[1]=baz
Weiterführende Literatur:
Verwenden Sie die Ausgabepufferung mit ob_start (). Während die Ausgabepufferung aktiv ist, wird keine Ausgabe vom Skript (außer den Headern) gesendet, stattdessen wird die Ausgabe in einem internen Puffer gespeichert.
Der Inhalt dieses internen Puffers kann mit ob_get_contents () in eine String-Variable kopiert werden. Verwenden Sie ob_end_flush (), um auszugeben, was im internen Puffer gespeichert ist. Alternativ verwirft ob_end_clean () den Pufferinhalt automatisch.
Tags und Links php apache multipartform-data post content-length