How do I make a simple PHP API handler? - php

I've written a basic API script in PHP using cURL - and successfully used a version of it on another API, this one is specifically to handle domain DNS management on DigitalOcean - and I can't send data?
Prelude...
I understand there is a PHP library available, I'm not after something that full featured or bloated with dependencies - just something small to use locally and primarily to help me understand how RESTful API's work a little better in practice - an educational exercise
The offending Code...
function basic_api_handle($key, $method, $URI, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization: Bearer '.$key,
'Content-Type: application/json')
);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_URL, $URI);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}
var_dump(basic_api_handle($api_key, 'POST', 'https://api.digitalocean.com/v2/domains', array('name' => 'my-domain.tld', 'ip_address' => '1.2.3.4')));
This works with a GET request, such as listing the domains on the account but seems to fail at posting/sending data... this results in "unprocessable_entity" and "Name can't be blank" - as the name is not blank and is correctly formatted (as far as I can tell) it suggests to me the data is not being sent correctly?
Solution Attempts so far...
I've tried json encoding the data (seen in code), not json encoding, url encoding with and without json encoding and various other options with no luck.
I've seen a few posts online about this exact same issue specifically with DigitalOcean's API (and a another) but no one had an explanation (other than give up and use the library or something to that affect).
Using cURL directly from a terminal does work etc so there is nothing wrong with the API for creating a domain.
As far as I understand, the authentication is working, and the general setup works as I can list domains within the account, I just cant POST or PUT new data. I've been though the API's documentation and can't see what I'm doing wrong, maybe some sort of wrong encoding?
Any help would be much appreciated! :)
Edit:
After much work and research even other simple API handlers do not work with Digital Ocean (such as https://github.com/ledfusion/php-rest-curl) - is there something this API in particular needs or am I missing something fundamental about API's in general?

Technically this is not an fix but a work around. Thank you everyone for your comments and ideas, unfortunately nothing worked/fixed the code and the bounty expired :(
Although I have no idea why the PHP cURL option didn't work (the HTTP works, just Digital Ocean spitting errors for unknown reason linked to validation of the post data)...
I do have a new method that DOES WORK finally... (thanks to jtittle post on the Digital Ocean Community forum)
Just incase that link dies in the future... he's the working function using streams and file_get_contents and not curl...
<?php
function doapi( $key, $method, $uri, array $data = [] )
{
/**
* DigitalOcean API URI
*/
$api = 'https://api.digitalocean.com/v2';
/**
* Merge DigitalOcean API URI and Endpoint URI
*
* i.e if $uri is set to 'domains', then $api ends up as
* $api = 'https://api.digitalocean.com/v2/domains'
*/
$uri = $api . DIRECTORY_SEPARATOR . $uri;
/**
* Define Authorization and Content-Type Header.
*/
$headers = "Authorization: Bearer $key \r\n" .
"Content-Type: application/json";
/**
* If $data array is not empty, assume we're passing data, so we'll encode
* it and pass it to 'content'. If $data is empty, assume we're not passing
* data, so we won't sent 'content'.
*/
if ( ! empty( $data ) )
{
$data = [
'http' => [
'method' => strtoupper( $method ),
'header' => $headers,
'content' => json_encode( $data )
]
];
}
else
{
$data = [
'http' => [
'method' => strtoupper( $method ),
'header' => $headers
]
];
}
/**
* Create Stream Context
* http://php.net/manual/en/function.stream-context-create.php
*/
$context = stream_context_create( $data );
/**
* Send Request and Store to $response.
*/
$response = file_get_contents( $uri, false, $context );
/**
* Return as decoded JSON (i.e. an array)
*/
return json_decode( $response, true );
}
/**
* Example Usage
*/
var_dump(doapi(
'do-api-key',
'get',
'domains'
));
I used this to actually post the data successfully...
var_dump(doapi(
$api_key,
'post',
'domains',
array("name" => (string) $newDomain, "ip_address" => "1.2.3.4")
));

Add the Content-Length header and use CURLOPT_POST option for POST requests
function basic_api_handle($key, $method, $URI, $data) {
$json = json_encode($data)
$headers = array(
'Authorization: Bearer '.$key,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $URI);
if ( $method === 'POST' ) {
curl_setopt($curl, CURLOPT_POST, 1);
} else {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
array_push($headers, 'Content-Length: ' . strlen($json) );
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers)
curl_setopt($ch, CURLOPT_POSTFIELDS, $json );
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}

Maybe this will work for you:
function basic_api_handle($key, $method, $URI, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); // <-- Should be set to "GET" or "POST"
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // <-- Maybe the SSL is the problem
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"); // <-- I am not familiar with this API, but maybe it needs a user agent?
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization: Bearer '.$key,
'Content-Type: application/json')
);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_URL, $URI);
curl_setopt($ch, CURLOPT_POST, count($data)); // <-- Add this line which counts the inputs you send
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}
It can also be a problem of a header you should sent and your missing it.

It could be a 307 or 308 http redirect.
Maybe "https://api.digitalocean.com/v2/domains" redirects to another url.
If this is the case, try adding:
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
to make curl follow the redirection and keep the parameters.
It is suggested that you also use:
curl_setopt($curl, CURLOPT_POSTREDIR, 3);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
to keep the request body.
Hope it helps.

You can also try use CURLOPT_POST

Related

CURL_SETOPT_ARRAY Not working inside a function, but works alone [duplicate]

Can anyone show me how to do a PHP cURL with an HTTP POST?
I want to send data like this:
username=user1, password=passuser1, gender=1
To www.example.com
I expect the cURL to return a response like result=OK. Are there any examples?
<?php
//
// A very simple PHP example that sends a HTTP POST to a remote site
//
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"http://www.example.com/tester.phtml");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"postvar1=value1&postvar2=value2&postvar3=value3");
// In real life you should use something like:
// curl_setopt($ch, CURLOPT_POSTFIELDS,
// http_build_query(array('postvar1' => 'value1')));
// Receive server response ...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec($ch);
curl_close($ch);
// Further processing ...
if ($server_output == "OK") { ... } else { ... }
?>
Procedural
// set post fields
$post = [
'username' => 'user1',
'password' => 'passuser1',
'gender' => 1,
];
$ch = curl_init('http://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
// execute!
$response = curl_exec($ch);
// close the connection, release resources used
curl_close($ch);
// do anything you want with your response
var_dump($response);
Object oriented
<?php
// mutatis mutandis
namespace MyApp\Http;
class CurlPost
{
private $url;
private $options;
/**
* #param string $url Request URL
* #param array $options cURL options
*/
public function __construct($url, array $options = [])
{
$this->url = $url;
$this->options = $options;
}
/**
* Get the response
* #return string
* #throws \RuntimeException On cURL error
*/
public function __invoke(array $post)
{
$ch = \curl_init($this->url);
foreach ($this->options as $key => $val) {
\curl_setopt($ch, $key, $val);
}
\curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
\curl_setopt($ch, \CURLOPT_POSTFIELDS, $post);
$response = \curl_exec($ch);
$error = \curl_error($ch);
$errno = \curl_errno($ch);
if (\is_resource($ch)) {
\curl_close($ch);
}
if (0 !== $errno) {
throw new \RuntimeException($error, $errno);
}
return $response;
}
}
Usage
// create curl object
$curl = new \MyApp\Http\CurlPost('http://www.example.com');
try {
// execute the request
echo $curl([
'username' => 'user1',
'password' => 'passuser1',
'gender' => 1,
]);
} catch (\RuntimeException $ex) {
// catch errors
die(sprintf('Http error %s with code %d', $ex->getMessage(), $ex->getCode()));
}
Side note here: it would be best to create some kind of interface called AdapterInterface for example with getResponse() method and let the class above implement it. Then you can always swap this implementation with another adapter of your like, without any side effects to your application.
Using HTTPS / encrypting traffic
Usually there's a problem with cURL in PHP under the Windows operating system. While trying to connect to a https protected endpoint, you will get an error telling you that certificate verify failed.
What most people do here is to tell the cURL library to simply ignore certificate errors and continue (curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);). As this will make your code work, you introduce huge security hole and enable malicious users to perform various attacks on your app like Man In The Middle attack or such.
Never, ever do that. Instead, you simply need to modify your php.ini and tell PHP where your CA Certificate file is to let it verify certificates correctly:
; modify the absolute path to the cacert.pem file
curl.cainfo=c:\php\cacert.pem
The latest cacert.pem can be downloaded from the Internet or extracted from your favorite browser. When changing any php.ini related settings remember to restart your webserver.
A live example of using php curl_exec to do an HTTP post:
Put this in a file called foobar.php:
<?php
$ch = curl_init();
$skipper = "luxury assault recreational vehicle";
$fields = array( 'penguins'=>$skipper, 'bestpony'=>'rainbowdash');
$postvars = '';
foreach($fields as $key=>$value) {
$postvars .= $key . "=" . $value . "&";
}
$url = "http://www.google.com";
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST, 1); //0 for a get request
curl_setopt($ch,CURLOPT_POSTFIELDS,$postvars);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT ,3);
curl_setopt($ch,CURLOPT_TIMEOUT, 20);
$response = curl_exec($ch);
print "curl response is:" . $response;
curl_close ($ch);
?>
Then run it with the command php foobar.php, it dumps this kind of output to screen:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Title</title>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<body>
A mountain of content...
</body>
</html>
So you did a PHP POST to www.google.com and sent it some data.
Had the server been programmed to read in the post variables, it could decide to do something different based upon that.
It's can be easily reached with:
<?php
$post = [
'username' => 'user1',
'password' => 'passuser1',
'gender' => 1,
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.domain.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
$response = curl_exec($ch);
var_export($response);
1.Step by step
Initialize the cURL session:
$url = "www.domain.com";
$ch = curl_init($url);
If your request has headers like bearer token or defining JSON contents you have to set HTTPHEADER options to cURL:
$token = "generated token code";
curl_setopt(
$ch,
CURLOPT_HTTPHEADER,
array(
'Content-Type: application/json', // for define content type that is json
'bearer: '.$token, // send token in header request
'Content-length: 100' // content length for example 100 characters (can add by strlen($fields))
)
);
If you want to include the header in the output set CURLOPT_HEADER to true:
curl_setopt($ch, CURLOPT_HEADER, false);
Set RETURNTRANSFER option to true to return the transfer as a string instead of outputting it directly:
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
To check the existence of a common name in the SSL peer certificate can be set to 0(to not check the names), 1(not supported in cURL 7.28.1), 2(default value and for production mode):
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
For posting fields as an array by cURL:
$fields = array(
"username" => "user1",
"password" => "passuser1",
"gender" => 1
);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
Execute cURL and return the string. depending on your resource this returns output like result=OK:
$result = curl_exec($ch);
Close cURL resource, and free up system resources:
curl_close($ch);
2.Use as a class
The whole call_cURL class that can be extended:
class class_name_for_call_cURL {
protected function getUrl() {
return "www.domain.com";
}
public function call_cURL() {
$token = "generated token code";
$fields = array(
"username" => "user1",
"password" => "passuser1",
"gender" => 1
);
$url = $this->getUrl();
$output = $this->_execute($fields, $url, $token);
// if you want to get json data
// $output = json_decode($output);
if ($output == "OK") {
return true;
} else {
return false;
}
}
private function _execute($postData, $url, $token) {
// for sending data as json type
$fields = json_encode($postData);
$ch = curl_init($url);
curl_setopt(
$ch,
CURLOPT_HTTPHEADER,
array(
'Content-Type: application/json', // if the content type is json
'bearer: '.$token // if you need token in header
)
);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
}
Using the class and call cURL:
$class = new class_name_for_call_cURL();
var_dump($class->call_cURL()); // output is true/false
3.One function
A function for using anywhere that needed:
function get_cURL() {
$url = "www.domain.com";
$token = "generated token code";
$postData = array(
"username" => "user1",
"password" => "passuser1",
"gender" => 1
);
// for sending data as json type
$fields = json_encode($postData);
$ch = curl_init($url);
curl_setopt(
$ch,
CURLOPT_HTTPHEADER,
array(
'Content-Type: application/json', // if the content type is json
'bearer: '.$token // if you need token in header
)
);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
This function is usable just by:
var_dump(get_cURL());
Curl Post + Error Handling + Set Headers [thanks to #mantas-d]:
function curlPost($url, $data=NULL, $headers = NULL) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
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;
}
curlPost('google.com', [
'username' => 'admin',
'password' => '12345',
]);
curlPost('google.com', [
'username' => 'admin',
'password' => '12345',
]);
function curlPost($url, $data) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error !== '') {
throw new \Exception($error);
}
return $response;
}
I'm surprised nobody suggested file_get_contents:
$url = "http://www.example.com";
$parameters = array('username' => 'user1', 'password' => 'passuser1', 'gender' => '1');
$options = array('http' => array(
'header' => 'Content-Type: application/x-www-form-urlencoded\r\n',
'method' => 'POST',
'content' => http_build_query($parameters)
));
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
it's simple, it works; I use it in an environment where I control the code at both ends.
even better, use json_decode (and set up your code to return JSON)
$result = json_decode(file_get_contents($url, false, $context), TRUE);
this approach invokes curl behind the scenes, but you don't jump through as many hoops.
Answer refined from this original answer elsewhere on Stack Overflow:
PHP sending variables to file_get_contents()
If the form is using redirects, authentication, cookies, SSL (https), or anything else other than a totally open script expecting POST variables, you are going to start gnashing your teeth really quick. Take a look at Snoopy, which does exactly what you have in mind while removing the need to set up a lot of the overhead.
A simpler answer IF you are passing information to your own website is to use a SESSION variable. Begin php page with:
session_start();
If at some point there is information you want to generate in PHP and pass to the next page in the session, instead of using a POST variable, assign it to a SESSION variable. Example:
$_SESSION['message']='www.'.$_GET['school'].'.edu was not found. Please try again.'
Then on the next page you simply reference this SESSION variable. NOTE: after you use it, be sure you destroy it, so it doesn't persist after it is used:
if (isset($_SESSION['message'])) {echo $_SESSION['message']; unset($_SESSION['message']);}
Here are some boilerplate code for PHP + curl
http://www.webbotsspidersscreenscrapers.com/DSP_download.php
include in these library will simplify development
<?php
# Initialization
include("LIB_http.php");
include("LIB_parse.php");
$product_array=array();
$product_count=0;
# Download the target (store) web page
$target = "http://www.tellmewhenitchanges.com/buyair";
$web_page = http_get($target, "");
...
?>
Examples of sending form and raw data:
$curlHandler = curl_init();
curl_setopt_array($curlHandler, [
CURLOPT_URL => 'https://postman-echo.com/post',
CURLOPT_RETURNTRANSFER => true,
/**
* Specify POST method
*/
CURLOPT_POST => true,
/**
* Specify array of form fields
*/
CURLOPT_POSTFIELDS => [
'foo' => 'bar',
'baz' => 'biz',
],
]);
$response = curl_exec($curlHandler);
curl_close($curlHandler);
echo($response);
If you try to login on site with cookies.
This code:
if ($server_output == "OK") { ... } else { ... }
It May not works if you try to login, because many sites return status 200, but the post is not successful.
The easy way to check if the login post is successful is to check if it setting cookies again. If in output have a Set-Cookies string, this means the posts are not successful and it starts a new session.
Also, the post can be successful, but the status can redirect instead of 200.
To be sure the post is successful try this:
Follow location after the post, so it will go to the page where the post does redirect to:
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
And than check if new cookies existing in the request:
if (!preg_match('/^Set-Cookie:\s*([^;]*)/mi', $server_output))
{echo 'post successful'; }
else { echo 'not successful'; }
Easiest is to send data as application/json. This will take an array as input and properly encodes it into a json string:
$data = array(
'field1' => 'field1value',
'field2' => 'field2value',
)
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type:application/json',
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resultStr = curl_exec($ch);
return json_decode($resultStr, true);

Shopify REST API Pagination Link Empty

Situation
I am trying to make a call to the Shopify REST API where I have more than 50-250 results but I am not able to get the Link Header from the cURL Response which contains the Pagination Links.
Sample of Link Headers from the API Documentation for Cursor-Pagination (https://shopify.dev/tutorials/make-paginated-requests-to-rest-admin-api)
#...
Link: "<https://{shop}.myshopify.com/admin/api/{version}/products.json?page_info={page_info}&limit={limit}>; rel={next}, <https://{shop}.myshopify.com/admin/api/{version}/products.json?page_info={page_info}&limit={limit}>; rel={previous}"
#...
The link rel parameter does show up, but the Link is empty as below.
My Shopify Call function
function shopify_call($token, $shop, $api_endpoint, $query = array(), $method = 'GET', $request_headers = array()) {
// Build URL
$url = "https://" . $shop . ".myshopify.com" . $api_endpoint;
if (!is_null($query) && in_array($method, array('GET', 'DELETE'))) $url = $url . "?" . http_build_query($query);
$headers = [];
// Configure cURL
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, TRUE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
// this function is called by curl for each header received
curl_setopt($curl, CURLOPT_HEADERFUNCTION,
function($ch, $header) use (&$headers)
{
$len = strlen($header);
$header = explode(':', $header, 2);
if (count($header) < 2) // ignore invalid headers
return $len;
$headers[trim($header[0])] = trim($header[1]);
return $len;
}
);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($curl, CURLOPT_MAXREDIRS, 3);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
// curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 3);
// curl_setopt($curl, CURLOPT_SSLVERSION, 3);
curl_setopt($curl, CURLOPT_USERAGENT, 'Sphyx App v.1');
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($curl, CURLOPT_TIMEOUT, 30);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($curl,CURLOPT_ENCODING,'');
// Setup headers
$request_headers[] = "";
if (!is_null($token)) $request_headers[] = "X-Shopify-Access-Token: " . $token;
$request_headers[] = 'Accept: */*'; // Copied from POSTMAN
$request_headers[] = 'Accept-Encoding: gzip, deflate, br'; // Copied from POSTMAN
curl_setopt($curl, CURLOPT_HTTPHEADER, $request_headers);
if ($method !== 'GET' && in_array($method, array('POST', 'PUT'))) {
if (is_array($query)) $query = http_build_query($query);
curl_setopt ($curl, CURLOPT_POSTFIELDS, $query);
}
// Send request to Shopify and capture any errors
$result = curl_exec($curl);
$response = preg_split("/\r\n\r\n|\n\n|\r\r/", $result, 2);
$error_number = curl_errno($curl);
$error_message = curl_error($curl);
// Close cURL to be nice
curl_close($curl);
// Return an error is cURL has a problem
if ($error_number) {
return $error_message;
} else {
// Return headers and Shopify's response
return array('headers' => $headers, 'response' => json_decode($response[1],true));
}
}
But when I use a POSTMAN Collection, I get a proper formatted response without the Link getting truncated/processed.
I have tried a lot of things here available via the StackOverflow Forums as well as Shopify Community, but I'm unable to parse the Response Header the same way as shown by API Examples or POSTMAN
My issue does seem to be with the PHP Code, but I'm not a pro with cURL. Thus, I'm not able to make it further :(
Also, I'm not able to understand why POSTMAN's Headers are in Proper Case whereas mine are in Lower Case
Thanks in Advance!
Found my answer :
https://community.shopify.com/c/Shopify-APIs-SDKs/Help-with-cursor-based-paging/m-p/579640#M38946
I was using a browser to view my log files. So the data is there but it's hidden because of your use of '<'s around the data. I had to use the browser inspector to see the data. Not sure who decided this syntax was a good idea. Preference would be two headers that one can see and more easily parse since using link syntax is not relative to using an API.
My suggestion would be 2 headers:
X-Shopify-Page-Next: page_info_value (empty if no more pages)
X-Shopify-Page-Perv: page_info_value (empty on first page or if there is no previous page).
Easy to parse and use.
But having this buried as an invalid xml tag, having them both in the same header and using 'rel=' syntax makes no sense at all from an API perspective.

How do I send this CURL in PHP [duplicate]

Can anyone show me how to do a PHP cURL with an HTTP POST?
I want to send data like this:
username=user1, password=passuser1, gender=1
To www.example.com
I expect the cURL to return a response like result=OK. Are there any examples?
<?php
//
// A very simple PHP example that sends a HTTP POST to a remote site
//
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"http://www.example.com/tester.phtml");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"postvar1=value1&postvar2=value2&postvar3=value3");
// In real life you should use something like:
// curl_setopt($ch, CURLOPT_POSTFIELDS,
// http_build_query(array('postvar1' => 'value1')));
// Receive server response ...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec($ch);
curl_close($ch);
// Further processing ...
if ($server_output == "OK") { ... } else { ... }
?>
Procedural
// set post fields
$post = [
'username' => 'user1',
'password' => 'passuser1',
'gender' => 1,
];
$ch = curl_init('http://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
// execute!
$response = curl_exec($ch);
// close the connection, release resources used
curl_close($ch);
// do anything you want with your response
var_dump($response);
Object oriented
<?php
// mutatis mutandis
namespace MyApp\Http;
class CurlPost
{
private $url;
private $options;
/**
* #param string $url Request URL
* #param array $options cURL options
*/
public function __construct($url, array $options = [])
{
$this->url = $url;
$this->options = $options;
}
/**
* Get the response
* #return string
* #throws \RuntimeException On cURL error
*/
public function __invoke(array $post)
{
$ch = \curl_init($this->url);
foreach ($this->options as $key => $val) {
\curl_setopt($ch, $key, $val);
}
\curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
\curl_setopt($ch, \CURLOPT_POSTFIELDS, $post);
$response = \curl_exec($ch);
$error = \curl_error($ch);
$errno = \curl_errno($ch);
if (\is_resource($ch)) {
\curl_close($ch);
}
if (0 !== $errno) {
throw new \RuntimeException($error, $errno);
}
return $response;
}
}
Usage
// create curl object
$curl = new \MyApp\Http\CurlPost('http://www.example.com');
try {
// execute the request
echo $curl([
'username' => 'user1',
'password' => 'passuser1',
'gender' => 1,
]);
} catch (\RuntimeException $ex) {
// catch errors
die(sprintf('Http error %s with code %d', $ex->getMessage(), $ex->getCode()));
}
Side note here: it would be best to create some kind of interface called AdapterInterface for example with getResponse() method and let the class above implement it. Then you can always swap this implementation with another adapter of your like, without any side effects to your application.
Using HTTPS / encrypting traffic
Usually there's a problem with cURL in PHP under the Windows operating system. While trying to connect to a https protected endpoint, you will get an error telling you that certificate verify failed.
What most people do here is to tell the cURL library to simply ignore certificate errors and continue (curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);). As this will make your code work, you introduce huge security hole and enable malicious users to perform various attacks on your app like Man In The Middle attack or such.
Never, ever do that. Instead, you simply need to modify your php.ini and tell PHP where your CA Certificate file is to let it verify certificates correctly:
; modify the absolute path to the cacert.pem file
curl.cainfo=c:\php\cacert.pem
The latest cacert.pem can be downloaded from the Internet or extracted from your favorite browser. When changing any php.ini related settings remember to restart your webserver.
A live example of using php curl_exec to do an HTTP post:
Put this in a file called foobar.php:
<?php
$ch = curl_init();
$skipper = "luxury assault recreational vehicle";
$fields = array( 'penguins'=>$skipper, 'bestpony'=>'rainbowdash');
$postvars = '';
foreach($fields as $key=>$value) {
$postvars .= $key . "=" . $value . "&";
}
$url = "http://www.google.com";
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST, 1); //0 for a get request
curl_setopt($ch,CURLOPT_POSTFIELDS,$postvars);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT ,3);
curl_setopt($ch,CURLOPT_TIMEOUT, 20);
$response = curl_exec($ch);
print "curl response is:" . $response;
curl_close ($ch);
?>
Then run it with the command php foobar.php, it dumps this kind of output to screen:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Title</title>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<body>
A mountain of content...
</body>
</html>
So you did a PHP POST to www.google.com and sent it some data.
Had the server been programmed to read in the post variables, it could decide to do something different based upon that.
It's can be easily reached with:
<?php
$post = [
'username' => 'user1',
'password' => 'passuser1',
'gender' => 1,
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.domain.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
$response = curl_exec($ch);
var_export($response);
1.Step by step
Initialize the cURL session:
$url = "www.domain.com";
$ch = curl_init($url);
If your request has headers like bearer token or defining JSON contents you have to set HTTPHEADER options to cURL:
$token = "generated token code";
curl_setopt(
$ch,
CURLOPT_HTTPHEADER,
array(
'Content-Type: application/json', // for define content type that is json
'bearer: '.$token, // send token in header request
'Content-length: 100' // content length for example 100 characters (can add by strlen($fields))
)
);
If you want to include the header in the output set CURLOPT_HEADER to true:
curl_setopt($ch, CURLOPT_HEADER, false);
Set RETURNTRANSFER option to true to return the transfer as a string instead of outputting it directly:
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
To check the existence of a common name in the SSL peer certificate can be set to 0(to not check the names), 1(not supported in cURL 7.28.1), 2(default value and for production mode):
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
For posting fields as an array by cURL:
$fields = array(
"username" => "user1",
"password" => "passuser1",
"gender" => 1
);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
Execute cURL and return the string. depending on your resource this returns output like result=OK:
$result = curl_exec($ch);
Close cURL resource, and free up system resources:
curl_close($ch);
2.Use as a class
The whole call_cURL class that can be extended:
class class_name_for_call_cURL {
protected function getUrl() {
return "www.domain.com";
}
public function call_cURL() {
$token = "generated token code";
$fields = array(
"username" => "user1",
"password" => "passuser1",
"gender" => 1
);
$url = $this->getUrl();
$output = $this->_execute($fields, $url, $token);
// if you want to get json data
// $output = json_decode($output);
if ($output == "OK") {
return true;
} else {
return false;
}
}
private function _execute($postData, $url, $token) {
// for sending data as json type
$fields = json_encode($postData);
$ch = curl_init($url);
curl_setopt(
$ch,
CURLOPT_HTTPHEADER,
array(
'Content-Type: application/json', // if the content type is json
'bearer: '.$token // if you need token in header
)
);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
}
Using the class and call cURL:
$class = new class_name_for_call_cURL();
var_dump($class->call_cURL()); // output is true/false
3.One function
A function for using anywhere that needed:
function get_cURL() {
$url = "www.domain.com";
$token = "generated token code";
$postData = array(
"username" => "user1",
"password" => "passuser1",
"gender" => 1
);
// for sending data as json type
$fields = json_encode($postData);
$ch = curl_init($url);
curl_setopt(
$ch,
CURLOPT_HTTPHEADER,
array(
'Content-Type: application/json', // if the content type is json
'bearer: '.$token // if you need token in header
)
);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
This function is usable just by:
var_dump(get_cURL());
Curl Post + Error Handling + Set Headers [thanks to #mantas-d]:
function curlPost($url, $data=NULL, $headers = NULL) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
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;
}
curlPost('google.com', [
'username' => 'admin',
'password' => '12345',
]);
curlPost('google.com', [
'username' => 'admin',
'password' => '12345',
]);
function curlPost($url, $data) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error !== '') {
throw new \Exception($error);
}
return $response;
}
I'm surprised nobody suggested file_get_contents:
$url = "http://www.example.com";
$parameters = array('username' => 'user1', 'password' => 'passuser1', 'gender' => '1');
$options = array('http' => array(
'header' => 'Content-Type: application/x-www-form-urlencoded\r\n',
'method' => 'POST',
'content' => http_build_query($parameters)
));
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
it's simple, it works; I use it in an environment where I control the code at both ends.
even better, use json_decode (and set up your code to return JSON)
$result = json_decode(file_get_contents($url, false, $context), TRUE);
this approach invokes curl behind the scenes, but you don't jump through as many hoops.
Answer refined from this original answer elsewhere on Stack Overflow:
PHP sending variables to file_get_contents()
If the form is using redirects, authentication, cookies, SSL (https), or anything else other than a totally open script expecting POST variables, you are going to start gnashing your teeth really quick. Take a look at Snoopy, which does exactly what you have in mind while removing the need to set up a lot of the overhead.
A simpler answer IF you are passing information to your own website is to use a SESSION variable. Begin php page with:
session_start();
If at some point there is information you want to generate in PHP and pass to the next page in the session, instead of using a POST variable, assign it to a SESSION variable. Example:
$_SESSION['message']='www.'.$_GET['school'].'.edu was not found. Please try again.'
Then on the next page you simply reference this SESSION variable. NOTE: after you use it, be sure you destroy it, so it doesn't persist after it is used:
if (isset($_SESSION['message'])) {echo $_SESSION['message']; unset($_SESSION['message']);}
Here are some boilerplate code for PHP + curl
http://www.webbotsspidersscreenscrapers.com/DSP_download.php
include in these library will simplify development
<?php
# Initialization
include("LIB_http.php");
include("LIB_parse.php");
$product_array=array();
$product_count=0;
# Download the target (store) web page
$target = "http://www.tellmewhenitchanges.com/buyair";
$web_page = http_get($target, "");
...
?>
Examples of sending form and raw data:
$curlHandler = curl_init();
curl_setopt_array($curlHandler, [
CURLOPT_URL => 'https://postman-echo.com/post',
CURLOPT_RETURNTRANSFER => true,
/**
* Specify POST method
*/
CURLOPT_POST => true,
/**
* Specify array of form fields
*/
CURLOPT_POSTFIELDS => [
'foo' => 'bar',
'baz' => 'biz',
],
]);
$response = curl_exec($curlHandler);
curl_close($curlHandler);
echo($response);
If you try to login on site with cookies.
This code:
if ($server_output == "OK") { ... } else { ... }
It May not works if you try to login, because many sites return status 200, but the post is not successful.
The easy way to check if the login post is successful is to check if it setting cookies again. If in output have a Set-Cookies string, this means the posts are not successful and it starts a new session.
Also, the post can be successful, but the status can redirect instead of 200.
To be sure the post is successful try this:
Follow location after the post, so it will go to the page where the post does redirect to:
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
And than check if new cookies existing in the request:
if (!preg_match('/^Set-Cookie:\s*([^;]*)/mi', $server_output))
{echo 'post successful'; }
else { echo 'not successful'; }
Easiest is to send data as application/json. This will take an array as input and properly encodes it into a json string:
$data = array(
'field1' => 'field1value',
'field2' => 'field2value',
)
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type:application/json',
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resultStr = curl_exec($ch);
return json_decode($resultStr, true);

After redirection submit form with values with PHP [duplicate]

Can anyone show me how to do a PHP cURL with an HTTP POST?
I want to send data like this:
username=user1, password=passuser1, gender=1
To www.example.com
I expect the cURL to return a response like result=OK. Are there any examples?
<?php
//
// A very simple PHP example that sends a HTTP POST to a remote site
//
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"http://www.example.com/tester.phtml");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
"postvar1=value1&postvar2=value2&postvar3=value3");
// In real life you should use something like:
// curl_setopt($ch, CURLOPT_POSTFIELDS,
// http_build_query(array('postvar1' => 'value1')));
// Receive server response ...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$server_output = curl_exec($ch);
curl_close($ch);
// Further processing ...
if ($server_output == "OK") { ... } else { ... }
?>
Procedural
// set post fields
$post = [
'username' => 'user1',
'password' => 'passuser1',
'gender' => 1,
];
$ch = curl_init('http://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
// execute!
$response = curl_exec($ch);
// close the connection, release resources used
curl_close($ch);
// do anything you want with your response
var_dump($response);
Object oriented
<?php
// mutatis mutandis
namespace MyApp\Http;
class CurlPost
{
private $url;
private $options;
/**
* #param string $url Request URL
* #param array $options cURL options
*/
public function __construct($url, array $options = [])
{
$this->url = $url;
$this->options = $options;
}
/**
* Get the response
* #return string
* #throws \RuntimeException On cURL error
*/
public function __invoke(array $post)
{
$ch = \curl_init($this->url);
foreach ($this->options as $key => $val) {
\curl_setopt($ch, $key, $val);
}
\curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
\curl_setopt($ch, \CURLOPT_POSTFIELDS, $post);
$response = \curl_exec($ch);
$error = \curl_error($ch);
$errno = \curl_errno($ch);
if (\is_resource($ch)) {
\curl_close($ch);
}
if (0 !== $errno) {
throw new \RuntimeException($error, $errno);
}
return $response;
}
}
Usage
// create curl object
$curl = new \MyApp\Http\CurlPost('http://www.example.com');
try {
// execute the request
echo $curl([
'username' => 'user1',
'password' => 'passuser1',
'gender' => 1,
]);
} catch (\RuntimeException $ex) {
// catch errors
die(sprintf('Http error %s with code %d', $ex->getMessage(), $ex->getCode()));
}
Side note here: it would be best to create some kind of interface called AdapterInterface for example with getResponse() method and let the class above implement it. Then you can always swap this implementation with another adapter of your like, without any side effects to your application.
Using HTTPS / encrypting traffic
Usually there's a problem with cURL in PHP under the Windows operating system. While trying to connect to a https protected endpoint, you will get an error telling you that certificate verify failed.
What most people do here is to tell the cURL library to simply ignore certificate errors and continue (curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);). As this will make your code work, you introduce huge security hole and enable malicious users to perform various attacks on your app like Man In The Middle attack or such.
Never, ever do that. Instead, you simply need to modify your php.ini and tell PHP where your CA Certificate file is to let it verify certificates correctly:
; modify the absolute path to the cacert.pem file
curl.cainfo=c:\php\cacert.pem
The latest cacert.pem can be downloaded from the Internet or extracted from your favorite browser. When changing any php.ini related settings remember to restart your webserver.
A live example of using php curl_exec to do an HTTP post:
Put this in a file called foobar.php:
<?php
$ch = curl_init();
$skipper = "luxury assault recreational vehicle";
$fields = array( 'penguins'=>$skipper, 'bestpony'=>'rainbowdash');
$postvars = '';
foreach($fields as $key=>$value) {
$postvars .= $key . "=" . $value . "&";
}
$url = "http://www.google.com";
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST, 1); //0 for a get request
curl_setopt($ch,CURLOPT_POSTFIELDS,$postvars);
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT ,3);
curl_setopt($ch,CURLOPT_TIMEOUT, 20);
$response = curl_exec($ch);
print "curl response is:" . $response;
curl_close ($ch);
?>
Then run it with the command php foobar.php, it dumps this kind of output to screen:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Title</title>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<body>
A mountain of content...
</body>
</html>
So you did a PHP POST to www.google.com and sent it some data.
Had the server been programmed to read in the post variables, it could decide to do something different based upon that.
It's can be easily reached with:
<?php
$post = [
'username' => 'user1',
'password' => 'passuser1',
'gender' => 1,
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://www.domain.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post));
$response = curl_exec($ch);
var_export($response);
1.Step by step
Initialize the cURL session:
$url = "www.domain.com";
$ch = curl_init($url);
If your request has headers like bearer token or defining JSON contents you have to set HTTPHEADER options to cURL:
$token = "generated token code";
curl_setopt(
$ch,
CURLOPT_HTTPHEADER,
array(
'Content-Type: application/json', // for define content type that is json
'bearer: '.$token, // send token in header request
'Content-length: 100' // content length for example 100 characters (can add by strlen($fields))
)
);
If you want to include the header in the output set CURLOPT_HEADER to true:
curl_setopt($ch, CURLOPT_HEADER, false);
Set RETURNTRANSFER option to true to return the transfer as a string instead of outputting it directly:
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
To check the existence of a common name in the SSL peer certificate can be set to 0(to not check the names), 1(not supported in cURL 7.28.1), 2(default value and for production mode):
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
For posting fields as an array by cURL:
$fields = array(
"username" => "user1",
"password" => "passuser1",
"gender" => 1
);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
Execute cURL and return the string. depending on your resource this returns output like result=OK:
$result = curl_exec($ch);
Close cURL resource, and free up system resources:
curl_close($ch);
2.Use as a class
The whole call_cURL class that can be extended:
class class_name_for_call_cURL {
protected function getUrl() {
return "www.domain.com";
}
public function call_cURL() {
$token = "generated token code";
$fields = array(
"username" => "user1",
"password" => "passuser1",
"gender" => 1
);
$url = $this->getUrl();
$output = $this->_execute($fields, $url, $token);
// if you want to get json data
// $output = json_decode($output);
if ($output == "OK") {
return true;
} else {
return false;
}
}
private function _execute($postData, $url, $token) {
// for sending data as json type
$fields = json_encode($postData);
$ch = curl_init($url);
curl_setopt(
$ch,
CURLOPT_HTTPHEADER,
array(
'Content-Type: application/json', // if the content type is json
'bearer: '.$token // if you need token in header
)
);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
}
Using the class and call cURL:
$class = new class_name_for_call_cURL();
var_dump($class->call_cURL()); // output is true/false
3.One function
A function for using anywhere that needed:
function get_cURL() {
$url = "www.domain.com";
$token = "generated token code";
$postData = array(
"username" => "user1",
"password" => "passuser1",
"gender" => 1
);
// for sending data as json type
$fields = json_encode($postData);
$ch = curl_init($url);
curl_setopt(
$ch,
CURLOPT_HTTPHEADER,
array(
'Content-Type: application/json', // if the content type is json
'bearer: '.$token // if you need token in header
)
);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
This function is usable just by:
var_dump(get_cURL());
Curl Post + Error Handling + Set Headers [thanks to #mantas-d]:
function curlPost($url, $data=NULL, $headers = NULL) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
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;
}
curlPost('google.com', [
'username' => 'admin',
'password' => '12345',
]);
curlPost('google.com', [
'username' => 'admin',
'password' => '12345',
]);
function curlPost($url, $data) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error !== '') {
throw new \Exception($error);
}
return $response;
}
I'm surprised nobody suggested file_get_contents:
$url = "http://www.example.com";
$parameters = array('username' => 'user1', 'password' => 'passuser1', 'gender' => '1');
$options = array('http' => array(
'header' => 'Content-Type: application/x-www-form-urlencoded\r\n',
'method' => 'POST',
'content' => http_build_query($parameters)
));
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
it's simple, it works; I use it in an environment where I control the code at both ends.
even better, use json_decode (and set up your code to return JSON)
$result = json_decode(file_get_contents($url, false, $context), TRUE);
this approach invokes curl behind the scenes, but you don't jump through as many hoops.
Answer refined from this original answer elsewhere on Stack Overflow:
PHP sending variables to file_get_contents()
If the form is using redirects, authentication, cookies, SSL (https), or anything else other than a totally open script expecting POST variables, you are going to start gnashing your teeth really quick. Take a look at Snoopy, which does exactly what you have in mind while removing the need to set up a lot of the overhead.
A simpler answer IF you are passing information to your own website is to use a SESSION variable. Begin php page with:
session_start();
If at some point there is information you want to generate in PHP and pass to the next page in the session, instead of using a POST variable, assign it to a SESSION variable. Example:
$_SESSION['message']='www.'.$_GET['school'].'.edu was not found. Please try again.'
Then on the next page you simply reference this SESSION variable. NOTE: after you use it, be sure you destroy it, so it doesn't persist after it is used:
if (isset($_SESSION['message'])) {echo $_SESSION['message']; unset($_SESSION['message']);}
Here are some boilerplate code for PHP + curl
http://www.webbotsspidersscreenscrapers.com/DSP_download.php
include in these library will simplify development
<?php
# Initialization
include("LIB_http.php");
include("LIB_parse.php");
$product_array=array();
$product_count=0;
# Download the target (store) web page
$target = "http://www.tellmewhenitchanges.com/buyair";
$web_page = http_get($target, "");
...
?>
Examples of sending form and raw data:
$curlHandler = curl_init();
curl_setopt_array($curlHandler, [
CURLOPT_URL => 'https://postman-echo.com/post',
CURLOPT_RETURNTRANSFER => true,
/**
* Specify POST method
*/
CURLOPT_POST => true,
/**
* Specify array of form fields
*/
CURLOPT_POSTFIELDS => [
'foo' => 'bar',
'baz' => 'biz',
],
]);
$response = curl_exec($curlHandler);
curl_close($curlHandler);
echo($response);
If you try to login on site with cookies.
This code:
if ($server_output == "OK") { ... } else { ... }
It May not works if you try to login, because many sites return status 200, but the post is not successful.
The easy way to check if the login post is successful is to check if it setting cookies again. If in output have a Set-Cookies string, this means the posts are not successful and it starts a new session.
Also, the post can be successful, but the status can redirect instead of 200.
To be sure the post is successful try this:
Follow location after the post, so it will go to the page where the post does redirect to:
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
And than check if new cookies existing in the request:
if (!preg_match('/^Set-Cookie:\s*([^;]*)/mi', $server_output))
{echo 'post successful'; }
else { echo 'not successful'; }
Easiest is to send data as application/json. This will take an array as input and properly encodes it into a json string:
$data = array(
'field1' => 'field1value',
'field2' => 'field2value',
)
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type:application/json',
));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resultStr = curl_exec($ch);
return json_decode($resultStr, true);

How to recode http_post_data() to curl?

I have a hosted server with curl installed, but not http_post_data() pecl.
I'm trying to translate this (working) http_post_data() code to curl:
$responseString = #http_post_data("http://" . $this->username . ":" . $this->password ."#" . $this->webserviceHost . $this->requestUriBase .$request,
$requestString,
array('http_auth' => $this->username . ":" . $this->password, 'headers' => array('Content-Type' => 'text/xml')));
I've tried:
$url = "http://" . $this->username . ":" . $this->password ."#" . $this->webserviceHost . $this->requestUriBase .$request;
curl_setopt($this->curl, CURLOPT_HTTPHEADER, array('Accept: application/xml', 'Content-Type: application/xml'));
curl_setopt($this->curl, CURLOPT_URL, $url);
curl_setopt($this->curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt(CURLOPT_USERPWD, "[$this->username]:[$this->password]");
curl_setopt ($this->curl, CURLOPT_POST, true);
curl_setopt ($this->curl, CURLOPT_POSTFIELDS, array($requestString));
$content = curl_exec($this->curl);
... and failed: couldn't connect to host
What's the correct code?
Here is a function that should allow you to use your existing code unmodified:
if (!function_exists('http_post_data')) {
function http_post_data ($url, $data, $options) {
// Construct the URL with the auth stripped out
$urlParts = parse_url($url);
$urlToUse = $urlParts['scheme'].'://'.$urlParts['host'];
if (isset($urlParts['port'])) $urlToUse .= ':'.$urlParts['port'];
$urlToUse .= $urlParts['path'];
if (isset($urlParts['query'])) $urlToUse .= '?'.$urlParts['query'];
// Convert headers to a format cURL will like
$headers = array();
if (isset($options['headers'])) {
foreach ($options['headers'] as $name => $val) {
$headers[] = "$name: $val";
}
}
// Initialise cURL with the modified URL
$ch = curl_init($urlToUse);
// We want the function to return the response as a string
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, TRUE);
// Set the method to POST and set the body data
curl_setopt ($ch, CURLOPT_POST, TRUE);
curl_setopt ($ch, CURLOPT_POSTFIELDS, $data); // Wrapping this in an array() is definitely wrong, given that the content-type is xml
// Set the auth details if specified
if (isset($urlParts['user'], $urlParts['pass'])) {
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); // It's probably best to allow any auth method, unless you know the server ONLY supports basic
curl_setopt($ch, CURLOPT_USERPWD, $urlParts['user'].':'.$urlParts['pass']); // The square brackets are not required and will be treated as part of the username/password
}
// Set any extra headers
if ($headers) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
// Send the request and return the result:
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
}
This function only implements that options for http_post_data() that you have made use of in your original code - it would be possible to implement other features using cURL as well, but I have not bloated the above code with unnecessary implementations of them. If does not do much error checking, particularly in terms of validating the supplied URL, so you may wish to add some additional sanitization.
This function is wrapped in an if (!function_exists()) to allow you to place it your code and be distributed anywhere. It will not collide with the native function where it is available.
To configure and execute a CURL request, I suggest the following format:
# in curl URL is scheme://hostname/rest, and hostname != authority
# (authority is hostname plus port and with user/pass in front)
$url = sprintf('http://%s/%s', $this->webserviceHost
, $this->requestUriBase . $request);
$options = array(
CURLOPT_HTTPHEADER => array(
'Accept: application/xml',
'Content-Type: application/xml',
),
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
# don't use the brackets []
CURLOPT_USERPWD => $this->username . ':' . $this->password,
CURLOPT_POST => TRUE,
CURLOPT_POSTFIELDS => $requestString,
CURLOPT_RETURNTRANSFER => TRUE,
);
$this->curl = curl_init($url);
$r = curl_ setopt_ array($this->curl, $options);
if (!$r) throw new Exception('Failed to setup options.');
$content = curl_exec($this->curl); # This needs CURLOPT_RETURNTRANSFER => TRUE
I'm not sure about CURLOPT_POSTFIELDS because you don't have specified what $requestString contains. It's likely that this setting above is wrong. See curl POST format for CURLOPT_POSTFIELDS.
Edit: You have specified it via http_post_data:
String containing the pre-encoded post data
Curl supports that as well, just don't pass as array, pass it as string:
CURLOPT_POSTFIELDS => $requestString,
Try removing username and password from the URL and use CURLOPT_USERPWD without brackets:
curl_setopt(CURLOPT_USERPWD, "$this->username:$this->password");
your URL is not supposed to contain the username and password - when you do that, curl interprets it to be part of the hostname.
Hence the error "couldn't connect to host".
you're already doing the needful by including the authentication information by setting the USERPWD option.

Categories