php stream_context_create confusion - php

I know that this feature in php creates and returns a stream context with any options supplied in options preset. I also know that I can use it to do what I want which is to pass my username and password credentials...But I still don't quite get how to use this feature and what it exactly does the complicated words in the description are really confusing me....I have the code from the example but I don't know how I can use this feature to pass credentials to www.confluence.com (only I can access it since its on a apache server). Can someone please explain or give example of how I can use this to pass the credentials?
EDIT: Here is the overal summary, pretty short so dunno if you call it a summary....I am assigned an app to make.....there is about 10 different ways to do this. due to the limitations they have given me, I can only work with 1 way that I found...I am very frustrated because there is a much easier way to do this using google calendar but they refuse due to security reasons so I am stuck to confluence calendar.....In addition to that, to make this harder, confluence is hosted by external company and so I cannot even use get_contents to directly access the confluence calendar because it asks for login credentials....I am not a pro at this and one after another obstacles keep popping up to make my life harder and this is just bs...Ive spent hours and hours for the past 3 weeks finding solutions only to have it rejected...Ive finally got this get_contents thingy working but now login credentials is a pain in the butt and I have never dealt with this so I am trying my best but I have ABSOLUTELY NO IDEA what stream_context_create does OR how to even use it to pass my credentials...Confluence the site I am trying to access I can manually login using my logins but the code cannot....confluence is on an apache server so other people cannot access it....and I cannot share my login info as that is company's security issue...I am sorry if i made no sense but I am very frustrated and can find no solution and my mind is half dead from coding and reading
Believe me I have done much searching and googling....But Ive finally reached the point where I am blank stuck...
<?php
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en\r\n" .
"Cookie: foo=bar\r\n"
)
);
$context = stream_context_create($opts);
/* Sends an http request to www.example.com
with additional headers shown above */
$fp = fopen('http://www.example.com', 'r', false, $context);
fpassthru($fp);
fclose($fp);
?>
I found some additional code here similar to what I am doing but not quite sure what to do with this or how to modify it..
$data = array('account'=>'javier',
'password'=>'12345',
'submit'=>'SUBMIT');
$content = file_get_contents('http://localhost/misc/login.php', false, stream_context_create( array('http' => array('method' => 'POST', 'content' => http_build_query($data) ) ) ) );
$sFind = 'Logged in';
$search = strpos($content, $sFind);
echo $content;
if($search === false){
echo 'Invalid Account';
}
else {
echo 'Valid Account';
}
Another Idea I have is to use JavaScript to do the login...I dont know which is better but I am not allowed to download any libraries or such so suggestions are nice.

You are using the 'GET' method, it is uncommon for login information to be passed like this.
Are you sure the page you are requesting doesn't use POST?
Also personally when retrieving webpages, especially when sending POST or GET variables I prefer to use cURL.

Related

API token authentication issues in php

First of all I want to say that I'm not a native english (french) so that's why this could bring some mistakes sometimes.
So my problem is that I'm trying to use the API of a website, which documentation can be found at documentation
The problem is for requests which need authentication, every thing is fine for public requests.
So I tried the first request which is according to the website 'retrieve account balances' which is a signed get method (using a hmac256 payload).
Thing are getting harder since the documentation is saying that the payload has to be either recvWindow=5000×tamp=1540203005798 (with the weird cross before tamp) even if I think this is more a display problem or has we can find in the documentation at another line : recvWindow=5000&timestamp=my timestamp.
So this is the first problem because I don't know the which one to use in the payload. (but I've tried with both and it didn't work so ...).
Then I wrote a quick php script to retrieve my informations :
<?php
include('pwd.php');
$time = time()*1000;
$sign = hash_hmac('sha256', 'recvWindow=5000&timestamp='.$time, $private);
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=> array("Authorization" => $public,
"Signature" => $sign
)
));
$context = stream_context_create($opts);
$fp = file_get_contents('https://trade.coss.io/c/api/v1/account/balances?
recvWindow=5000&timestamp='.$time, false, $context);
echo $fp;
?>
The first include juste includes my public key and my private key.
I run out of idea to find what is the problem with this script, because I tried with every payload with the cross without the cross with my timestamp with fixed timestamp but nothing work, I just get 500 error.
Any kind of help would be great.
I found the answer to my problem it came from the header which had a syntax mistake, instead of what I wrote the proper way is :
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=> array("Authorization: ".$public,
"Signature: ".$sign
)
));

Google Play scraper

I'm trying to develop a Play Store reviews scraper in PHP and I need to make a POST request to this URL https://play.google.com/store/getreviews, and I saw the parameter post with firebug.
I am using Goutte library and here is my code:
require_once 'goutte.phar';
use Goutte\Client;
$client = new Client();
$params = Array(
"id" => "com.trello",
"pageNum" => 2 ,
"reviewSortOrder" => 2 ,
"reviewType" => 0,
"xhr" => 1
);
$crawler = $client->request('POST' , 'https://play.google.com/store/getreviews', $params);
The problem is that the request returns nothing. Is there anyone who already faced this problem and solved it?
I don't think this is possible. Google Play changed their review interface last year. They now have a "token" parameter which is missing here. I have worked before to try and work out what seeds this (see Google play review scraping changes) but I can't figure it out. After a number of attempts to hit that webservice with an incorrect request (presumably without the token) Google Play starts blocking your IP, that's why you'll be getting nothing back after a while (and won't be able to open Google Play in your browser either). If you find a solution, let me know!
This URL works for me, with the form-post data in your example.
https://play.google.com/store/getreviews?authuser=0

Posting a like via app on facebook only returns true and does nothing

I was trying to get the feeds of friends' fan pages with a cURL and to post a like via app.
The cURL GET works fine, but when it comes to liking the object (that has for sure likes enabled because it's facebook), all I get is a boolean (and no action).
I had seen on SO that you post a like with
($access_token, "https://graph.facebook.com/$post_id/likes", 'POST')
However, it is not working (it says either that the app has no permissions to do that, or that I need a valid url).
I have tried all possible solutions but nothing seems to work. The profile is mine, the access token too, and I gave publish_stream permissions to my own app.
After having given a try to the SDK PHP Likbrary, I tried a direct cURL post, with the following code:
function likeit($url){
//open connection
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, $url);
curl_exec($ch);
curl_close($ch);
}
The execution i a puzzle. When it does not return an OAuth Exception it returns boolean and stops there (there is no way for me to "like" the post I want to like). The last attempt (but I've tried them all, even the whole url in some tests) is
foreach ($feeds->data as $feed_data)
$message = $feed_data->message;
$title = $feed_data->name;
$link = $feed_data->link;
$id = $feed_data->id;
$myaccesstoken = "longlastingaccesstokenstring";
$post=likeit($myaccesstoken, "https://graph.facebook.com/$post_id/likes", 'POST');
Does anybody have a suggestion on how to do this? It seems trivial and yet there is no way for me to accomplish it. Thank you so much in advance!
I've found a solution, and thus am posting it here for future reference (hoping it is helpful for anybody with the same problem):
the only problem was that after the new permissions with facebook I needed to re-authorize my app.
After that, it is possible to post a like with the SDK facebook library, normally:
$facebook->api("/$id/likes", 'post', array(
'access_token' => $myaccesstoken));
No need to use cURL directly. Hope this helps someone with the same question.

Best way to implement Single-Sign-On with all major providers?

I already did a lot of research on this topic and have implemented a lot of solutions myself.
Including OpenID, Facebook Connect (using the old Rest API and the new Graph OAuth 2.0 API), Sign in with twitter (which has been upgraded to fully qualified OpenID by now as far as I know), and so on...
But what I'm still missing is the perfect all in one solution.
During my research I stumbled about some interesting projects:
Janrain (formerly RPX) - a commercial solution
Gigya - a free but externally hosted solution with javascript and rest apis
AnyOpenID - a free solution for clients, commercial for websites
But I don't want to rely on an external provider and I would like a free solution as well, so I am not limited in implementation.
I have also seen developers implementing one service after another dutifully following the providers instructions and setting up models and database tables for everything.
Of course this will work but it is a shitload of work and always needs development and changes in your application etc.
What I am looking for is an abstraction layer that takes all the services out there to one standard that can be integrated in my website. Once a new service appears I only want to add one model that deals with the abstraction of that specific provider so I can seamlessly integrate it into my application.
Or better, find an already existing solution that I can just dowonload.
Ideally this abstraction service would be hosted independently from my application so it can be used for several applications and be upgraded independently.
The last of the 3 solutions above looks promising from the concept.
Everything is just ported to an synthetic OpenID, and the website jut has to implement OpenID.
After a while i found Django socialauth, a python based authentication system for the Django Webframework. But it looks like it operates as described above and i think this is the same login system that Stackoverflow uses (or at least some modified fork...).
I downloaded it and tried to set it up and to see whether it could be set up as a standalone solution but I had no luck, as I am not so into python either.
I would love a PHP based solution.
So after this long text my question precisely is:
How would you implement SSO, any better idea than porting everything and have OpenID as basis?
What are the pros and cons of that?
Do you know any already existing solutions? Preferrably open source.
I hope this question is not too subjective, thanks in advance.
Update:
I concluded that building a proxy / wrapper or what you might call it for Facebook, to port it to an OpenID so it becomes an OpenID endpoint / provider would be the best option.
So that exactly what i did.
Please see my answer below.
I added the bounty to get feedback/discussion on it. Maby my approach is not so good as i currently think it is!
As original author of this answer, I want to note that I regard it as
OUTDATED. Since most providers decided to exclusively implement Oauth instead of Openid. Newer Openid services will also likely use
openid connect, which is based on oauth. There are good libraries like for example: https://github.com/hybridauth/hybridauth
After the discussion of the already existing answer i sum up:
Almost every major provider is an openid provider / endpoint including Google, Yahoo, Aol.
Some of them requrie the user to specify the username to construct the openid endpoint.
Some of them (the ones mentioned above) do have discovery urls, where the user id is automatically returned so that the user only has to click. (i would be glad if someone could explain the technical background)
However the only pain in the ass is Facebook, because they have their Facebook connect where they use an adapted version of OAuth for authentication.
Now what I did for my project is to set up an openid provider that authenticates the user with the credentials of my facebook Application - so the user gets connected to my application - and returns a user id that looks like:
http://my-facebook-openid-proxy-subdomain.mydomain.com/?id=facebook-user-id
I also configured it to fetch email adress and name and return it as AX attributes.
So my website just has to implement opend id and i am fine :)
I build it upon the classes you can find here: http://gitorious.org/lightopenid
In my index.php file i just call it like this:
<?php
require 'LightOpenIDProvider.php';
require 'FacebookProvider.php';
$op = new FacebookProvider;
$op->appid = 148906418456860; // your facebook app id
$op->secret = 'mysecret'; // your facebook app secret
$op->baseurl = 'http://fbopenid.2xfun.com'; // needs to be allowed by facebook
$op->server();
?>
and the source code of FacebookProvider.php follows:
<?php
class FacebookProvider extends LightOpenIDProvider
{
public $appid = "";
public $appsecret = "";
public $baseurl = "";
// i have really no idea what this is for. just copied it from the example.
public $select_id = true;
function __construct() {
$this->baseurl = rtrim($this->baseurl,'/'); // no trailing slash as it will be concatenated with
// request uri wich has leading slash
parent::__construct();
# If we use select_id, we must disable it for identity pages,
# so that an RP can discover it and get proper data (i.e. without select_id)
if(isset($_GET['id'])) {
// i have really no idea what happens here. works with or without! just copied it from the example.
$this->select_id = false;
}
}
function setup($identity, $realm, $assoc_handle, $attributes)
{
// here we should check the requested attributes and adjust the scope param accordingly
// for now i just hardcoded email
$attributes = base64_encode(serialize($attributes));
$url = "https://graph.facebook.com/oauth/authorize?client_id=".$this->appid."&redirect_uri=";
$redirecturl = urlencode($this->baseurl.$_SERVER['REQUEST_URI'].'&attributes='.$attributes);
$url .= $redirecturl;
$url .= "&display=popup";
$url .= "&scope=email";
header("Location: $url");
exit();
}
function checkid($realm, &$attributes)
{
// try authenticating
$code = isset($_GET["code"]) ? $_GET["code"] : false;
if(!$code) {
// user has not authenticated yet, lets return false so setup redirects him to facebook
return false;
}
// we have the code parameter set so it looks like the user authenticated
$url = "https://graph.facebook.com/oauth/access_token?client_id=148906418456860&redirect_uri=";
$redirecturl = ($this->baseurl.$_SERVER['REQUEST_URI']);
$redirecturl = strstr($redirecturl, '&code', true);
$redirecturl = urlencode($redirecturl);
$url .= $redirecturl;
$url .= "&client_secret=".$this->secret;
$url .= "&code=".$code;
$data = $this->get_data($url);
parse_str($data,$data);
$token = $data['access_token'];
$data = $this->get_data('https://graph.facebook.com/me?access_token='.urlencode($token));
$data = json_decode($data);
$id = $data->id;
$email = $data->email;
$attribute_map = array(
'namePerson/friendly' => 'name', // we should parse the facebook link to get the nickname
'contact/email' => 'email',
);
if($id > 0) {
$requested_attributes = unserialize(base64_decode($_GET["attributes"]));
// lets be nice and return everything we can
$requested_attributes = array_merge($requested_attributes['required'],$requested_attributes['optional']);
$attributes = array();
foreach($requested_attributes as $requsted_attribute) {
if(!isset($data->{$attribute_map[$requsted_attribute]})) {
continue; // unknown attribute
}
$attributes[$requsted_attribute] = $data->{$attribute_map[$requsted_attribute]};
}
// yeah authenticated!
return $this->serverLocation . '?id=' . $id ;
}
die('login failed'); // die so we dont retry bouncing back to facebook
return false;
}
function get_data($url) {
$ch = curl_init();
$timeout = 5;
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
}
Its just a first working version (quick and dirty)
Some dynamic stuff is hardcoded to my needs.
It should show how and that it can be done.
I am happy if someone picks up and improves it or re writes it or whatever :)
Well i consider this question answered
but I add a bounty just to get discussion. I would like to know what you think of my solution.
I will award the bounty to the best answer/comment beside this one.
OpenID is going to be your best bet for this application. It is supported by many, providers:
Google
Yahoo
MyOpenID
AOL
The Only problem is that twitter has not implemented OpenID yet. This is probably due to the fact that they are a proprietery based company, so they wanted their 'own' solution.
To solve that solution, you might write a wrapper class to provide compatibility with OpenID, but the chance is that even if your users don't have a twitter account, they might have a Facebook, Google, or Yahoo account.
Facebook Supports oauth, so you will have to port oauth to OpenID
Some PHP libraries for OpenID can be found here.
Now, some questions have been raised about facebook being an oauth provider.
Their oauth URL is "https://graph.facebook.com/oauth/authorize"
If you still do not belive me, then you can look at this javascript file, where I got that URL. If you don't believe that javascript file, then notice that it is hosted by stackexchange, the provider of this site. Now you must beleive that.
Fast forward two years and the answer of "OpenID is the answer" appears to be falling by the wayside by a number of the big providers. Most of the major third-party integration sites seem to have moved onto some flavor of OAuth (usually OAuth2). Also, if you don't mind NOT using OpenID/OAuth, there is a now complete SSO solution written in PHP (Disclaimer and full disclosure: This product is developed and maintained by myself under the CubicleSoft banner):
Single Sign-On Server/Client
Which didn't exist when this question was originally asked. It has a liberal license (MIT or LGPL) and meets your requirement of being an abstraction layer. The project tends to be focused toward enterprise sign ins but has some social media sign ins in the mix too (Google and Facebook).
You might also want to look at HybridAuth, which is only focused on social media sign ins but is more of a library than a prebuilt solution that you can throw onto a server and be done with it. So there is a bit more work involved with setting it up. It really depends on what you are after.
If you are happy with your OpenID solution, then great, but there are more options today than there were two years ago and people are still finding this thread.

Why can't I update our Twitter status?

I've spent the last three hours trying to get a simple Twitter status update to work using Zend_Service_Twitter and Zend_Oauth_Token_Access. Infuriatingly, I keep getting the following response:
object(Zend_Rest_Client_Result)#34 (2) {
["_sxml:protected"]=>
object(SimpleXMLElement)#39 (2) {
["request"]=>
string(33) "/1/account/verify_credentials.xml"
["error"]=>
string(20) "Invalid / used nonce"
}
["_errstr:protected"]=>
NULL
}
Here is the code I have tried:
$token = new Zend_Oauth_Token_Access();
$token->setToken('my token');
$token->setTokenSecret('my token secret');
$params = array('accessToken' => $token,
'consumerKey' => 'my key',
'consumerSecret' => 'my secret'
);
$twitter = new Zend_Service_Twitter($params);
$response = $twitter->statusUpdate('simpletest');
What on Earth is a 'nonce'? If I mess up the token/token secret the error message in the response changes accordingly. However, with correct credentials I keep getting the above noncence (pun intended). Also, I have tried several alternatives such as the ones in this previous post on SO.
Any help would be appreciated!
Update:
In case it helps, or makes things easier, all I am trying to do is update the status of a single Twitter account, which is the application's twitter account. As I commented below #David Caunt's answer, whenever an 'item' gets posted to our site, the site's Twitter status will update to a brief description of the item as well as a link. That's all! This used to work, before oAuth became compulsory to make API calls (all that was needed was to instantiate a Zend_Service_Twitter and pass in our credentials).
Consulting the reference manual, I believe your error is in creating the Zend_Service_Twitter object.
$twitter = new Zend_Service_Twitter(array(
'username' => 'johndoe',
'accessToken' => $token
));
$response = $twitter->status->update('My Great Tweet');
You do not need to pass in the key and secret again, as they are contained in the access token used to sign the request.
See also my comment above explaining the nonce.
UPDATE:
I've tried the code in a minimal environment and you're right, it simply doesn't work.
You can see all of my code in a GitHub gist. It's deliberately minimal, avoiding MVC and other complications.
You may take comfort in the fact that a Zend_Http_Client returned from the Access Token does work.
Twitter servers were reporting a problem with my nonces, when the error
was in the signature.
My OAuth code was working for most
requests, but when trying to post new
statuses I was getting "Invalid / used
nonce" as a response.
After much debugging, I found out I
was failing to encode spaces as %20
and instead was sending them as +.
After using the correct encoding, it
worked flawlessly.
Twitter servers should have reported a
problem with the signature, not the
nonce.
I don't really expect you guys to
waste any time fixing this (but it
would be nice)... I just want to leave
this note here so next time someone
comes googling for "invalid / used
nonce" they know they have to look at
their encodings too.
From http://code.google.com/p/twitter-api/issues/detail?id=1059
(other solution in comments)

Categories