10

I try to post data from angular 2 to php:

let headers = new Headers();
headers.append('Content-Type', 'application/json');
var order = {'order': this.orders};

this.http.post('http://myserver/processorder.php', JSON.stringify(order), {
    headers: headers
}).subscribe(res => {
    console.log('post result %o', res);
});

In angular 2 one can only post string as data and not Json? That's ok for me but I struggle to get the posted data on php. I tried $obj = $_POST['order'];

1
  • 1
    PHP expects post data to be in key=value pairs when it's building $_POSt. you didn't sent that, you sent a raw json string, which is basically just the value component. since there's no key, php can't put anything into $_POST, because an array item must have a key. you could probably retrieve the json by reading from php://input. Commented Feb 10, 2016 at 21:07

4 Answers 4

9

Marc B is correct, however what is happening is that the $_POST array will contain an empty value with a key set to the JSON string you are passing...

Array
(
    [{"order":"foobar"}] => 
)

You "can" grab that (although this would be the wrong approach) by getting the key using...

key($_POST)

for example:

$obj = json_decode(key($_POST));
echo $obj->order;

BUT what you can do is send the data as value key pairs:

let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
let order = 'order=foobar';

this.http.post('http://myserver/processorder.php', order, {
    headers: headers
}).subscribe(res => {
    console.log('post result %o', res);
});

Then in PHP you can grab the data using:

$_POST['order']

Few things to note:

  • changed header Content-Type to application/x-www-form-urlencoded (more for my own testing since this doesn't do any preflight requests)
  • notice that order is a key value pair string instead of JSON
  • notice that order in this.http.post is getting passed as-is without JSON.stringify
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you it worked for me :) 4 hours search finally :)
@inki: let order = 'order=foobar'; sends one data. Can you please help me to send multiple data. Can you please give me syntax.
@GreenComputers do it like = 'order=foobar&anotherkey=anothervalue&key3=value3' Separate your variables using & sign
5

I do not know if it's bad practice but it seems right to me, although it bothers me a little

const headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');

const obj = { nome: 'gabriel', age: 20 };
const body = 'data=' + JSON.stringify(obj);

this.http.post('/test.php', body, { headers })
  .subscribe(res => console.log(res.json()), res => console.error(res))

And in php

$post = json_decode($_POST['data']);

Comments

2

Agreed with you that we can't at the moment provide object instead of string. It's a feature in progress. See this issue:

Regarding your problem to get JSON data on the server side, this question should help you:

Comments

0

Hey if you are still reading this in 2023... I followed @Gabriel Martins answer above and that got me most of the way there... but adding 'data=' into the call was unncessary due to me choosing to use "php://input".

This project is currently in development and using Apache, php (8.1), Angular 16.

So my front end call (Using Angular 16) looks like the following:

public createPost(form: any){
    let headers = new HttpHeaders();
    headers.append('Accept', 'application/x-www-form-urlencoded');
    headers.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8')
    //method value below is 'createPost'
    let obj = JSON.stringify(Object.assign(form, {method: environment.endpoints.createPost.method}));
    return this.http.post(environment.origin + environment.endpoints.createPost.url, obj, {['headers']: headers}).pipe()
    //At this point, everything is almost the same as Gabriel's answer.
  }

And my backend code (using PDO for mysql) and a small custom library is:

<?php

namespace System;

class Request {
    
    private $headers = [];
    private $method = [];
    private $inputs = [];
    private $files = [];
    
    public static $instance;
    
    public function __construct() {
        self::$instance = $this;
        $this->headers = apache_request_headers();
        $this->method = strtolower($_SERVER['REQUEST_METHOD']);
        
        if($this->method == 'post'){
            //This is one spot where our answers are different. 
            //The addition of 'data=' causes unneeded parsing here. 
            //Just passing a stringified JSON seemed to work better. 
            //Note the second argument for true to json_decode.
            $input = json_decode(file_get_contents("php://input"), true);
            if(isset($this->headers['Content-Type'])){
                $content_type = $this->headers['Content-Type'];

                if($content_type == 'application/x-www-form-urlencoded' || strstr($content_type, 'text/plain')){
                    foreach($input as $key=>$value){
                        $this->inputs[$key] = filter_var($value, FILTER_DEFAULT);
                    }
                }
            }
        }
    }
    /**
     * returns this class instance
     * @return self
     */
    public static function get(){
        if(self::$instance === null){
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * returns the method used to access the current request
     * @return string
     */
    public function get_method() : string{
        return $this->method;
    }
    
    /**
     * returns all the headers in the current request
     * @return array
     */
    public function get_headers() : array{
        return $this->headers;
    }
    
    /**
     * returns the header or null by key
     * @param string $key
     * @return type
     */
    public function get_header(string $key){
        return $this->headers[$key] ?? null;
    }
    
    /**
     * returns the input value in the request or null
     * @param string $var
     * @return type
     */
    public function get_input(string $var){
        return $this->inputs[$var] ?? null;
    }
    
    /**
     * returns all the input fields in the current request
     * @return array
     */
    public function get_all_inputs(): array{
        return $this->inputs;
    }
    
    public function get_files(): array{
        return $this->files;
    }
}
?>

The public API code that actually calls my PDO library is:

<?php
    require_once(__DIR__."/../Models/BlogPosts.php");
    require_once(__DIR__."/../System/Request.php");
    
    $blogModel = new \Models\BlogPost();
    $req = \System\Request::get();
    
    switch($req->get_input('method')){
        case 'createPost':
            print_r($blogModel->createPost(
                $req->get_input('url'),
                $req->get_input('title'),
                $req->get_input('description'),
                $req->get_input('author'),
                $req->get_input('category'),
                $req->get_input('sequence'),
                $req->get_input('image'),
                $req->get_input('imageWebp'),
                $req->get_input('content')
            ));
            break;
        case 'getFullPostByID':
            print_r($blogModel->getFullPostByID($req->get_input('id')));
            break;
        case 'getAllPosts':
            print_r($blogModel->getAllBasicPostInfo());
            break;
    }

?>

Anyway, I hope that helps someone.. I also made sure to append a slash at the end of the request URL, to send the request to 'api/posts.php/' instead of 'api/posts.php'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.