php cURL sometimes works, sometimes doesn't - php

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?

Related

curl works in CLI, but not in 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

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.

Curl is working however error with php CURL

We want to communicate to the 3rd party API for which we are using curl from linux terminal. The curl is -
curl -X POST \
\
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json'
When we fire this curl then we are getting expected response.
However, when we try to do this from PHP script then we are getting error as -
HTTP ERROR 500
PHP Code snippet is -
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, <URL>);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
//curl_setopt($ch, CURLOPT_POSTFIELDS,'');
curl_setopt($ch, CURLOPT_VERBOSE,true);
$headers = array();
$headers[] = 'Authorization: Bearer <token>';
$headers[] = 'Content-Type: application/json';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
echo $result;
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
curl_close($ch);
?>
When verbose mode is on then response received is -
* Trying <IP>...
* Connected to <URL> (<IP>) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:#STRENGTH
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: OU=Domain Control Validated; CN=* <domain>
* start date: Dec 17 10:41:01 2017 GMT
* expire date: Dec 17 10:41:01 2020 GMT
* subjectAltName: <URL> matched
* issuer: C=US; ST=Arizona; L=Scottsdale; O=GoDaddy.com, Inc.; OU=http://certs.godaddy.com/repository/; CN=Go Daddy Secure Certificate Authority - G2
* SSL certificate verify ok.
> POST /app/auth HTTP/1.1
Host: <URL>
Accept: */*
Authorization: Bearer <Token>
Content-Type: application/json
Expect: 100-continue
< HTTP/1.1 500 Request failed.
< Cache-Control: must-revalidate,no-cache,no-store
< Content-Type: text/html;charset=iso-8859-1
< Date: Wed, 08 Jan 2020 04:39:23 GMT
< Content-Length: 252
< Connection: keep-alive
* HTTP error before end of send, stop sending
<
* Closing connection 0
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 500 Request failed.</title>
</head>
<body><h2>HTTP ERROR 500</h2>
<p>Problem accessing /app/auth. Reason:
<pre> Request failed.</pre></p>
</body>
</html>
Please note that Ihave replaced actual URL,IP and token while posting the question here.
To make sure that there are no issues with the PHP curl we used curl-to-PHP code generator utility to generate code ( http://incarnate.github.io/curl-to-php/).
Can someone please help me and let me know what might be going wrong.
To avoid «500 error» (for example) be sure to:
set proper "Referer: " header if needed, with
curl_setopt(CURLOPT_REFERER, 'ref page');
set proper "User-Agent: " header, with
curl_setopt(CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)');

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