file_get_contents ignoring verify_peer=>false? - php

file_get_contents with https hosts works just fine, except for a particular host (test api server from some company - ip whitelisted, can't give you URL to test). This rules out not loaded https modules and other initial setup mistakes.
I have tested with multiple PHP installations, all at v5.3.3, 32bits, Debian 32bits.
The request works with cURL, but only if setting curl_setopt($curl,
CURLOPT_SSL_VERIFYPEER, 0);. However, setting verify_peer"=>false on the context for file_get_contents seems to make no difference.
With file_get_contents, the exact same request (same URL, same XML POST data) fails with SSL: Connection reset by peer:
$arrContextOptions=array(
"http" => array(
"method" => "POST",
"header" =>
"Content-Type: application/xml; charset=utf-8;\r\n".
"Connection: close\r\n",
"ignore_errors" => true,
"timeout" => (float)30.0,
"content" => $strRequestXML,
),
"ssl"=>array(
"allow_self_signed"=>true,
"verify_peer"=>false,
),
);
file_get_contents("https://somedomain:2000/abc/", false, stream_context_create($arrContextOptions));
.
Has anyone encountered this with file_get_contents? Any ideas how to debug?

You missed verify_peer_name. If you set that to false as well, the request works:
$arrContextOptions=array(
"http" => array(
"method" => "POST",
"header" =>
"Content-Type: application/xml; charset=utf-8;\r\n".
"Connection: close\r\n",
"ignore_errors" => true,
"timeout" => (float)30.0,
"content" => $strRequestXML,
),
"ssl"=>array(
"allow_self_signed"=>true,
"verify_peer"=>false,
"verify_peer_name"=>false,
),
);
file_get_contents("https://somedomain:2000/abc/", false, stream_context_create($arrContextOptions));

dont' know if this will actually help, but do try removing the SSL options from your option array.
The reason behind this:
according to http://www.php.net/manual/en/context.ssl.php , verify_peer is false by default.
allow_self_signed REQUIRES verify_peer, and is false by default.
From the above, I gather that allow_self_signed probably overrides your setting for verify_peer.
So please try without any option for SSL, or without the allow_self_signed, and let us know if that helped any.

You could try to debug this with Wireshark -- you might get a better idea of what goes wrong, you should see which SSL error occurs.

try this code :
$fp = fsockopen("ssl://somedomain/abc/", 2000 , $ErrNo, $ErrString, 30);
if (!$fp) {
echo "Error No : $ErrNo - $ErrString <br />\n";
} else {
$out = "POST / HTTP/1.1\r\n";
$out .= "Host: somedomain \r\n";
$out .= "Content-Type: application/xml; charset=utf-8;\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
if you don't get error , i think problem (with file_get_contents) is form client php configuration otherwise from server configuration.

only install this
yum install ca-certificates.noarch

Related

file_get_contents + stream_context_create works on 1 server, blocked on another

We have 2 servers, dev and live. They both use LAMP (Debian), but the dev server is regular http and the live server is https. This code works perfectly on our dev server:
$all_data = array(...);
$eol = "\r\n";
$headers = array(
'Content-Type: application/json',
'Content-Length: ' . strlen(json_encode($all_data)),
'connection: close'
);
$headers = implode($eol, $headers);
$opts = array(
'http'=>array(
'method' => 'POST',
'header' => $headers,
'content' => json_encode($all_data)
)
);
$context = stream_context_create($opts);
$update_data = file_get_contents($_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . $system_file, null, $context);
On the live server, the file_get_contents gives this error:
Warning: file_get_contents(https://...): failed to open stream: Connection timed out in ....php on line 1086
I have looked at the apache logs for clues as to what is causing it to fail on the live server, but I only see the error above. It doesn't say what's blocking the call. I have allow_url_include and allow_url_fopen set to On on the live server.
I don't know if it's something in the Apache configuration or the SSL configuration, or something else, and I don't know where to look. I spent several hours today researching this issue and tried adding different headers to the headers array (User-Agent, Accept-Language, Accept-Encoding, Cookie, etc.), but nothing worked. I basically tried to replicate what was on dev, but live just didn't like it.
I also verified that if I copy and paste the URL that's being created directly in the browser that it works, so I know the filename is correct.
dev server:
php: 5.6.14-0+deb8u1
apache: Apache/2.4.10
debian: 8.2
live server:
php: 5.5.12
apache: Apache/2.4.10
debian: 7.9
Can you please use proxy and try
$aContext = array(
'http' => array(
'proxy' => 'tcp://192.168.0.2:3128',
'request_fulluri' => true,
),
);
$cxContext = stream_context_create($aContext);
$sFile = file_get_contents("http://www.google.com", False, $cxContext);
echo $sFile;

HTTP Request file get contents not working

I'm trying to send a file through rest using HTTP request to BonitaBPM but the file im trying to send comes out empty when i use file get contents and the HTTP request doesn't work obviously due to that
$file_contents = file_get_contents("C:/inetpub/wwwroot/upload/Director.png");
$data1 = array(
"caseId"=> $case_id[1],
"file"=>"C:/inetpub/wwwroot/upload/Director.png",
"name"=>"doc_invoice",
"fileName"=> $_FILES['file_attach']['name'],
"description"=> "Invoice"
);
//Structure of process data to start case
$options1 = array(
"http" => array(
"method" => "POST",
"header"=> "POST /bonita/API/bpm/caseDocument HTTP/1.1\r\n".
"Host: bonita.libertypr.com\r\n".
"Cookie: ". $display[1]."\r\n".
"Content-Type: application/json\r\n" .
"Accept: application/json\r\n".
"Cache-Control: no-cache\r\n".
"Pragma: no-cache\r\n".
"Connection: Keep-Alive\r\n\r\n",
"content" => json_encode($data1)
)
);
//decode process data and adds document to case
$url1 = "http://bonita.libertypr.com:8081/bonita/API/bpm/caseDocument";
$context1 = stream_context_create($options1);
$result1 = file_get_contents($url1, false, $context1);
$response1 = json_decode($result1);
Please make sure that you are authenticated on the Bonita side before calling this API call.
See this link for more details:
http://documentation.bonitasoft.com/rest-api-overview#authentication
If you are not, the Bonita API calls will be rejected.
To analyze a bit further what is causing the issue, you should get your hands on the HTTP request and response sent between your code and Bonita.
To do so, you can capture the HTTP traffic with a tool such as Wireshark
Cheers,

server not sending custom header values

I'm using PHP 5.2.17 to get a remote page, the HTTP requests contains some cookie values but cookies are not delivered to the destination page.
$url = 'http://somesite.com/';
$opts = array(
'http' => array
(
'header' => array("Cookie: field1=value1; field2=value2\r\n")
)
);
$context = stream_context_create($opts);
echo file_get_contents($url, false, $context);
Can you help me find the problem?
Note: I can't use curl.
Thanks.
Are you sure the receiving code is working properly?
I can get your example to work with the receiving page simply echoing:
<?php
echo $_COOKIE['field1'] . '::' . $_COOKIE['field2']; // returns value1::value2
?>
Alternatively, the site could be requiring a user agent (anything). I had this problem earlier in reaching Wikipedia (not restricted by all Mediawiki software; apparently just for the Wikimedia sites). Set the user_agent property inside the 'http' array to whatever value you want. (However, if you do happen to be trying to reach Wikipedia, you might instead try their api.php: http://en.wikipedia.org/w/api.php ; if another Mediawiki site, use the same relative path)
Maybe allow_url_fopen is not enabled, check the value w/ ini_get: ini_get('allow_url_fopen');
You might also do a sanity check by calling file_get_contents() on any old page you know is publicly accessible.
Other than that your example code looks just fine.
Second Option, Socket Connection:
<?php
$fp = fsockopen("somesite.com", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: somesite.com\r\n";
$out .= "Cookie: field1=value1; field2=value2; path=/; domain=somesite.com;\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
echo PHP_EOL;
$url = 'http://somesite.com/';
$opts = array(
'http' => array
(
'header' => "Cookie: field1=value1; field2=value2\r\n"
)
);
$context = stream_context_create($opts);
file_get_contents($url, false, $context);

Need to change fsocketopen to CURL to be able to navigate redirects

I have a php script that I recently added an array to. The php script checks URL's from the array for a set of text also in the array. Everything works great except the script will not follow redirects or check sub-pages.
I have been told that this is a limitation of fsocketopen and that I need to use CURL.
If this is the case then I require some assistance converting this from using fsocketopen to CURL. Hopefully there is some way to get fsocketopen to follow redirects or at least access sub-pages.
function check($host, $find){
$fp = fsockopen($host, 80, $errno, $errstr, 10);
if (!$fp){
echo "$errstr ($errno)\n";
} else {
$header = "GET / HTTP/1.1\r\n";
$header .= "Host: $host\r\n";
$header .= "Connection: close\r\n\r\n";
fputs($fp, $header);
while (!feof($fp)) {
$str.= fgets($fp, 1024);
}
fclose($fp);
return (strpos($str, $find) !== false);
}
}
function alert($host){
$headers = 'From: Set your from address here';
mail('my-email#my-domain.com', 'Website Monitoring', $host.' is down' $headers);
}
$hostMap = array(
'www.my-domain.com' => 'content on site',
'www.my-domain2.com' => 'content on second site',
);
//if (!check($host, $find)) alert($host);
foreach ($hostMap as $host => $find){
if( !check( $host, $find ) ){
alert($host);
}
}
unset($host);
unset($find);
Apparently I wasn't clear in my question. I am looking for confirmation that fsocketopen cannot follow redirects or that it cannot go to a sub-page (url.com/subpage).
If this is the case, is CURL my best option and are there any examples I can look at?
When you get the data returned from feof(), you can parse out the redirect information from the headers and create connect to that, but that is kind of annoying and cURL does it on its own.
You should just be able to use
$ch = curl_init($host);
curl_setopt_array($ch, array(
CURLOPT_RETUNTRANSFER => true
, CURLOPT_FOLLOWLOCATION => true
, CURLOPT_HEADER => true
));
$str = curl_exec($ch);
cURL follows redirects by default using the Location: header.

How do I make a POST request over HTTPS in PHP?

I trying to work with the YouTube API and its ClientLogin. And that means that I need to make a POST request to their servers.
The URL to which I need to make the request to https://www.google.com/accounts/ClientLogin. The variables I need to send are Email, Passwd, source and service. So far, so good.
I found this neat function to make POST calls (see below), but it does not use HTTPS, which I think I must use. It all works but I think my POST request is being forwarded to HTTPS and therefore it does not give me the proper callback. When I try to var_dump, the returned data web page reloads and I end up at https://www.google.com/accounts/ClientLogin where I get proper data. But of course I need this data as an array or string.
So how do I make a POST request using HTTPS?
Se my code (which I found at Jonas’ Snippet Library) below:
function post_request($url, $data, $referer='') {
$data = http_build_query($data);
$url = parse_url($url);
$host = $url['host'];
$path = $url['path'];
$fp = fsockopen($host, 80, $errno, $errstr, 30);
if ($fp){
fputs($fp, "POST $path HTTP/1.1\r\n");
fputs($fp, "Host: $host\r\n");
if ($referer != '')
fputs($fp, "Referer: $referer\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ". strlen($data) ."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $data);
$result = '';
while(!feof($fp)) {
$result .= fgets($fp, 128);
}
}
else {
return array(
'status' => 'err',
'error' => "$errstr ($errno)"
);
}
fclose($fp);
$result = explode("\r\n\r\n", $result, 2);
$header = isset($result[0]) ? $result[0] : '';
$content = isset($result[1]) ? $result[1] : '';
return array(
'status' => 'ok',
'header' => $header,
'content' => $content
);
}
This is the response headers:
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Date: Tue, 03 May 2011 12:15:20 GMT
Expires: Tue, 03 May 2011 12:15:20 GMT
Cache-Control: private, max-age=0
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Length: 728
Server: GSE
Connection: close
The content I get back is some kind of form autosubmitted, which I think is because I use HTTP instead of HTTPS:
function autoSubmit() {
document.forms["hiddenpost"].submit();
}
Processing...
So, how do I do a HTTPS POST request?
As octopusgrabbus kindly pointed out, I need to use port 443 instead of 80. So I changed this, but now I get nothing back.
var_dump from function return:
array(3) {
["status"]=>
string(2) "ok"
["header"]=>
string(0) ""
["content"]=>
string(0) ""
}
I get no header and no content back. What is wrong?
I think you cannot talk directly HTTPS, as it is HTTP encrypted with the public certificate of the server you are connecting to. Maybe you can use some of the ssl functions in php. But, this will take you some time and frankly, there are easier things.
Just take a look at cURL (client URL), that has support for GET and POST requests, and also connecting to https servers.
You are opening your socket at port 80. The SSL port is 443.
If this is SSL, there is an official computer name tied to the secure cert that's present on that web server. You might need to connect using that official name.
When you open the socket, changing the port to 443 and the prepending the host with ssl:// should work. (I just had this issue with paypal and some third party code). This assumes you don't have a protocol in your host already.
So
$fp = fsockopen('ssl://' . $host, 443, $errno, $errstr, 30);
As Carlos pointed out cUrl is good for this sort of thing. But there's no need to completely change what you're using in this case, particularly when it's a single line change.

Categories