2

I've tried searching, the other answers didn't help me.

I'm trying to send POST data via cURL, but it's only working on some servers. What gives?

I've tried:

if (!empty($data) && $usePost) {
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
}

$data contains an array with the key of products and the value of a JSON string.

I also tried explicitly using the query:

if (!empty($data) && $usePost) {
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
}

But still, $_POST on the receiving server gives me NULL.

Any idea what to do?

Here's the whole method:

public static function execCommand($command, $ch,$data=array(),$cookie_file='genCookie.txt', $usePost = false) {
    $url = $command;
    if (!empty($data) && !$usePost)
        $url .= '?' . http_build_query($data);
    elseif (isset($data['sessionid'])) {
        $url .= '?sessionid=' . $data['sessionid'];
        unset($data['sessionid']);
    }

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; rv:21.0) Gecko/20100101 Firefox/21.0');
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

    if (!empty($data) && $usePost) {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }

    return curl_exec($ch);
}

I tried echoing $_REQUEST, so it's not in $_GET by mistake. I also tried file_get_contents('php://input'), but still nothing.

Both the sending and receiving ends are on Apache servers.

Bigger thing is, it's working on most servers, but only some are ignoring it. Is there a safer, more cross platform way to do this?

casraf
  • 21,085
  • 9
  • 56
  • 91

6 Answers6

4

I find it difficult to believe that Curl is not sending "post" fields to some servers (the code you shared looks OK). I would rather assume that there is something wrong with how you handle POST on those servers or you do something wrong elsewhere.

You can troubleshoot with tcpdump

$ sudo tcpdump -nl -w - -s0 -A -c 500 tcp port 80 | strings

Now if you run an example code like:

<?php

class Curl {

    protected static function getCurlHandler( $url, $data = false, $headers = false ) {
        $ch =  curl_init(); 

        curl_setopt( $ch, CURLOPT_URL, $url );
        curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
        curl_setopt( $ch, CURLOPT_HEADER, 0 );

        if( $headers ) {
            curl_setopt($ch, CURLINFO_HEADER_OUT, true);
            curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers );
        }

        if( $data ) {
            curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query( $data ) );
        }

        return $ch;
    }

    protected static function exec( $ch ) {
        $output = curl_exec( $ch );

        // handle errors

        curl_close( $ch );
        return $output;
    }

    public static function get( $url, $headers = array() ) {
        $ch = self::getCurlHandler( $url, false, $headers );

        return self::exec( $ch );
    }

    public static function post( $url, $data = array(), $headers = array() ) {
        $ch = self::getCurlHandler( $url, $data, $headers );
        curl_setopt( $ch, CURLOPT_POST, 1 );

        return self::exec( $ch );
    }

    public static function put( $url, $data = array(), $headers = array() ) {
        $ch = self::getCurlHandler( $url, $data, $headers );
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");

        return self::exec( $ch );
    }

    public static function delete( $url, $data = array(), $headers = array() ) {
        $ch = self::getCurlHandler( $url, $data, $headers );
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");

        return self::exec( $ch );
    }

}


Curl::post( "http://www.google.com", array('q' => 'hello world'));

You should find something like this in the TCPDUMP output

POST / HTTP/1.1
Host: www.google.com
Accept: */*
Content-Length: 13
Content-Type: application/x-www-form-urlencoded
q=hello+world

The last line is the most interesting bit which clearly shows that CURL sent a POST request with the required data.

Lukasz Kujawa
  • 3,026
  • 1
  • 28
  • 43
1

Your alternative is to use wget which essentially downloads a file from a location. It is probably going to be a bit slower as you need to then open the file you download and delete the space. I am not confident it scales well and it's not going to be good for POST requests. cURL works using port 80, which is the basic browser port. That means that if you can access it via a browser, cURL will work.

Through the limited information you gave I can provide some troubleshooting tips.

In this instance I am calling your PHP server that initiates the request the client and the server you are sending information to the server.

The first thing you should do is make sure that this is working on your server. Check your source code.

Step 1. Try to submit a form and make sure $_POST returns information. If it does, you can move on. If it doesn't you have a very, very strange bug. I would be interested to know if you are using different OSes on these different servers.

Step 2. Check your server sessionid. Make sure your client is expecting them to come via GET. I know this may seem obvious, but many times the obvious is the source of failure. What does your server do if your sessionid fails? Make sure your processing script returns something like:

if(session_is_registered($_GET['sessionid']) {
    echo "This is a registered session.";
    $_POST['debugSessionExists'] = true;
} else {
    echo "This sesion does not exist.";
    $_POST['debugSessionExists'] = false;
}

You should be able to spit out return data on your client too thanks to the echo.

Step 3. Do the same thing for all of your $_POST variables and echo a return.

foreach($_POST as $key=>$value) {
    echo "{$key} exists and has the value of $value.<BR />";
}
echo "Done checking $_POSTs.";

The reason I advise this is because I am not sure how you have been checking your $_POST values to date and it doesn't hurt to see if your cURL response is getting information you are not seeing. This means that the way you are storing your $_POST values is just not transferring on some of your servers and that is your point of failure.

I will be interested to find out what is returned via these results.

smcjones
  • 5,490
  • 1
  • 23
  • 39
0

As mentioned earlier, you might need to do tcpdump to see exactly how the data is going to the server.

You might be running into the 'Expect' header with curl which can be disabled:

http://the-stickman.com/web-development/php-and-curl-disabling-100-continue-header/

By disabling the Expect header, there is a perf. advantage of avoiding additional round-trips between the client and the server albeit at the cost of bypassing additional checks on the server side (e.g. enforcing maximum POST body size etc...).

Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
jrm
  • 341
  • 1
  • 2
0

Try debugging with http://req.uest.info/

Also have you checked the logs of your originating server?

Chris Gunawardena
  • 6,246
  • 1
  • 29
  • 45
0

Bigger thing is, it's working on most servers, but only some are ignoring it.

The POST is sent ok, but the server differ. For starters, compare the PHP versions.

For example; since PHP 4.2.0 register_globals is off, which could give similar NULL results if the receiving end reuses variable names like $foo VS $_POST['foo'].

Is there a safer, more cross platform way to do this?

No, a POST is a good way to send data. But keep in mind that data is sent plaintext over the wire unless you use encryption or https.

Barry Staes
  • 3,890
  • 4
  • 24
  • 30
0

Turns out the problem, was the SSL on the receiving server. The request was being made to HTTP instead of HTTPS, and instead of giving an error or redirection, it simply dropped the POST on the way (maybe it redirected to HTTPS but failed to pass the POST along with it?)

casraf
  • 21,085
  • 9
  • 56
  • 91