PHP cURL vs. file_get_contents when using proxy - php

Running in Windows.
The following code works fine. I don't have specify a username and password when setting up the proxy.
$aContext = array(
'http' => array(
'proxy' => 'tcp://ip:port',
'request_fulluri' => true,
),
);
$cxContext = stream_context_create($aContext);
echo file_get_contents("someurl", False, $cxContext);
However when I try this code it won't work unless I specify the username and password for the proxy.
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_setopt($ch, CURLOPT_PROXY, 'http://ip:port');
curl_setopt($ch, CURLOPT_URL, "someurl");
$responseBody = curl_exec($ch);
I get an HTTP 407 error (Received HTTP code 407 from proxy after CONNECT) unless i specify the http://domain\user:password#ip:port
Any ideas how to make cURL work without specifying the user and password (like file_get_contents does)?

You can use the CURLOPT_PROXY and CURLOPT_PROXYPORT options:
curl_setopt($ch, CURLOPT_PROXY, "123.123.123.123");
curl_setopt($ch, CURLOPT_PROXYPORT, 8080);
It's unclear from your question, but if you need to use a username and password to authenticate with this proxy, then you can use the CURLOPT_PROXYUSERPWD option to specify your username and password and the CURLOPT_PROXYAUTH option to specify your authentication method:
curl_setopt($ch, CURLOPT_PROXYUSERPWD, "username:password");
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); //HTTP Basic auth
Also, depending on what type of proxy you are working with, you may need to specify the type in the CURLOPT_PROXY setting or separately via CURLOPT_PROXYTYPE.
Documentation:
http://php.net/manual/en/function.curl-setopt.php
http://curl.haxx.se/libcurl/c/curl_easy_setopt.html

Related

Apple Pay for the web Startsession Handshake Error

I am currently trying to implement apple pay for the web which is quite the troublesome topic it seems. When I try to start a session according to the docs (https://developer.apple.com/documentation/apple_pay_on_the_web/apple_pay_js_api/requesting_an_apple_pay_payment_session) using Curl in PHP I receive a handshake error.
I don't know how to solve that. There is a very limited set of parameters available (link above) and nothing I tried so far worked.
My domain has TLS 1.3 and an overall ranking of A when I check via ssllabs.com
My call is currently looking like this
$url = 'https://apple-pay-gateway.apple.com/paymentservices/startSession';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['merchantIdentifier' => '##my-merchant-id##', 'displayName' => 'something', 'initiative' => 'web', 'initiativeContext' => '##my-domain-name##']));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
curl_close($ch);

PHP Soap issue: OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 54 or SSL: Connection reset by peer

I try to execute SOAP request,
request works well on Soap UI gives proper response, - copy paste payload from tries bellow
request not work on Postman gives Could not get any response error
request not work using php SoapClient library giving SoapClient::__doRequest(): SSL: Connection reset by peer error
request not work using php curl gives OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 54 error
all ready tries SoapClient in no wsdl mode, and different ssl verification option, and tries on remote server so is not internet connection issue.
this is code for point 3:
$this->client = new \SoapClient($this->wsdl, [
'soap_version' => SOAP_1_1,
'exceptions' => true,
'trace' => true,
'cache_wsdl' => WSDL_CACHE_NONE,
]);
$response = $this->client->__doRequest(trim($xml), $url, 'getReport', SOAP_1_1);
this is code for point 4:
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); // both 0 & 1 not works
curl_setopt($ch, CURLOPT_URL, $location);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); // also tries different values
curl_setopt($ch, CURLOPT_TIMEOUT, 15); // here too
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, trim($request));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1); // also not works without this
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // and this
$response = curl_exec($ch);
what can i do to debug this issue more deeply and solve it?
turns out that header value SOAPAction needs to be in extra escaped quote like this:
$headers = [
"SOAPAction: \"http://example-url.com\"",
]

PHP - with curl, how to send username password in a popup of htpasswd?

I have to submit POST method using curl, but while opening $URL it has a popup window with username/password to submit (like with htpasswd).
For some reason the following code is not working i get from server
HTTP/1.1 401 Unauthorized and HTTP/1.1 404 Not Found ( https://www.httpwatch.com/httpgallery/authentication/ )
// For Debug server response details
$curlOptions = array(
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_FOLLOWLOCATION => TRUE,
CURLOPT_VERBOSE => TRUE,
CURLOPT_STDERR => $verbose = fopen('php://temp', 'rw+'),
CURLOPT_FILETIME => TRUE,
);
// Real meat
$ch = curl_init();
curl_setopt_array($ch, $curlOptions);
curl_setopt($ch, CURLOPT_URL,$URL);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
// is this the right way here in POST method???
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");// is this correct way to enter username/password in the popup?
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$result=curl_exec ($ch);
// Pretty print the debug logs
echo '<pre>',
!rewind($verbose),
stream_get_contents($verbose),
"\n",
'</pre>';
curl_close ($ch);
echo $result;
How can i make sure my POST method submission is really submitting the username/password? (debug log i do not see if i have submitted correctly, server is also not maintained by me, as its third-party service providers API)
EDIT:
TRY1: FAILED
// For Debug server response details
$curlOptions = array(
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_FOLLOWLOCATION => TRUE,
CURLOPT_VERBOSE => TRUE,
CURLOPT_STDERR => $verbose = fopen('php://temp', 'rw+'),
CURLOPT_FILETIME => TRUE,
);
// Real meat
$ch = curl_init();
curl_setopt_array($ch, $curlOptions);
//
//
//
//
// STACK-OVERFLOW EXPERT SAID UPDATE THE $URL WITH USER:PASS# THIS
//
//
//
//
$URL = "http://$username:$password#site.com/postblabla";
curl_setopt($ch, CURLOPT_URL, $URL);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
//
//
//
//
// STACK-OVERFLOW EXPERT SAID REMOVE THIS
//
//
//
//
//curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$result=curl_exec ($ch);
// Pretty print the debug logs
echo '<pre>',
!rewind($verbose),
stream_get_contents($verbose),
"\n",
'</pre>';
curl_close ($ch);
echo $result;
With HTTP Auth, you send a username and a password as a part of the URL:
<schema>://<username>:<password>#<url>
Also see this SO question and answer.
However, the CURLOPT_USERPWD should have worked as well as both methods only set HTTP Authorization header. as mentioned here. This is also safer as your credentials will not be transferred as plaintext in URL and with potential use of SSL/TLS they will not be visible out in the open.
Also, setting HTTP Basic auth may help.
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);

PHP cURL returns FALSE on HTTPS

I'm trying to make a bot for: https://coinroll.it/api
From the site:
The Coinroll API is a stateless interface which works over HTTPS. Requests are made using POST variables (application/x-www-form-urlencoded) while responses are encoded in JSON (application/json). A HTTPS connection is required for accessing the API.
I have the following code:
$ch = curl_init();
$data = array('user' => 'xxx', 'password' => 'yyy');
curl_setopt($ch, CURLOPT_URL, 'https://coinroll.it');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
echo $result;
When I run this code, it returns a blank page, what am I doing wrong?
EDIT
I don't actually need to use cURl, if there is a better solution, please tell me.
You can prevent cURL from trying to verify the SSL certificate by using CURLOPT_VERIFYPEER.
Also set the action in the URL:
$ch = curl_init();
$data = array('user' => 'xxx', 'password' => 'yyy');
curl_setopt($ch, CURLOPT_URL, 'https://coinroll.it/getbalance');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$result = curl_exec($ch);
echo $result;
You can use the following cURL option in order to see what happens with the HTTP connection:
curl_setopt($ch, CURLOPT_VERBOSE, true);
When TRUE it outputs verbose information.
Today I had the case where "It had been working fine until now.", but it stopped working when the FQDN changed, and I had to self-sign another certificate, with a different DN.
After a few experiments, it turned out to be that the Subject Alternate Name (aka SAN) was not matching the certificate name, and the curl call had not been set with CURLOPT_SSL_VERIFYHOST, 2.
Conclusion: by default, CURLOPT_SSL_VERIFYHOST is set to 2, but, if your cert SAN is wrong, it will fail, unless you deactivate CURLOPT_SSL_VERIFYHOST, and, with it, CURLOPT_SSL_VERIFYPEER.
It is obviously the best practice to set both, and have a SAN that matches the subject.
Reminder: this is how to quickly check the SAN using OpenSSH on command line:
openssl x509 -in /etc/ssl/certs/recette.pharmags.fr.crt -noout -text | grep -A1 "Subject Alternative Name"

How to get info on sent PHP curl request

I'm trying to debug a curl request to a webservice 'getToken' endpoint.
I'm not 100% confident that the URL and the auth info is getting written in to the curl handle correctly.
I'm trying to use curl_getinfo($ch, CURLINFO_HEADER_OUT); to capture the sent request, but it doesn't give me much info. Is there a way to get more in depth diagnostics about what the actual curl request looks like?
Here's the code:
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
curl_setopt($ch, CURLOPT_HEADER, 1); // just getting header to see if we got an auth token
curl_setopt($ch, CURLOPT_FILE, $fh);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLINFO_HEADER_OUT, 1); // capture the header info
curl_setopt($ch, CURLOPT_VERBOSE, 1); // turn verbose on
// execute the curl request
$rh = fopen("request.txt", "w"); // open request file handle
$verbose = fopen('php://temp', 'rw+');
curl_setopt($ch, CURLOPT_STDERR, $verbose);
curl_exec($ch); // execute request
$sent_request = curl_getinfo($ch, CURLINFO_HEADER_OUT);
fwrite($rh, $sent_request); // save the request info
fclose($rh);
!rewind($verbose);
$verboseLog = stream_get_contents($verbose);
echo "Verbose information:\n<pre>", htmlspecialchars($verboseLog), "</pre>\n";
This all works as far as it goes, but returns a 401 every time-- the API admin assures me that the username / pass I have is correct.
I was wondering if I'm somehow getting the URL value wrong, or not sending the right username / pass, but this info isn't printed in the request data saved:
HEAD /export/auth HTTP/1.1
Authorization: Basic Y2FpcmRzdW5mYTpENWlAaVM4cw==
Host: webservices.mycompany.com
Accept: */*
You can see that the username/pass is not recorded (I assume for security). The endpoint URL I think is the host value plus the start of the HEAD value, so webservices.mycompany.com/export/auth?
The "Verbose Information" statement prints nothing. Not sure why on this either!
Thanks for help.
EDIT: added verbose mode from Php - Debugging Curl thanks to commenter immulatin
If you set CURLINFO_HEADER_OUT to true, outgoing headers are available in the array returned by curl_getinfo(), under request_header key:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://foo.com/bar");
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "someusername:secretpassword");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_exec($ch);
$info = curl_getinfo($ch);
print_r($info['request_header']);
This will print:
GET /bar HTTP/1.1
Authorization: Basic c29tZXVzZXJuYW1lOnNlY3JldHBhc3N3b3Jk
Host: foo.com
Accept: */*
Note the auth details are base64-encoded:
echo base64_decode('c29tZXVzZXJuYW1lOnNlY3JldHBhc3N3b3Jk');
// prints: someusername:secretpassword
Also note that username and password need to be percent-encoded to escape any URL reserved characters (/, ?, &, : and so on) they might contain:
curl_setopt($ch, CURLOPT_USERPWD, urlencode($username).':'.urlencode($password));
You can also use a proxy tool like Charles to capture the outgoing request headers, data, etc. by passing the proxy details through CURLOPT_PROXY to your curl_setopt_array method.
For example:
$proxy = '127.0.0.1:8888';
$opt = array (
CURLOPT_URL => "http://www.example.com",
CURLOPT_PROXY => $proxy,
CURLOPT_POST => true,
CURLOPT_VERBOSE => true,
);
$ch = curl_init();
curl_setopt_array($ch, $opt);
curl_exec($ch);
curl_close($ch);
curl_getinfo() must be added before closing the curl handler
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://example.com/bar");
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, "someusername:secretpassword");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_exec($ch);
$info = curl_getinfo($ch);
print_r($info['request_header']);
curl_close($ch);
The request is printed in a request.txt with details
$ch = curl_init();
$f = fopen('request.txt', 'w');
curl_setopt_array($ch, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_VERBOSE => 1,
CURLOPT_STDERR => $f,
));
$response = curl_exec($ch);
fclose($f);
curl_close($ch);
You can also use curl_getinfo() function.

Categories