AngularJS HTTP-Post an PHP und undefiniert

107

Ich habe ein Formular mit dem Tag ng-submit="login()

Die Funktion wird in Javascript als fein bezeichnet.

function LoginForm($scope, $http)
{
    $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';

    $scope.email    = "[email protected]";
    $scope.password = "1234";

    $scope.login = function()
    {
        data = {
            'email' : $scope.email,
            'password' : $scope.password
        };

        $http.post('resources/curl.php', data)
        .success(function(data, status, headers, config)
        {
            console.log(status + ' - ' + data);
        })
        .error(function(data, status, headers, config)
        {
            console.log('error');
        });
    }
}

Ich erhalte eine 200-OK-Antwort von der PHP-Datei zurück, die zurückgegebenen Daten sagen dies jedoch emailund passwordsind undefiniert. Das ist alles was ich habe

<?php
$email = $_POST['email'];
$pass  = $_POST['password'];
echo $email;
?>

Irgendeine Idee, warum ich undefinierte POSTWerte erhalte ?

BEARBEITEN

Ich wollte darauf hinweisen, da dies eine beliebte Frage zu sein scheint (aber es ist alt) .successund .errorveraltet ist und Sie verwenden sollten, .thenwie @James Gentes in den Kommentaren hervorhob

Ronnie
quelle
2
Haben Sie sich die Registerkarte "Netzwerk" Ihrer Entwicklertools angesehen? Welcher Wert wird übergeben $http?
Marcel Korpel
1
In der Registerkarte Netzwerk unter Form-Dataes sagt{"email":"[email protected]","password":"1234"}
Ronnie
@ Ronnie Scheint wie JSON. Versuchen Sie print_r($_POST);und dann versuchen Sie json_decode()auf dem richtigen Index
HamZa
1
echo 'test';funktioniert gut. Ich zeige auf jeden Fall auf die richtige Datei
Ronnie
1
Beachten Sie, dass .success und .error veraltet sind und durch .then ( docs.angularjs.org/api/ng/service/$http ) ersetzt wurden
James Gentes

Antworten:

228

angularjs verwendet .post()standardmäßig den Header für den Inhaltstyp application/json. Sie überschreiben dies, um formularcodierte Daten zu übergeben. Sie ändern jedoch nicht Ihren dataWert, um eine geeignete Abfragezeichenfolge zu übergeben, sodass PHP nicht $_POSTwie erwartet ausgefüllt wird.

Mein Vorschlag wäre, einfach die Standardeinstellung anglejs von application/jsonals Header zu verwenden, die Roheingabe in PHP zu lesen und dann den JSON zu deserialisieren.

Das kann in PHP so erreicht werden:

$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
$email = $request->email;
$pass = $request->password;

Wenn Sie sich stark auf $_POSTFunktionalität verlassen, können Sie alternativ eine Abfragezeichenfolge wie diese bilden [email protected]&password=somepasswordund diese als Daten senden. Stellen Sie sicher, dass diese Abfragezeichenfolge URL-codiert ist. Wenn jQuery.serialize()Javascript manuell erstellt wird (im Gegensatz zur Verwendung von etwas Ähnlichem ), encodeURIComponent()sollte es den Trick für Sie tun.

Mike Brant
quelle
7
Ihr Wissen nicht zu missachten, aber zu verwenden file_get_contents("php://input");scheint eine Art Hack zu sein, nicht wahr? Ich habe noch nie davon gehört. Was muss passieren, damit ich es einfach so referenzieren kann$_POST['email'];
Ronnie
6
@ Ronnie Es ist kein Hack. Es hängt wirklich davon ab, wie Sie Ihren Webdienst einrichten möchten. Wenn Sie JSON senden und abrufen möchten, müssen Sie mit Roheingaben arbeiten, $_POSTdie nicht ausgefüllt werden.
Mike Brant
1
@lepe Es ist mir nicht klar, wie sich die verknüpfte Frage / Antwort auf meine Antwort bezieht. Es gibt hier keine Diskussion darüber, ein Javascript-Objekt serialisieren zu müssen.
Mike Brant
2
@lascort gibt es wirklich keinen großen Unterschied zu den Lösungen wirklich. In meiner Lösung fülle ich die Daten nicht in $ _POST, sondern bevorzuge stattdessen eine benutzerdefinierte Variable. Im Allgemeinen ist dies für mich insofern sinnvoller, als Sie bei der Arbeit mit JSON-serialisierten Daten möglicherweise mit Objekten oder numerisch indizierten Arrays arbeiten. Ich würde nicht vorschlagen, $ _POST ein numerisch indiziertes Array hinzuzufügen, da dies eine atypische Verwendung wäre. Ich scheue mich im Allgemeinen auch davor, Daten in die Superglobalen zu schreiben, die für Eingabedaten verwendet werden.
Mike Brant
1
@ItsmeJulian gibt es keine absolut richtige Antwort. Es kann wirklich davon abhängen, wie Ihre Anwendung aufgebaut ist. Wenn Sie mit einem REST-Service interagieren, der JSON verbraucht / bereitstellt, würde ich mich wahrscheinlich an den JSON-Inhaltstyp halten. Wenn ich größtenteils mit einem Endpunkt gearbeitet habe, der HTML- oder HTML-Fragmente erzeugen kann oder die einfache Formularveröffentlichung als Fallback für AJAX verwendet, bin ich möglicherweise geneigt, mich an die Formularcodierung zu halten.
Mike Brant
41

Ich mache es auf der Serverseite, am Anfang meiner Init-Datei, funktioniert wie ein Zauber und Sie müssen nichts in eckigem oder vorhandenem PHP-Code tun:

if ($_SERVER['REQUEST_METHOD'] == 'POST' && empty($_POST))
    $_POST = json_decode(file_get_contents('php://input'), true);
valmarv
quelle
3
Sie sollten Ihr Ergebnis umwandeln, falls $ _POST leer ist : $_POST = (array) json_decode(file_get_contents('php://input'), true).
M'sieur Toph '12.
Ich verstehe nicht wirklich, warum PHP-Leute dies nicht selbst implementiert haben. Sie erwarten wirklich immer URL-codierte Posts?
Azerafati
@Bludream Ich verstehe nicht, warum jemand erwartet, dass PHP das tut, was erwartet wird. Es verstößt ständig gegen das Prinzip der geringsten Überraschung.
Doug65536
Dies scheint ein sehr fragiler Ansatz zu sein, es sei denn, Sie wissen absolut, dass die POST-Daten ein assoziatives Array darstellen (eine Objektdarstellung in JSON). Was ist, wenn der JSON eine numerisch indizierte Array-Darstellung enthält? $_POSTwürde in diesen Fällen ein numerisch indiziertes Array erhalten, was in anderen Teilen des Systems, die auf einem konsistenten $_POSTsuperglobalen Verhalten beruhen, ein sehr unerwartetes Verhalten wäre.
Mike Brant
1
Ich benutze dies natürlich nur in Anwendungen mit Winkelantrieb und validiere meine POST-Daten sehr gründlich. Ich sehe nicht, wie das ein Problem sein kann ...
Valmarv
14

In der API, die ich entwickle, habe ich einen Basis-Controller und in seiner __construct () -Methode habe ich Folgendes:

if(isset($_SERVER["CONTENT_TYPE"]) && strpos($_SERVER["CONTENT_TYPE"], "application/json") !== false) {
    $_POST = array_merge($_POST, (array) json_decode(trim(file_get_contents('php://input')), true));
}

Dadurch kann ich die JSON-Daten bei Bedarf einfach als $ _POST ["var"] referenzieren. Funktioniert super.

Auf diese Weise antwortet die API fehlerfrei und reagiert, wenn sich ein authentifizierter Benutzer mit einer Bibliothek wie einer jQuery verbindet, die Post-Daten mit dem Standardwert Inhaltstyp: application / x-www-form-urlencoded oder Inhaltstyp: application / json sendet Machen Sie die API etwas entwicklerfreundlicher.

Hoffe das hilft.

Tim Wickstrom
quelle
11

Da PHP JSON nicht nativ akzeptiert 'application/json'Ein Ansatz besteht darin, Ihre Header und Parameter aus dem Winkel zu aktualisieren, damit Ihre API die Daten direkt verwenden kann.

Erstens , Parametrieren Ihre Daten:

data: $.param({ "foo": $scope.fooValue })

Fügen Sie dann Folgendes zu Ihrem hinzu$http

 headers: {
     'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8'
 }, 

Wenn alle Ihre Anforderungen an PHP gehen, können die Parameter in der Konfiguration wie folgt global festgelegt werden:

myApp.config(function($httpProvider) {
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
});
Malkus
quelle
8

Angular Js Demo Code: -

angular.module('ModuleName',[]).controller('main', ['$http', function($http){

                var formData = { password: 'test pwd', email : 'test email' };
                var postData = 'myData='+JSON.stringify(formData);
                $http({
                        method : 'POST',
                        url : 'resources/curl.php',
                        data: postData,
                        headers : {'Content-Type': 'application/x-www-form-urlencoded'}  

                }).success(function(res){
                        console.log(res);
                }).error(function(error){
                        console.log(error);
        });

        }]);

Serverseitiger Code: -

<?php


// it will print whole json string, which you access after json_decocde in php
$myData = json_decode($_POST['myData']);
print_r($myData);

?>

Aufgrund des Winkelverhaltens gibt es keine direkte Methode für das normale Post-Verhalten auf dem PHP-Server. Sie müssen es daher in JSON-Objekten verwalten.

Rajendra Khabiya
quelle
1
Das ist falsch. Siehe die obigen Antworten, in denen JSON direkt von der PHP-Roheingabe gelesen wird. Dies ist viel einfacher als das Mischen von JSON in eine Abfragezeichenfolge.
Mike Brant
Die Methoden .successund .errorsind veraltet und wurden aus dem AngularJS-Framework entfernt.
Georgeawg
6

Sie müssen Ihre Formulardaten deserialisieren, bevor Sie sie als zweiten Parameter an .post () übergeben. Sie können dies mit der $ .param (data) -Methode von jQuery erreichen. Dann können Sie auf der Serverseite darauf verweisen, wie $ .POST ['email'];

bahramzy
quelle
6

Dies ist die beste Lösung (IMO), da keine jQuery und keine JSON-Dekodierung erforderlich sind:

Quelle: https://wordpress.stackexchange.com/a/179373 und: https://stackoverflow.com/a/1714899/196507

Zusammenfassung:

//Replacement of jQuery.param
var serialize = function(obj, prefix) {
  var str = [];
  for(var p in obj) {
    if (obj.hasOwnProperty(p)) {
      var k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
      str.push(typeof v == "object" ?
        serialize(v, k) :
        encodeURIComponent(k) + "=" + encodeURIComponent(v));
    }
  }
  return str.join("&");
};

//Your AngularJS application:
var app = angular.module('foo', []);

app.config(function ($httpProvider) {
    // send all requests payload as query string
    $httpProvider.defaults.transformRequest = function(data){
        if (data === undefined) {
            return data;
        }
        return serialize(data);
    };

    // set all post requests content type
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
});

Beispiel:

...
   var data = { id: 'some_id', name : 'some_name' };
   $http.post(my_php_url,data).success(function(data){
        // It works!
   }).error(function() {
        // :(
   });

PHP-Code:

<?php
    $id = $_POST["id"];
?>
Lepe
quelle
Was ist mit: JSON.stringify('{ id: 'some_id', name : 'some_name' }')oder $httpParamSerializerfür die clientseitige Konvertierung?
qrtLs
5

Es ist eine alte Frage, aber es ist erwähnenswert, dass in Angular 1.4 $ httpParamSerializer hinzugefügt wird. Wenn Sie $ http.post verwenden und $ httpParamSerializer (params) verwenden, um die Parameter zu übergeben, funktioniert alles wie eine reguläre Post-Anfrage und keine JSON-Deserialisierung auf der Serverseite benötigt.

https://docs.angularjs.org/api/ng/service/$httpParamSerializer

Sep.
quelle
1

Ich habe Stunden gebraucht, um das zu verstehen, während ich mit Angular und PHP gearbeitet habe. Post-Daten gingen in $ _POST nicht an PHP

Gehen Sie im PHP-Code wie folgt vor. - Erstellen Sie eine Variable $ angle_post_params. - Führen Sie dann die folgenden Schritte aus $angular_http_params = (array)json_decode(trim(file_get_contents('php://input')));

Jetzt können Sie wie in $ _POST auf Ihre Parameter zugreifen

$angular_http_params["key"]

Für den Fall, dass Sie sich über Javascript wunderten ... das habe ich verwendet

    var myApp = angular.module('appUsers', []);
    //var post_params = $.param({ request_type: "getListOfUsersWithRolesInfo" });
    var dataObj = {
        task_to_perform: 'getListOfUsersWithRolesInfo'
    };

    myApp.controller('ctrlListOfUsers', function ($scope, $http) {
        $http({
            method: 'POST',
            dataType: 'json',
            url: ajax_processor_url,
            headers: {
                'Content-Type': 'application/json'
            },
            data: dataObj,
            //transformRequest: function(){},
            timeout: 30000,
            cache: false
        }).
        success(function (rsp) {
            console.log("success");
            console.log(rsp);
        }).
        error(function (rsp) {
            console.log("error");
        });
    });
Talha
quelle
für Neulinge ... vergessen Sie nicht, ng-app- und ng-controller-Direktiven zu Ihrem Inhaltsinhaber-Container auf der Seite hinzuzufügen :)
Talha
Die Methoden .successund .errorsind veraltet und wurden aus dem AngularJS-Framework entfernt.
Georgeawg