Basic authentication with Apache - php

I have basic authentication enabled on an Apache server. The server is hosting an API that I implemented and I want to do is call this API from my PHP script. I got as far as figuring out how to create a header:
$user = 'my_name_api';
$pwd = 'xxxxxxxxx';
$auth_string = $user . ':' . $pwd;
$auth_b64 = base64_encode($auth_string);
$header = 'Authorization: Basic ' . $auth_b64;
How do I include the $header in my API calls? I am looking for something other than cURL, and I am NOT using any environments like zend, etc. (saw some example for Zend, etc., but I am not using any of those).

Have you tried fopen / file_get_contents?
Start here: http://php.net/manual/en/function.fopen.php
or here: http://www.php.net/manual/en/function.file-get-contents.php
and let me know how it goes...
airyt

If you don't need SSL or proxy support, you can use file_get_contents() with a stream context. The stream context can contain HTTP headers:
$opts = array
(
'http'=>array
(
'method' => "GET",
'header' => "Authorization: ..."
)
);
$context = stream_context_create($opts);
$file = file_get_contents('http://www.example.com', false, $context);
More on this here.

Related

Using file_get_contents with basic auth and SSL

I'm attempting a GET request using SSL and basic auth using the file_get_contents function:
$username = "XXXXXXXXXX";
$password = "XXXXXXXXXX";
$url = "https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api";
$context = stream_context_create(array("http" => array("header" => "Authorization: Basic " . base64_encode("$username:$password"))));
$data = file_get_contents($url, false, $context);
echo $data;
Here's the error message I get:
Warning: file_get_contents(https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api): failed to open stream: HTTP request failed! HTTP/1.0 500 Server Error...
I've already confirmed that openssl is enabled:
And we might as well get this out of the way up-front:
Why don't you just use cURL?
I could. But I also want to figure out why file_get_contents isn't working. I like the relative simplicity of file_get_contents. Call me crazy.
Curiosity is a good thing so it's cool to dig this problem without falling back to cURL before fixing this problem.
<?php
$username = "XXXXXXXXXX";
$password = "XXXXXXXXXX";
$url = "https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api";
$context = stream_context_create(array(
"http" => array(
"header" => "Authorization: Basic " . base64_encode("$username:$password"),
"protocol_version" => 1.1, //IMPORTANT IS HERE
)));
$data = file_get_contents($url, false, $context);
echo $data;
The fact is the server does not support HTTP/1.0. So you haven't any problem with SSL/TLS nor with your user agent. It is just the server that support HTTP from 1.1.
As said in the stream_context_create documentation the default protocol_version used in stream_context_create is 1.0. That's why you got an error 500.
EDIT : My bad, don't see this is not curl. Try with this
$username = "XXXXXXXXXX";
$password = "XXXXXXXXXX";
$url = "https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api";
$context = stream_context_create(array(
"http" => array("header" => "Authorization: Basic " . base64_encode("$username:$password")),
"ssl"=>array(
"verify_peer"=>false,
"verify_peer_name"=>false,
)));
$data = file_get_contents($url, false, $context);
echo $data;

fedora commons ingest object via REST error

I recently set up FEDORA for a project I am working on to catalogue various
media. I want to be able to consume files (datastreams) via the FEDORA REST api. I managed to create a digital object via curl with no issues at all. I also managed to add an html page as a datastream to the digital object mentioned above with no problems as well.
However, adding a digital object with other content types/file types fails and throws an internal server error 500. On checking the logs, the following error appears:
[http-bio-8080-exec-18] (DatastreamResource) Error with uploaded://47 : XML was not well-formed. Invalid byte 1 of 1-byte UTF-8 sequence
The following is my code snippet of how I am ingesting the files:
$url = "http://localhost:8080/fedora/objects/changeme:5/datastreams/NEWDS8?controlGroup=X&dsLabel=LAZLO";
$file = "namibia2015.pdf";
// Build cURL options
$userPassword = "fedoraAdmin:test123"; // username:password
$verifyPeer = false; // false for ignoring self signed certificates
$headers = array("Accept: text/xml", "Content-Type: " . mime_content_type($file));
$fileContents = file_get_contents($file);
$curlOptions = array(
CURLOPT_URL => $url,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_USERPWD => $userPassword,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_SSL_VERIFYPEER => $verifyPeer,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $fileContents
);
$curlHandle = curl_init();
$success = curl_setopt_array($curlHandle, $curlOptions);
throw new Exception(
sprintf(
"curl_setopt_array(...) failed. Error: %s. Info: %s",
curl_error($curlHandle),
print_r(curl_getinfo($curlHandle), true)
),
curl_errno($curlHandle)
);
}
$curlReturn = curl_exec($curlHandle);
$httpCode = curl_getinfo($curlHandle, CURLINFO_HTTP_CODE);
I came across this post How can I ingest an image into Fedora Commons using PHP? tried the suggested method but still no luck.
What am I doing wrong? What am I missing? Why is it possible to add an html file datastream to the digital object but it fails when I try to
add .jpeg, .pdf, .txt etc?
I finally fixed the error. The exception was being caused by the way I was structuring my URL parameters in my curl request. Using a URL with the following format:
$url = "http://localhost:8080/fedora/objects/changeme:5/datastreams/NEWDS8?controlGroup=X&dsLabel=LAZLO";
will throw the error. Instead, you have to build an http query of all the options you want attached to the POST request. I did that as follows:
$array = array();
$array['dsID'] = '5' ;
$array['controlGroup'] = 'M' ;
$array['altIDS'] = 'Other';
$array['versionable'] = true;
$array['dsLabel'] = 'The pic';
$array['logMessage'] = 'Example log message';
$link = "http://localhost:8080/fedora/objects/changeme:5/datastreams/newobject";
$params = http_build_query($array);
$url = $link.'?'.$params; //add the http query parameters to the url
Thereafter, I made my curl request as before and it will successfully create a data stream attached to the digital object.
Hope this will help someone in the future.

PHP api call header variable retrieval

I'm working with an api that returns a number of useful variables within the header response, for example with...
Pragma → no-cache
Server → Apache
X-Pages → 1424
... I'd like to use the X-Pages variable to form some further logic. How do I retrieve this variable and use it within my php script?
My api currently call looks like this:
$username = "XXXXXXXX";
$password = "XXXXXXXX";
$remote_url = 'XXXXXXXX';
$headers = array();
$headers[] = "Authorization: Basic " . base64_encode("$username:$password");
$opts = array(
'http'=>array(
'method'=>"GET",
'header' => $headers
)
);
$context = stream_context_create($opts);
$file1 = file_get_contents($remote_url, false, $context);
Thanks,
Matt
You can find the response headers in $http_response_header after making the call to file_get_contents - it'll be automatically populated in the local scope.

How to use file_get_contents() with a Wordpress user's cookies

I need to send a file_get_contents() to an API endpoint with the client's cookies that are set by Wordpress to show that the user is logged into the wordpress site. I know I need to use stream_context_create() roughly as follows:
$cookies = ??? //THIS IS THE QUESTION (see answer below)!
// Create a stream
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en\r\n" .
"Cookie: {$cookies}\r\n"
)
);
$context = stream_context_create($opts);
// Open the file using the HTTP headers set above
$file = file_get_contents('http://example.dev/api/autho/', false, $context);
As you can see from the comment on the first line, I'm stuck on how to send this request so that the correct cookies are sent. I know the correct cookies are sent because I can print out $_COOKIES and see them there. But if I try to insert that same array into the headers, it doesn't work.
Thanks in advance!
ps: I've read that I should use cURL for this, but I'm not sure why and I don't know how to use it... but I'm open to the idea.
UPDATE:
I got this to work. It's basically the same thing I was doing, with another important cookie . See my answer below.
The cookies should be in the following format: Cookie: cookieone=value; cookietwo=value, that is, separated by a semicolon and space with no trailing semicolon. Loop through your cookie array, output that format, and send it.
It turns out I was doing it correctly, but I didn't know that WP needs a second cookie sent in order for the request to work properly.
Here's the code that works for me:
$cookies = $_COOKIE;
$name;
$value;
foreach ($_COOKIE as $key => $cookie ) {
if ( strpos( $key, 'wordpress_logged_in') !== FALSE ) {
$name = $key;
$value = $cookie;
}
}
// Create a stream
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en\r\n" .
"Cookie: {$key}={$cookie}; wordpress_test_cookie=WP Cookie check \r\n"
)
);
$context = stream_context_create($opts);
// Open the file using the HTTP headers set above
$file = file_get_contents('http://mydomain.dev/api/autho/', false, $context);
var_dump($file);
It's basically the same thing as you see in my question, but with an important addition: wordpress_test_cookie=WP Cookie check. I haven't seen it documented anywhere, but WP needs this cookie as well as the actual wordpress_logged_in cookie in order for the call to happen as an logged in user.
Okay, as you mentioned you should use cURL (partially it's my personal opinion, I have some bad experiences with server configuration that prohibited URL file wrappers).
A quote from manual:
A URL can be used as a filename with this function if the fopen
wrappers have been enabled.
So it may happen to you that the code just won't work. On the other hand cURL is designed for fetching of remote content and provides lot of control on what's going on, how to fetch data and so on.
When you look at curl_setopt you can see how many and how detailed things you can set (but you don't have to, it's just optional when you need it).
Here's the first link after googling php curl set cookies, that's great place for you to start... Basic examples are totally trivial.
$cookies = $_COOKIE;
foreach ($_COOKIE as $key => $cookie ) {
if ( strpos( $key, 'wordpress_logged_in') !== FALSE ) {
$name = $key;
$value = $cookie;
break;
}
}
// Create a stream
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en\r\n" .
"Cookie: {$key}={$cookie}; wordpress_test_cookie=WP Cookie check\r\n"
)
);
$context = stream_context_create($opts);
// Open the file using the HTTP headers set above
$file = file_get_contents('http://mydomain.dev/api/autho/', false, $context);
var_dump($file);
I didn't have points to make a comment, so I readded the code from emersonthis. In order for this to work under my configuration (php 7.0.3, wordpress 4.4.2) I HAD TO remove the last space after the "WP Cookie check" string.

file_get_contents behind a proxy?

At work we have to use a proxy to basically access port 80 for example, we have our own custom logins for each user.
My temporary workaround is using curl to basically login as myself through a proxy and access the external data I need.
Is there some sort of advanced php setting I can set so that internally whenever it tries to invoke something like file_get_contents() it always goes through a proxy? I'm on Windows ATM so it'd be a pain to recompile if that's the only way.
The reason my workaround is temporary is because I need a solution that's generic and works for multiple users instead of using one user's credentials ( Ive considered requesting a separate user account solely to do this but passwords change often and this technique needs to be deployed throughout a dozen or more sites ). I don't want to hard-code credentials basically to use the curl workaround.
To use file_get_contents() over/through a proxy that doesn't require authentication, something like this should do :
(I'm not able to test this one : my proxy requires an authentication)
$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;
Of course, replacing the IP and port of my proxy by those which are OK for yours ;-)
If you're getting that kind of error :
Warning: file_get_contents(http://www.google.com) [function.file-get-contents]: failed to open stream: HTTP request failed! HTTP/1.0 407 Proxy Authentication Required
It means your proxy requires an authentication.
If the proxy requires an authentication, you'll have to add a couple of lines, like this :
$auth = base64_encode('LOGIN:PASSWORD');
$aContext = array(
'http' => array(
'proxy' => 'tcp://192.168.0.2:3128',
'request_fulluri' => true,
'header' => "Proxy-Authorization: Basic $auth",
),
);
$cxContext = stream_context_create($aContext);
$sFile = file_get_contents("http://www.google.com", False, $cxContext);
echo $sFile;
Same thing about IP and port, and, this time, also LOGIN and PASSWORD ;-) Check out all valid http options.
Now, you are passing an Proxy-Authorization header to the proxy, containing your login and password.
And... The page should be displayed ;-)
Use stream_context_set_default function. It is much easier to use as you can directly use file_get_contents or similar functions without passing any additional parameters
This blog post explains how to use it. Here is the code from that page.
<?php
// Edit the four values below
$PROXY_HOST = "proxy.example.com"; // Proxy server address
$PROXY_PORT = "1234"; // Proxy server port
$PROXY_USER = "LOGIN"; // Username
$PROXY_PASS = "PASSWORD"; // Password
// Username and Password are required only if your proxy server needs basic authentication
$auth = base64_encode("$PROXY_USER:$PROXY_PASS");
stream_context_set_default(
array(
'http' => array(
'proxy' => "tcp://$PROXY_HOST:$PROXY_PORT",
'request_fulluri' => true,
'header' => "Proxy-Authorization: Basic $auth"
// Remove the 'header' option if proxy authentication is not required
)
)
);
$url = "http://www.pirob.com/";
print_r( get_headers($url) );
echo file_get_contents($url);
?>
Depending on how the proxy login works stream_context_set_default might help you.
$context = stream_context_set_default(
array(
'http'=>array(
'header'=>'Authorization: Basic ' . base64_encode('username'.':'.'userpass')
)
)
);
$result = file_get_contents('http://..../...');
There's a similar post here: http://techpad.co.uk/content.php?sid=137 which explains how to do it.
function file_get_contents_proxy($url,$proxy){
// Create context stream
$context_array = array('http'=>array('proxy'=>$proxy,'request_fulluri'=>true));
$context = stream_context_create($context_array);
// Use context stream with file_get_contents
$data = file_get_contents($url,false,$context);
// Return data via proxy
return $data;
}

Categories