ChatGPT解决这个技术问题 Extra ChatGPT

How do I send a POST request with PHP?

Actually I want to read the contents that come after the search query, when it is done. The problem is that the URL only accepts POST methods, and it does not take any action with GET method...

I have to read all contents with the help of domdocument or file_get_contents(). Is there any method that will let me send parameters with POST method and then read the contents via PHP?


m
maraca

CURL-less method with PHP5:

$url = 'http://server.com/path';
$data = array('key1' => 'value1', 'key2' => 'value2');

// use key 'http' even if you send the request to https://...
$options = array(
    'http' => array(
        'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
        'method'  => 'POST',
        'content' => http_build_query($data)
    )
);
$context  = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }

var_dump($result);

See the PHP manual for more information on the method and how to add headers, for example:

stream_context_create: http://php.net/manual/en/function.stream-context-create.php


It's worth noting that if you decide to use an array for the headers, do NOT end the keys or values with '\r\n'. stream_context_create() will only take the text up to the first '\r\n'
A URL can be used as a filename with file_get_contents() only if the fopen wrappers have been enabled. See php.net/manual/en/…
Is there a specific reason for not using CURL?
@jvannistelrooy CURL for PHP is an extension which may not exist in all environments whereas file_get_contents() is part of PHP's core. Also, using an extension unnecessarily can widen the attack surface of your app. E.g. Google php curl cve
bool(false) i get??
Y
YanDatsiuk

You could use cURL:

<?php
//The url you wish to send the POST request to
$url = $file_name;

//The data you want to send via POST
$fields = [
    '__VIEWSTATE '      => $state,
    '__EVENTVALIDATION' => $valid,
    'btnSubmit'         => 'Submit'
];

//url-ify the data for the POST
$fields_string = http_build_query($fields);

//open connection
$ch = curl_init();

//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);

//So that curl_exec returns the contents of the cURL; rather than echoing it
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true); 

//execute post
$result = curl_exec($ch);
echo $result;
?>

this one worked for me because the page I am sending to a page that has no content so the file_get_contents version didn't work.
file_get_contents solution doesn't work on PHP configurations with allow_url_fopen Off (like in shared hosting). This version uses curl library and I think is most "universal" so I give you my vote
You didn't site where you copied this code sample from: davidwalsh.name/curl-post
Although it is not very important, the CURLOPT_POSTFIELDS parameter data actually doesn't need to be converted to a string ("urlified"). Quote: "This parameter can either be passed as a urlencoded string like 'para1=val1&para2=val2&...' or as an array with the field name as key and field data as value. If value is an array, the Content-Type header will be set to multipart/form-data." Link: php.net/manual/en/function.curl-setopt.php.
Also, no offence for writing it differently, but I don't know why the CURLOPT_POST parameter is specified as a number here as it says to set it to a boolean on the manual page. Quote: "CURLOPT_POST: TRUE to do a regular HTTP POST." Link: php.net/manual/en/function.curl-setopt.php.
D
Dima L.

I use the following function to post data using curl. $data is an array of fields to post (will be correctly encoded using http_build_query). The data is encoded using application/x-www-form-urlencoded.

function httpPost($url, $data)
{
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($curl);
    curl_close($curl);
    return $response;
}

@Edward mentions that http_build_query may be omitted since curl will correctly encode array passed to CURLOPT_POSTFIELDS parameter, but be advised that in this case the data will be encoded using multipart/form-data.

I use this function with APIs that expect data to be encoded using application/x-www-form-urlencoded. That's why I use http_build_query().


Passing array to CURLOPT_POSTFIELDS causes data to be encoded using multipart/form-data which may not be desirable.
The user did ask for file_get_contents, so he needs a solution for changing the default_stream_context
To clarify: I think @DimaL. is responding to a comment that has been deleted; http_build_query converts $data array to a string, avoiding output as multipart/form-data.
@Radon8472 - ... CURLOPT_RETURNTRANSFER, true results in $response containing the contents.
@ToolmakerSteve as I said, the question was for file_get_contents and your solution needs CURL what many people dont have. so your solution is maybe working, but it is not answering the question how to do this with the native builtin file/stream functions.
C
Community

I recommend you to use the open-source package guzzle that is fully unit tested and uses the latest coding practices.

Installing Guzzle

Go to the command line in your project folder and type in the following command (assuming you already have the package manager composer installed). If you need help how to install Composer, you should have a look here.

php composer.phar require guzzlehttp/guzzle

Using Guzzle to send a POST request

The usage of Guzzle is very straight forward as it uses a light-weight object-oriented API:

// Initialize Guzzle client
$client = new GuzzleHttp\Client();

// Create a POST request
$response = $client->request(
    'POST',
    'http://example.org/',
    [
        'form_params' => [
            'key1' => 'value1',
            'key2' => 'value2'
        ]
    ]
);

// Parse the response object, e.g. read the headers, body, etc.
$headers = $response->getHeaders();
$body = $response->getBody();

// Output headers and body for debugging purposes
var_dump($headers, $body);

It would be useful to know what advantages this has over the native PHP solution already posted, and the cURL one too.
@artfulrobot: The native PHP-solution has lots of problems (e.g. connecting with https, certificate verification, etc.pp.), which is why almost every PHP developer uses cURL. And why not use cURL in this case? It's simple: Guzzle has a straight-forward, easy, light-weight interface which abstracts all those "low-level cURL handling problems" away. Almost everyone developing modern PHP uses Composer anyway, so using Guzzle is just really simple.
Thanks, I know guzzle is popular, however there are use cases when composer causes grief (e.g. developing plugins for bigger software projects that might already use a (different version) of guzzle or other dependencies), so it's good to know this info to make a decision about which solution will be most robust
@Andreas while you are right, this is a good example of more and more abstraction leading to less and less understanding of low-level technology thus leading to more and more devs not knowing what they are doing there anyway and not beeing able to debug even a simple request.
@clockw0rk Unfortunately, you're right about that. But still abstraction (to some extent) is useful and saves a lot of time and mistakes / potential bugs. Obviously, everyone using Guzzle should still be able to debug requests and also have a basic understanding of networking and how HTTP works.
m
mwatzer

I'd like to add some thoughts about the curl-based answer of Fred Tanrikut. I know most of them are already written in the answers above, but I think it is a good idea to show an answer that includes all of them together.

Here is the class I wrote to make HTTP-GET/POST/PUT/DELETE requests based on curl, concerning just about the response body:

class HTTPRequester {
    /**
     * @description Make HTTP-GET call
     * @param       $url
     * @param       array $params
     * @return      HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPGet($url, array $params) {
        $query = http_build_query($params); 
        $ch    = curl_init($url.'?'.$query);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }
    /**
     * @description Make HTTP-POST call
     * @param       $url
     * @param       array $params
     * @return      HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPPost($url, array $params) {
        $query = http_build_query($params);
        $ch    = curl_init();
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }
    /**
     * @description Make HTTP-PUT call
     * @param       $url
     * @param       array $params
     * @return      HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPPut($url, array $params) {
        $query = \http_build_query($params);
        $ch    = \curl_init();
        \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
        \curl_setopt($ch, \CURLOPT_HEADER, false);
        \curl_setopt($ch, \CURLOPT_URL, $url);
        \curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'PUT');
        \curl_setopt($ch, \CURLOPT_POSTFIELDS, $query);
        $response = \curl_exec($ch);
        \curl_close($ch);
        return $response;
    }
    /**
     * @category Make HTTP-DELETE call
     * @param    $url
     * @param    array $params
     * @return   HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPDelete($url, array $params) {
        $query = \http_build_query($params);
        $ch    = \curl_init();
        \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
        \curl_setopt($ch, \CURLOPT_HEADER, false);
        \curl_setopt($ch, \CURLOPT_URL, $url);
        \curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'DELETE');
        \curl_setopt($ch, \CURLOPT_POSTFIELDS, $query);
        $response = \curl_exec($ch);
        \curl_close($ch);
        return $response;
    }
}

Improvements

Using http_build_query to get the query-string out of an request-array.(you could also use the array itself, therefore see: http://php.net/manual/en/function.curl-setopt.php)

Returning the response instead of echoing it. Btw you can avoid the returning by removing the line curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);. After that the return value is a boolean(true = request was successful otherwise an error occured) and the response is echoed. See: http://php.net/en/manual/function.curl-exec.php

Clean session closing and deletion of the curl-handler by using curl_close. See: http://php.net/manual/en/function.curl-close.php

Using boolean values for the curl_setopt function instead of using any number.(I know that any number not equal zero is also considered as true, but the usage of true generates a more readable code, but that's just my opinion)

Ability to make HTTP-PUT/DELETE calls(useful for RESTful service testing)

Example of usage

GET

$response = HTTPRequester::HTTPGet("http://localhost/service/foobar.php", array("getParam" => "foobar"));

POST

$response = HTTPRequester::HTTPPost("http://localhost/service/foobar.php", array("postParam" => "foobar"));

PUT

$response = HTTPRequester::HTTPPut("http://localhost/service/foobar.php", array("putParam" => "foobar"));

DELETE

$response = HTTPRequester::HTTPDelete("http://localhost/service/foobar.php", array("deleteParam" => "foobar"));

Testing

You can also make some cool service tests by using this simple class.

class HTTPRequesterCase extends TestCase {
    /**
     * @description test static method HTTPGet
     */
    public function testHTTPGet() {
        $requestArr = array("getLicenses" => 1);
        $url        = "http://localhost/project/req/licenseService.php";
        $this->assertEquals(HTTPRequester::HTTPGet($url, $requestArr), '[{"error":false,"val":["NONE","AGPL","GPLv3"]}]');
    }
    /**
     * @description test static method HTTPPost
     */
    public function testHTTPPost() {
        $requestArr = array("addPerson" => array("foo", "bar"));
        $url        = "http://localhost/project/req/personService.php";
        $this->assertEquals(HTTPRequester::HTTPPost($url, $requestArr), '[{"error":false}]');
    }
    /**
     * @description test static method HTTPPut
     */
    public function testHTTPPut() {
        $requestArr = array("updatePerson" => array("foo", "bar"));
        $url        = "http://localhost/project/req/personService.php";
        $this->assertEquals(HTTPRequester::HTTPPut($url, $requestArr), '[{"error":false}]');
    }
    /**
     * @description test static method HTTPDelete
     */
    public function testHTTPDelete() {
        $requestArr = array("deletePerson" => array("foo", "bar"));
        $url        = "http://localhost/project/req/personService.php";
        $this->assertEquals(HTTPRequester::HTTPDelete($url, $requestArr), '[{"error":false}]');
    }
}

For me, it says "Uncaught Error: Call to undefined method HTTPRequester::HTTPost()". I have simply pasted your class into my .php file. Anything else I need to do?
Can you please post your code? It's pretty hard to guess what's wrong without any code snippet.
As I said, I've literally copied yours into my plain php file and it gave me this error.
Ok now I see the issue,.. it was wrong in the example! You have to call HTTPRequester::HTTPPost() instead of HTTPRequester::HTTPost()
Ah. That one's easy to miss. I had to read your comment like 5x before I spotted the extra P. Thanks!
C
Community

There's another CURL method if you are going that way.

This is pretty straightforward once you get your head around the way the PHP curl extension works, combining various flags with setopt() calls. In this example I've got a variable $xml which holds the XML I have prepared to send - I'm going to post the contents of that to example's test method.

$url = 'http://api.example.com/services/xmlrpc/';
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
//process $response

First we initialised the connection, then we set some options using setopt(). These tell PHP that we are making a post request, and that we are sending some data with it, supplying the data. The CURLOPT_RETURNTRANSFER flag tells curl to give us the output as the return value of curl_exec rather than outputting it. Then we make the call and close the connection - the result is in $response.


in the 3rd curl_setopt() call, the first arg should be $ch not $curl, correct?
Can you use this same code to POST JSON data? But replace $xml with say $json (where $json is probably a JSON string?)
佚名

If you by any chance are using Wordpress to develop your app (it's actually a convenient way to get authorization, info pages etc even for very simple stuff), you can use the following snippet:

$response = wp_remote_post( $url, array('body' => $parameters));

if ( is_wp_error( $response ) ) {
    // $response->get_error_message()
} else {
    // $response['body']
}

It uses different ways of making the actual HTTP request, depending on what is available on the web server. For more details, see the HTTP API documentation.

If you don't want to develop a custom theme or plugin to start the Wordpress engine, you can just do the following in an isolated PHP file in the wordpress root:

require_once( dirname(__FILE__) . '/wp-load.php' );

// ... your code

It won't show any theme or output any HTML, just hack away with the Wordpress APIs!


C
CPHPython

Another alternative of the curl-less method above is to use the native stream functions:

stream_context_create(): Creates and returns a stream context with any options supplied in options preset.

stream_get_contents(): Identical to file_get_contents(), except that stream_get_contents() operates on an already open stream resource and returns the remaining contents in a string, up to maxlength bytes and starting at the specified offset.

A POST function with these can simply be like this:

<?php

function post_request($url, array $params) {
  $query_content = http_build_query($params);
  $fp = fopen($url, 'r', FALSE, // do not use_include_path
    stream_context_create([
    'http' => [
      'header'  => [ // header array does not need '\r\n'
        'Content-type: application/x-www-form-urlencoded',
        'Content-Length: ' . strlen($query_content)
      ],
      'method'  => 'POST',
      'content' => $query_content
    ]
  ]));
  if ($fp === FALSE) {
    return json_encode(['error' => 'Failed to get contents...']);
  }
  $result = stream_get_contents($fp); // no maxlength/offset
  fclose($fp);
  return $result;
}

This CURL-less method worked fine for me to validate reCAPTCHA from google. This answer converges with this google code: github.com/google/recaptcha/blob/master/src/ReCaptcha/…
You don't have to use fclose() if $fp is false. Because fclose() expects a resource is parameter.
@Floris Edited it just now and indeed the fclose docs mentions "The file pointer must be valid". Thank you for noticing that!
I tried this, and I wasn't able to parse the 'post' data within my api.. I am using json_decode(file_get_contents("php://input"))) Any ideas?; Edit: By changing the content type header to application/json, it worked. Thanks!
S
Sayed Muhammad Idrees

Here is using just one command without cURL. Super simple.

echo file_get_contents('https://www.server.com', false, stream_context_create([
    'http' => [
        'method' => 'POST',
        'header'  => "Content-type: application/x-www-form-urlencoded",
        'content' => http_build_query([
            'key1' => 'Hello world!', 'key2' => 'second value'
        ])
    ]
]));

How will the Key2 works? what's the seperator between them?
@Sayedidrees to add key2 you can enter it as a second array item. 'key1' => 'Hello world!', 'key2' => 'second value'
Worked really well
I
Imran Zahoor

The better way of sending GET or POST requests with PHP is as below:

<?php
    $r = new HttpRequest('http://example.com/form.php', HttpRequest::METH_POST);
    $r->setOptions(array('cookies' => array('lang' => 'de')));
    $r->addPostFields(array('user' => 'mike', 'pass' => 's3c|r3t'));

    try {
        echo $r->send()->getBody();
    } catch (HttpException $ex) {
        echo $ex;
    }
?>

The code is taken from official documentation here http://docs.php.net/manual/da/httprequest.send.php


@akinuri thanks for highlighting, I'm going to share the new one.
how to do it on PHP 5x?
@YumYumYum please checkout dbau's answer above for 5x which uses this technique php.net/manual/en/function.stream-context-create.php Or you can always go back to standard curl solution.
This isn't native PHP. This requires pecl http.
B
Basj

Based on the main answer, here is what I use:

function do_post($url, $params) {
    $options = array(
        'http' => array(
            'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
            'method'  => 'POST',
            'content' => $params
        )
    );
    $result = file_get_contents($url, false, stream_context_create($options));
}

Example usage:

do_post('https://www.google-analytics.com/collect', 'v=1&t=pageview&tid=UA-xxxxxxx-xx&cid=abcdef...');

Hi Basj. I don't understand. I tried your example & it didn't work for me. Could you please show a usage for some URL like https://jsonplaceholder.typicode.com/todos/1? Thanks in advance
A
Arindam Nayak

I was looking for a similar problem and found a better approach of doing this. So here it goes.

You can simply put the following line on the redirection page (say page1.php).

header("Location: URL", TRUE, 307); // Replace URL with to be redirected URL, e.g. final.php

I need this to redirect POST requests for REST API calls. This solution is able to redirect with post data as well as custom header values.

Here is the reference link.


This answers how to redirect a page request not How do I send a POST request with PHP? Sure this would forward any POST parameters but that is not at all the same thing
@DelightedD0D, Sorry I did not get the difference between redirect a page request with POST param vs send POST request. For me purpose of both is same, correct me if I am wrong.
Is there any method that will let me send parameters with POST method and then read the contents via PHP? The OP wants thier php script to construct a set of POST parameters and send them to another php page and for their script to receive the output from that page . This solution would simply accept an already POSTed set of values and forward them to another page. They are pretty different.
C
Code

[Edit]: Please ignore, not available in php now.

There is one more which you can use

<?php
$fields = array(
    'name' => 'mike',
    'pass' => 'se_ret'
);
$files = array(
    array(
        'name' => 'uimg',
        'type' => 'image/jpeg',
        'file' => './profile.jpg',
    )
);

$response = http_post_fields("http://www.example.com/", $fields, $files);
?>

Click here for details


This relies on a PECL extension which most will not have installed. Not even sure it's still available, as the manual pages have been removed.
click here for details link invalid
W
Wellington Alves

Here ok with this code:

<?php
$postdata = http_build_query(
    array(
        'name' => 'Robert',
        'id' => '1'
    )
);
$opts = array('http' =>
    array(
        'method' => 'POST',
        'header' => 'Content-type: application/x-www-form-urlencoded',
        'content' => $postdata
    )
);
$context = stream_context_create($opts);
$result = file_get_contents('http://localhost:8000/api/test', false, $context);
echo $result;?>

c
cweiske

Try PEAR's HTTP_Request2 package to easily send POST requests. Alternatively, you can use PHP's curl functions or use a PHP stream context.

HTTP_Request2 also makes it possible to mock out the server, so you can unit-test your code easily


I'd like to see you to elaborate it, if possible.
T
Teocci

I make a function to request a post using JSON:

const FORMAT_CONTENT_LENGTH = 'Content-Length: %d';
const FORMAT_CONTENT_TYPE = 'Content-Type: %s';

const CONTENT_TYPE_JSON = 'application/json';
/**
 * @description Make a HTTP-POST JSON call
 * @param string $url
 * @param array $params
 * @return bool|string HTTP-Response body or an empty string if the request fails or is empty
 */
function HTTPJSONPost(string $url, array $params)
{
    $content = json_encode($params);
    $response = file_get_contents($url, false, // do not use_include_path
        stream_context_create([
            'http' => [
                'method' => 'POST',
                'header' => [ // header array does not need '\r\n'
                    sprintf(FORMAT_CONTENT_TYPE, CONTENT_TYPE_JSON),
                    sprintf(FORMAT_CONTENT_LENGTH, strlen($content)),
                ],
                'content' => $content
            ]
        ])); // no maxlength/offset
    if ($response === false) {
        return json_encode(['error' => 'Failed to get contents...']);
    }

    return $response;
}

M
MSS

I prefer this one:

function curlPost($url, $data = NULL, $headers = []) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 5); //timeout in seconds
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    curl_setopt($ch, CURLOPT_ENCODING, 'identity');

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

    if (!empty($headers)) {
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    }

    $response = curl_exec($ch);
    if (curl_error($ch)) {
        trigger_error('Curl Error:' . curl_error($ch));
    }

    curl_close($ch);
    return $response;
}

Usage example:

$response=curlPost("http://my.url.com", ["myField1"=>"myValue1"], ["myFitstHeaderName"=>"myFirstHeaderValue"]);

I believe this is missing curl_setopt($ch, CURLOPT_POST, true);
v
vincent thorpe

If you come from previous POST/GET/... you can include('fileName.php') or require('fileName.php') PHP script, in the actual php sheet. So it will continue the POST/GET/... petition will be valid inside the scope


Not sure I understand what you mean
me neither lol hahaha