Jest to pomocne pytanie dla osób, które chcą tworzyć interfejsy API RESTful. Większość nie wie, jak uzyskać dostęp do surowych danych wejściowych przesłanych do ich skryptów, ponieważ nie są one dostępne przez $_POSTsuperglobal. Jest to również (szczególnie) prawdziwe w przypadku żądań PUT, ponieważ PHP nie ma odpowiadającego superglobala.
Warto zauważyć, że nazwa $ _POST jest myląca, ponieważ nie będzie tam żadnych danych z żądania POST, ale tylko wtedy, gdy typem treści jest application / x-www-form-urlencoded lub multipart / form-data
Petruza
Odpowiedzi:
549
Aby uzyskać dostęp do treści encji żądania POST lub PUT (lub dowolnej innej metody HTTP):
$entityBody = file_get_contents('php://input');
Ponadto STDINstała jest już otwartym strumieniem do php://input, więc możesz alternatywnie:
Dane wejściowe php: // to strumień tylko do odczytu, który umożliwia odczytanie surowych danych z treści żądania. W przypadku żądań POST lepiej jest używać danych wejściowych php: // zamiast, $HTTP_RAW_POST_DATAponieważ nie zależy to od specjalnych dyrektyw php.ini. Ponadto w przypadkach, w których
$HTTP_RAW_POST_DATAdomyślnie nie jest zapełniany, jest to potencjalnie mniej obciążająca pamięć alternatywa dla aktywacji always_populate_raw_post_data. dane wejściowe php: // nie są dostępne z enctype = "multipart / form-data".
W szczególności należy zauważyć, że php://inputstrumień, niezależnie od tego, w jaki sposób uzyskujesz do niego dostęp w internetowym SAPI, nie jest widoczny . Oznacza to, że można go odczytać tylko raz. Jeśli pracujesz w środowisku, w którym duże jednostki HTTP są rutynowo przesyłane, możesz chcieć zachować dane wejściowe w formie strumienia (zamiast buforować je jak w pierwszym przykładzie powyżej).
Aby zachować zasób strumienia, pomocne może być coś takiego:
php://temppozwala zarządzać zużyciem pamięci, ponieważ po przejściu pewnej ilości danych (domyślnie 2 MB) przełączy się na pamięć systemu plików. Rozmiarem tym można manipulować w pliku php.ini lub przez dołączenie /maxmemory:NN, gdzie NNjest maksymalna ilość danych przechowywanych w pamięci przed użyciem pliku tymczasowego, w bajtach.
Oczywiście, chyba że masz naprawdę dobry powód, aby szukać w strumieniu wejściowym, nie powinieneś potrzebować tej funkcji w aplikacji internetowej. Zwykle wystarczające jest przeczytanie treści jednostki żądania HTTP - nie zmuszaj klientów do czekania przez cały dzień, podczas gdy aplikacja wymyśli, co zrobić.
Zauważ, że wejście php: // nie jest dostępne dla żądań określających Content-Type: multipart/form-datanagłówek ( enctype="multipart/form-data"w formularzach HTML). Wynika to z parsowania przez PHP danych formularza na $_POSTsuperglobal.
Należy pamiętać, że afaics, strumień STDIN nie jest dostępny w systemach z PHP korzystającym z CGI, tj. Przez mod_fcgid lub mod_fastcgi itp.
scy
ale przekazuję zmienną (jako dane formularza) z żądaniem, w jaki sposób mogę uzyskać dostęp do określonej wartości, przekazuję grant_type = hasło i nazwa użytkownika = użytkownik i hasło = podaj jako treść danych formularza z żądaniem, w jaki sposób otrzymam typ_zgody z „$ entityBody ”
Anvar Pk
według mojego testu php://inputjest to również puste dla typu application/x-www-form-urlencodedzawartości (poza tym multipart/form-data)
YakovL
6
Aby rozwinąć odpowiedź @ scy: STDIN jest niedostępny, ale php://inputjest. Tak więc, gdy konfiguracje CGI (szybkie) stream_get_contents(STDIN)nie będą działać, file_get_contents("php://input")będą działać .
W tym scenariuszu musisz teraz przechodzić przez $datatablicę asocjacyjną, aby sprawdzić, czy każda wartość jest zakodowana w pożądany sposób. Sposób patrzenia na „typ strumienia danych” może być uproszczony, ale może nie być tak skuteczny, jak radzenie sobie z kodowaniem w „formie strumienia” za pomocą filtra strumienia. Jeśli nie zajmujesz się problemami z kodowaniem, a jedynie odkażaniem i sprawdzaniem poprawności, brakuje Ci kroku.
Anthony Rutledge
13
Możliwym powodem pustego $_POSTjest to, że żądanie nie jest POSTlub POSTjuż nie jest ... Być może zaczęło się jako post, ale napotkało gdzieś 301lub 302przekierowało, na które zostało przełączone GET!
function getPost(){if(!empty($_POST)){// when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request// NOTE: if this is the case and $_POST is empty, check the variables_order in php.ini! - it must contain the letter Preturn $_POST;}// when using application/json as the HTTP Content-Type in the request
$post = json_decode(file_get_contents('php://input'),true);if(json_last_error()== JSON_ERROR_NONE){return $post;}return[];}
print_r(getPost());
To, czego brakuje w tym logice, to test wartości znalezionej w nagłówku Content-Type. Nie wynika z tego, że tylko dlatego, że $ _POST jest pusty, JSON musiał zostać przesłany, lub jeśli json_last_error() == JSON_ERROR_NONEtak false, to że pusta tablica powinna zostać zwrócona. Co jeśli ktoś przesłał XML lub YAML? Dodaj test dla Content-Type i stamtąd.
Anthony Rutledge
Ponadto metoda żądania HTTP może brać pod uwagę to, czy chcesz zaakceptować dane wejściowe. Zobacz $_SERVERsuperglobal, aby sprawdzić przydatne wartości.
$_POST
superglobal. Jest to również (szczególnie) prawdziwe w przypadku żądań PUT, ponieważ PHP nie ma odpowiadającego superglobala.Odpowiedzi:
Aby uzyskać dostęp do treści encji żądania POST lub PUT (lub dowolnej innej metody HTTP):
Ponadto
STDIN
stała jest już otwartym strumieniem dophp://input
, więc możesz alternatywnie:Z ręcznego wpisu PHP w dokumentach strumieni we / wy :
W szczególności należy zauważyć, że
php://input
strumień, niezależnie od tego, w jaki sposób uzyskujesz do niego dostęp w internetowym SAPI, nie jest widoczny . Oznacza to, że można go odczytać tylko raz. Jeśli pracujesz w środowisku, w którym duże jednostki HTTP są rutynowo przesyłane, możesz chcieć zachować dane wejściowe w formie strumienia (zamiast buforować je jak w pierwszym przykładzie powyżej).Aby zachować zasób strumienia, pomocne może być coś takiego:
php://temp
pozwala zarządzać zużyciem pamięci, ponieważ po przejściu pewnej ilości danych (domyślnie 2 MB) przełączy się na pamięć systemu plików. Rozmiarem tym można manipulować w pliku php.ini lub przez dołączenie/maxmemory:NN
, gdzieNN
jest maksymalna ilość danych przechowywanych w pamięci przed użyciem pliku tymczasowego, w bajtach.Oczywiście, chyba że masz naprawdę dobry powód, aby szukać w strumieniu wejściowym, nie powinieneś potrzebować tej funkcji w aplikacji internetowej. Zwykle wystarczające jest przeczytanie treści jednostki żądania HTTP - nie zmuszaj klientów do czekania przez cały dzień, podczas gdy aplikacja wymyśli, co zrobić.
Zauważ, że wejście php: // nie jest dostępne dla żądań określających
Content-Type: multipart/form-data
nagłówek (enctype="multipart/form-data"
w formularzach HTML). Wynika to z parsowania przez PHP danych formularza na$_POST
superglobal.źródło
php://input
jest to również puste dla typuapplication/x-www-form-urlencoded
zawartości (poza tymmultipart/form-data
)php://input
jest. Tak więc, gdy konfiguracje CGI (szybkie)stream_get_contents(STDIN)
nie będą działać,file_get_contents("php://input")
będą działać .zwraca wartość w tablicy
źródło
$data
tablicę asocjacyjną, aby sprawdzić, czy każda wartość jest zakodowana w pożądany sposób. Sposób patrzenia na „typ strumienia danych” może być uproszczony, ale może nie być tak skuteczny, jak radzenie sobie z kodowaniem w „formie strumienia” za pomocą filtra strumienia. Jeśli nie zajmujesz się problemami z kodowaniem, a jedynie odkażaniem i sprawdzaniem poprawności, brakuje Ci kroku.Możliwym powodem pustego
$_POST
jest to, że żądanie nie jestPOST
lubPOST
już nie jest ... Być może zaczęło się jako post, ale napotkało gdzieś301
lub302
przekierowało, na które zostało przełączoneGET
!Sprawdź,
$_SERVER['REQUEST_METHOD']
czy tak jest.Zobacz https://stackoverflow.com/a/19422232/109787, aby uzyskać dobre omówienie, dlaczego tak się nie stało, ale nadal tak jest.
źródło
POST
ale po sprawdzeniu okazała się, że byłaGET
. Po dodaniu/
na końcu mojego adresu URL zaczął on wyświetlać POST. Dziwne!Sprawdź
$HTTP_RAW_POST_DATA
zmiennąźródło
php://input
.$HTTP_RAW_POST_DATA
nie jest dostępny zenctype="multipart/form-data"
.Jeśli masz zainstalowane rozszerzenie HTTP PECL, możesz skorzystać z
http_get_request_body()
funkcji, aby uzyskać dane treści jako ciąg.źródło
Jeśli masz zainstalowane rozszerzenie pecl / http , możesz również użyć tego:
źródło
źródło
json_last_error() == JSON_ERROR_NONE
takfalse
, to że pusta tablica powinna zostać zwrócona. Co jeśli ktoś przesłał XML lub YAML? Dodaj test dla Content-Type i stamtąd.$_SERVER
superglobal, aby sprawdzić przydatne wartości.http_get_request_body()
został wyraźnie wykonany w celu uzyskania treściPUT
iPOST
wniosków zgodnie z dokumentacją http://php.net/manual/fa/function.http-get-request-body.phpźródło