curl works in CLI, but not in PHP - php

curl works in CLI, but not in PHP.
The following command works in the command line:
curl -X POST --header "Content-Type: application/json" --header "Authorization: Basic [token]" https://api.example.com/v1/token -v -k
* About to connect() to api.example.com port 443 (#0)
..
> POST /v1/token HTTP/1.1
> User-Agent: curl/7.29.0
> Host: api.example.com
> Accept: */*
> Content-Type: application/json
> Authorization: Basic [token]
>
< HTTP/1.1 200 OK
< Date: Fri, 30 Apr 2021 02:52:24 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 325
< Connection: keep-alive
< X-Powered-By: Express
< ETag: W/"145-rseWkvhNxxhur+O7jUfApznKiww"
<
* Connection #0 to host api.example.com left intact
{"accesstoken":"token","type":"Bearer","expired":"20210501115224"}
And in PHP using the code below:
test.php
<?php
$host = 'https://api.example.com/v1/token';
$headers = array(
'Content-Type: application/json',
'Authorization: Basic [token]'
);
$oCurl = curl_init();
curl_setopt($oCurl, CURLOPT_URL, $host);
curl_setopt($oCurl, CURLOPT_POST, true);
curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($oCurl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($oCurl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($oCurl, CURLOPT_VERBOSE, true);
$response = curl_exec($oCurl);
curl_close($oCurl);
$ php test.php
* About to connect() to api.example.com port 443 (#0)
..
> POST /v1/token HTTP/1.1
Host: api.example.com
Accept: */*
Content-Type: application/json
Authorization: Basic [token]
Content-Length: -1
Expect: 100-continue
< HTTP/1.1 100 Continue
< HTTP/1.1 400 Bad Request
< Server: nginx
< Date: Fri, 30 Apr 2021 04:22:08 GMT
< Content-Type: text/html
< Content-Length: 150
< Connection: close
<
* Closing connection 0
The result is a HTTP Status code 400 Bad Request. Is there something I'm doing wrong?
Please Help.
Any ideas would be greatly appreciated.

Content-Length: -1 looks weird.
Seems like cURL is adding that automatically, because your request does not contain a POST body - but then it should be set to 0, if it gets set at all.
Add 'Content-Length: 0' to your $headers array, so that cURL won’t add the header itself with the wrong value.

#choi
did you encode your token?
ej.
$host = 'https://api.example.com/v1/token';
$token = base64_encode('username:Password0..');
$headers = array(
'Content-Type: application/json',
'Authorization: Basic ' . $token
);
$oCurl = curl_init();
curl_setopt($oCurl, CURLOPT_URL, $host);
...
Response
$> php curl_test.php
* Trying 127.0.0.1:8080...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> POST /v1/token HTTP/1.1
Host: 127.0.0.1:8080
Accept: */*
Content-Type: application/json
Authorization: Basic dXNlcm5hbWU6UGFzt3dtcmQwLi4=
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx
< Date: Fri, 30 Apr 2021 06:50:59 GMT
< Content-Type: application/json; charset=utf-8
< Transfer-Encoding: chunked
< Connection: keep-alive
...
Ref: curl basic auth

Related

PHP_curl loose content-length on redirect

I'm trying to make a request to payment processing page. This requires authorization, which takes place through a set of redirects. In the second step, I get "411 Length Required" error, which means that content-length was lost along the way. Indeed, I cannot see it in the log. What can be done here? Change tool (programming language)?
CURLOPT_VERBOSE:
* Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to api.dev.example.com (188.186.236.44) port 443 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server accepted to use http/1.1
* Server certificate:
* subject: OU=Domain Control Validated; OU=PositiveSSL Wildcard; CN=*.dev.example.com
* start date: Apr 27 00:00:00 2019 GMT
* expire date: Apr 26 23:59:59 2021 GMT
* subjectAltName: host "api.dev.example.com" matched cert's "*.dev.example.com"
* issuer: C=GB; ST=Greater Manchester; L=Salford; O=Sectigo Limited; CN=Sectigo RSA Domain Validation Secure Server CA
* SSL certificate verify ok.
> POST /p2p/v2/payer HTTP/1.1
Host: api.dev.example.com
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Content-Length: 224
* upload completely sent off: 224 out of 224 bytes
< HTTP/1.1 302 Found
< Server: nginx
< Date: Mon, 13 Jul 2020 14:22:54 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 213
< Connection: keep-alive
< Keep-Alive: timeout=20
< Cache-Control: private
< Location: /api/payer/auth?sessionToken=e744a95992fa405ba10662bbc6908d6bedd48a73cc0d45d589f4ef2f7d7a0b88
< Set-Cookie: returnUrl=http://example.com/returnurl.php; path=/
<
* Ignoring the response-body
* Connection #0 to host api.dev.walletone.com left intact
* Issue another request to this URL: 'https://api.dev.example.com/auth?sessionToken=e744b95992fa405ba10662bbc6908d6b7dd48a73cc0d45d589f4ef2f7d7a0b88'
* Switch from POST to GET
* Found bundle for host api.dev.example.com: 0x5649fd243480 [can pipeline]
* Re-using existing connection! (#0) with host api.dev.example.com
* Connected to api.dev.example.com (188.186.236.44) port 443 (#0)
> POST /auth?sessionToken=e744b95992fa405ba10662bbc6908d6b7dd48a73cc0d45d589f4ef2f7d7a0b88 HTTP/1.1
Host: api.dev.example.com
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
< HTTP/1.1 411 Length Required
< Server: nginx
< Date: Mon, 13 Jul 2020 14:22:54 GMT
< Content-Type: text/html; charset=us-ascii
< Content-Length: 344
< Connection: keep-alive
< Keep-Alive: timeout=20
<
* Connection #0 to host api.dev.example.com left intact
My code is:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $path);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, Array (
"Content-Type: application/x-www-form-urlencoded",
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $curl_method);
curl_setopt($ch, CURLOPT_POSTFIELDS, $order_data);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_STDERR, $verbose);
$response = curl_exec($ch);
curl_close($ch);
Set the content-length in the header, which would be set to the string length strlen() of $order_data
curl_setopt($ch, CURLOPT_HTTPHEADER, Array (
"Content-Type: application/x-www-form-urlencoded",
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Content-Length: ". strlen($order_data)
));
you can also debug this by checking out curl_setopt($ch, CURLINFO_HEADER_OUT, true); which makes curl_getinfo() include the request's headers in its output.
The problem was in using curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $curl_method). Curl tryed to swithc to GET, like mostly browsers do, but cannot. Use curl_setopt($ch, CURLOPT_POST, 1); indeed.

php cURL sometimes works, sometimes doesn't

I have a strange situation.
I am trying to make curl requests in php. Sometimes it returns valid response, sometimes it returns "HTTP/1.1 401 Unauthorized. One common pattern is, if I wait for long time, 5 minutes between requests it works. If I make a request immediately after each other it fails. (This pattern is not consistent either) But sometimes I can make successful request one after another.
If I make the same request using curl command it works all the time. The verbose between the two are exactly the same.
<?php
$api = new ApiRestTest(URL,LOGIN,APIKEY);
$result = $api->curl_req(CONTACT_TEST);
var_dump($result);
class ApiRestTest
{
protected $_url;
protected $_username;
protected $_apiKey;
public function __construct($url, $username, $apiUserKey) {
$this->_url = $url;
$this->_username = $username;
$this->_apiKey = $apiUserKey;
}
private function getHeader() {
$nonce = base64_encode(substr(md5(uniqid()), 0, 16));;
$created = date('c');
$digest = base64_encode(sha1(base64_decode($nonce) . $created . $this->_apiKey, true));
$wsseHeader[] = "Content-type:application/vnd.api+json";
$wsseHeader[] = "Accept: application/json";
$wsseHeader[] = "Authorization: WSSE profile=\"UsernameToken\"";
$wsseHeader[]= sprintf(
'X-WSSE: UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"', $this->_username, $digest, $nonce, $created
);
var_dump($wsseHeader);
return $wsseHeader;
}
public function curl_req($path, $data=array())
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->_url . $path);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_USERAGENT, 'curl/7.54.0');
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->getHeader());
$data = curl_exec($ch);
curl_close($ch);
return $data;
}}
curl command line output
$ curl -v -H "Content-type:application/vnd.api+json" -H "Accept: application/json" -H 'Authorization: WSSE profile="UsernameToken"' -H 'X-WSSE: UsernameToken Username="system", PasswordDigest="D1jXzXaTxcZDJ6YKvtqkggkhXV8=", Nonce="ODM3ZWVmZTRiY2U0MmIzNQ==", Created="2017-08-30T10:16:55+10:00"' http://orocampus.tk/app.php/api/contacts/2
Trying 45.76.122.100...
TCP_NODELAY set
Connected to orocampus.tk (45.76.122.100) port 80 (#0)
> GET /app.php/api/contacts/2 HTTP/1.1
> Host: orocampus.tk
> User-Agent: curl/7.54.0
> Content-type:application/vnd.api+json
> Accept: application/json
> Authorization: WSSE profile="UsernameToken"
> X-WSSE: UsernameToken Username="system", PasswordDigest="D1jXzXaTxcZDJ6YKvtqkggkhXV8=", Nonce="ODM3ZWVmZTRiY2U0MmIzNQ==", Created="2017-08-30T10:16:55+10:00"
>
< HTTP/1.1 200 OK
< Server: nginx/1.13.3
< Date: Wed, 30 Aug 2017 00:17:17 GMT
< Content-Type: application/vnd.api+json
< Transfer-Encoding: chunked
< Cache-Control: no-cache
< Set-Cookie: SERVERID=web2; path=/
<
* Connection #0 to host orocampus.tk left intact
php output
$ php test.php
array(4) {
[0]=>
string(37) "Content-type:application/vnd.api+json"
[1]=>
string(24) "Accept: application/json"
[2]=>
string(43) "Authorization: WSSE profile="UsernameToken""
[3]=>
string(157) "X-WSSE: UsernameToken Username="system", PasswordDigest="D1jXzXaTxcZDJ6YKvtqkggkhXV8=", Nonce="ODM3ZWVmZTRiY2U0MmIzNQ==", Created="2017-08-30T10:16:55+10:00""
}
* Trying 45.76.122.100...
* TCP_NODELAY set
* Connected to orocampus.tk (45.76.122.100) port 80 (#0)
> GET /app.php/api/contacts/2 HTTP/1.1
Host: orocampus.tk
User-Agent: curl/7.54.0
Content-type:application/vnd.api+json
Accept: application/json
Authorization: WSSE profile="UsernameToken"
X-WSSE: UsernameToken Username="system", PasswordDigest="D1jXzXaTxcZDJ6YKvtqkggkhXV8=", Nonce="ODM3ZWVmZTRiY2U0MmIzNQ==", Created="2017-08-30T10:16:55+10:00"
< HTTP/1.1 401 Unauthorized
< Server: nginx/1.13.3
< Date: Wed, 30 Aug 2017 00:16:53 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Cache-Control: no-cache
< WWW-Authenticate: WSSE realm="Secured API", profile="UsernameToken"
< Set-Cookie: SERVERID=web2; path=/
<
* Connection #0 to host orocampus.tk left intact
string(277) "HTTP/1.1 401 Unauthorized
Server: nginx/1.13.3
Date: Wed, 30 Aug 2017 00:16:53 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Cache-Control: no-cache
WWW-Authenticate: WSSE realm="Secured API", profile="UsernameToken"
Set-Cookie: SERVERID=web2; path=/
I have tried to run curl in php. It also failed
function request($path) {
$curl = "curl -v -H \"Content-type:application/vnd.api+json\" -H \"Accept: application/json\" -H 'Authorization: WSSE profile=\"UsernameToken\"'".
" -H ".$this->getHeader()[3]."' " . $this->_url . $path;
var_dump($curl);
exec($curl, $output, $exit);
var_dump($output);
return $exit == 0;
}
If I run the same curl command in the terminal, it works fine. What is the problem?

How to duplicate a POST Request with CURL in PHP

I have a webapp that needs to be able to recreate the post actions of application provided by our vendor. The application allows the user to log in or out of phone workgroups. I have captured the HTTP Post request that the application is sending to initiate a session and to log the user in and out of the workgroups. I would like to recreate these POSTs in PHP using CURL, but I am having some issues getting the POST correct.
The post I am trying to emulate as captured from WireShark looks like this :
POST /Login?timeout=6 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: 10.1.##.##:5447
Content-Length: 160
Expect: 100-continue
Connection: Keep-Alive
{"username":"joell","user-auth-token":"TOKENTOKENTOKEN","user-role":"admin_role","client-type":3,"app-id":"cmwin.18.62.7800.0"}
Response
HTTP/1.1 200 OK
Content-Length: 58
Content-Type: text/plain; charset=UTF-8
Connection: Keep-Alive
Cache-Control: no-store
Date: Fri, 03 Apr 2015 13:08:42 GMT
Expires: Fri, 03 Apr 2015 13:08:42 GMT
Access-Control-Allow-Origin: *
Set-Cookie: SessionId=2006727099
My php code atempting to recreate this is:
$data = array(
"username" => "joell",
"user-auth-token" => "TOKENTOKENTOKEN",
"user-role" => "admin_role",
"client-type" => 3,
"app-id" => "cmwin.18.62.7800.0"
);
$data_string = json_encode($data);
$curl = curl_init('http://10.1.##.##:5447/Login?timeout=6');
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded',
'Content-Length: ' . strlen($data_string),
'Expect: 100-continue',
'Connection: Keep-Alive')
);
if(!curl_exec($curl)){
die('Error: "' . curl_error($curl) . '" - Code: ' . curl_errno($curl));
}
$result = curl_exec($curl);
print_r($result);
curl_close($curl);
The request that my script is generating is:
POST /Login?timeout=6 HTTP/1.1
Host: 10.1.##.##:5447
Accept: */*
Content-Type: application/x-www-form-urlencoded
Content-Length: 160
Expect: 100-continue
Connection: Keep-Alive
{"username":"joell","user-auth-token":"TOKETOKETOKEN","user-role":"admin_role","client-type":3,"app-id":"cmwin.18.62.7800.0"}
Response
HTTP/1.1 200 OK
Content-Length: 20
Content-Type: text/plain; charset=UTF-8
Connection: Keep-Alive
Cache-Control: no-store
Date: Fri, 03 Apr 2015 15:15:44 GMT
Expires: Fri, 03 Apr 2015 15:15:44 GMT
Access-Control-Allow-Origin: *
Currently the output of my PHP script is :
{"error":2147483650}

Send SOAP request using CURL

I am sending a soap request using PHP curl(). I need to print my request, so that I can have a look into my request and understand weather it is going in a right format.
Here is my code:
$parameters = "<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:ejb='http://ejb.gateway.ebpp.fawryis.com/'>
<soapenv:Header/>
<soapenv:Body>
<ejb:process>
//...
</ejb:process>
</soapenv:Body>
</soapenv:Envelope>";
$url='//URL to the service';
$curl = curl_init();
curl_setopt ($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl,CURLOPT_ENCODING,'utf-8');
curl_setopt($curl,CURLOPT_HTTPHEADER,array (
'SOAPAction:""',
'Content-Type: text/xml;
charset=utf-8',
));
curl_setopt ($curl, CURLOPT_POST, 1);
curl_setopt ($curl, CURLOPT_POSTFIELDS, $parameters);
$result = curl_exec($curl);
I get a wrong data sent error from the API side which means I am not sending a correct format.
Can anyone please let me know how to do that?
Update:
Verbose information
* About to connect() to 10.2.250.4 port 9081 (#0)
* Trying 10.2.250.4...
* connected
* Connected to 10.2.250.4 (10.2.250.4) port 9081 (#0)
> POST /CoreWeb/ApplicationBusinessFacadeService HTTP/1.1
Host: 10.2.250.4:9081
Accept: */*
Accept-Encoding: utf-8
SOAPAction:""
Content-Type: text/xml;
charset=utf-8
Content-Length: 1087
Expect: 100-continue
< HTTP/1.1 100 Continue
< Content-Length: 0
< Date: Thu, 20 Mar 2014 14:04:19 GMT
< Server: WebSphere Application Server/7.0
< HTTP/1.1 200 OK
< Date: Thu, 20 Mar 2014 14:04:19 GMT
< Server: WebSphere Application Server/7.0
< Content-Type: text/xml; charset=utf-8
< Content-Language: en-US
< Content-Length: 914
<
* Connection #0 to host 10.2.250.4 left intact
Your Header is broken into two lines:
'Content-Type: text/xml;
charset=utf-8',
Make it in one line. May be it is causing the problem for you.
'Content-Type: text/xml;charset=UTF-8',
UPDATE:
curl_setopt($curl,CURLOPT_HTTPHEADER,array (
'SOAPAction:""',
'Content-Type: text/xml;charset=utf-8',
'Expect:'
));

Error 401 using curl in PHP to access REST API

I am trying to execute a curl command that I can execute successfully in the terminal but it fails in PHP script with the following error:
HTTP/1.1 401 Unauthorized Access-Control-Allow-Origin: * Access-Control-Request-Method: * Cache-Control: no-cache Content-Type: application/json; charset=utf-8 Date: Mon, 06 Feb 2012 00:38:56 GMT Server: nginx/1.0.4 Set-Cookie: _parse_session=XXXXXX; domain=.parse.com; path=/; expires=Sun, 06-Feb-2022 00:38:56 GMT; HttpOnly Status: 401 Unauthorized WWW-Authenticate: Basic realm="Parse" X-Runtime: 0.002486 X-UA-Compatible: IE=Edge,chrome=1 Content-Length: 24 Connection: keep-alive {"error":"unauthorized"}
This is the command executed in terminal that executes successfully:
curl -H "Accept: application/json" -H "X-Parse-Application-Id: XXXXXXX" -H "X-Parse-REST-API-Key: XXXXXXXXX" -X GET "https://api.parse.com/1/classes/XXXXXX"
This is the PHP code:
$fields = array('Accept: '=>'application/json',
'X-Parse-Application-Id:' => 'XXXXX',
'X-Parse-REST-API-Key:' => 'XXXXX');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.parse.com/1/classes/XXXX');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
curl_setopt($ch, CURLOPT_HEADER, $fields);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt(CURLOPT_USERPWD, 'XXXXXX');
$result = curl_exec($ch);
curl_close($ch);
The interesting note is that when executed in the terminal authentication info is not required.
Help will be appreciated.
Thanks
Your header fields shouldn't have the : in the array defnition:
'X-Parse-REST-API-Key:' => 'XXXXX');
^---remove these
That makes the : part of the field name, so you're actually sending:
X-Parse-REST-API-Key:: XXXXX
^^---note the doubled colons
Your header is set using CURLOPT_HTTPHEADER, not CURLOPT_HEADER which expects a boolean value

Categories