I'm using the Zend framework and the openid selector from http://code.google.com/p/openid-selector/ - however I find I can't login using sites like Google and Yahoo as they use direct identity based login system whereby one is just redirected to a url as opposed to entering a unique url of their own for authentication.
I've checked out many options and hacks but none of them seem to work. How can i get this to work here btw - how is it implemented at stack overflow? I could really use all the help here guys..
Edit
Well the issue here is that from what I have noticed is that the Zend OpenID class doesn't support OpenID 2.0 the thing is that a typical open ID providor gives you a unique url such as your-name.openid-providor.com or openid-providor.com/your-name and the Zend OpenId class just parses through that url and then redirects you to the providor website where upon authentication you are redirected back.
In the case of Yahoo and google - you don't enter a unique url instead you are redirected to the providors login site and upon login and authentication you are redirected back - so basically whats happeining is that the zend_openID object when it parses to tell who the providor is it fails to tell from the general url itself. Like when you click on teh Google link it redirects you to https://www.google.com/accounts/o8/id
Its more an issue with the zend openid object here and there isn't any help on zend related forums - so I was wondering if someone had already hacked or had an alteration I could make to the class to accomplish this. Sorry if I'm missing something but I'm kinda new to this and programming with open ID and have just started to get my feet wet.
Thanks for the follow up - I did check into RPX a while back and they do have a php class but I wasnt able to check it out plus I really just want to for now get the code selector used as on stackoverflow to work with Yahoo and Google authentication. There has to be some kind of way to tweak the parsing which the Zend OpenID class uses as it runs a series of regular expression checks to make a discovery.
Little late to the game but I was able to get this working with some hacks I found around the interwebs.
First. Yahoo. To get Yahoo working all I had to do was change the JavaScript to use me.yahoo.com instead of just yahoo.com and it worked perfectly with the version of the Zend Framework I'm using. Unfortunately Google still wasn't, so some hacking was in order.
All of these changes go in Zend/OpenId/Consumer.php
First, in the _discovery method add the following on the series of preg_match checks that starts at around line 740.
} else if (preg_match('/<URI>([^<]+)<\/URI>/i', $response, $r)) {
$version = 2.0;
$server = $r[1];
I added this right before the return false; statement that's in the else {} block.
Second, in the _checkId method you'll need to add 3 new blocks (I haven't dug around enough to know what causes each of these three cases to be called, so I covered all to be on the safe side.
Inside the $version <= 2.0 block, you'll find an if/else if/else block. In the first if statement ($this->_session !== null) add this to the end:
if ($server == 'https://www.google.com/accounts/o8/ud') {
$this->_session->identity = 'http://specs.openid.net/auth/2.0/identifier_select';
$this->_session->claimed_id = 'http://specs.openid.net/auth/2.0/identifier_select';
}
In the else if (defined('SID') block add this to the end:
if ($server == 'https://www.google.com/accounts/o8/ud') {
$_SESSION['zend_openid']['identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
$_SESSION['zend_openid']['claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
}
And then after the else block (so outside the if/else if/else block all together, but still inside the $version <= 2.0 block) add this:
if ($server == 'https://www.google.com/accounts/o8/ud') {
$params['openid.identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
$params['openid.claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
}
Link to the bug in Zend Framework Issue Tracker
I need to use Google's OpenID stuff, and I tried Steven's code and couldn't get it to work as-is. I've made some modifications.
The _discovery change method is still the same:
Zend/OpenId/Consumer.php, line 765, add:
} else if (preg_match('/<URI>([^<]+)<\/URI>/i', $response, $r)) {
$version = 2.0;
$server = $r[1];
The rest is different, though:
Zend/OpenId/Consumer.php, line 859 (after making the above change), add:
if (stristr($server, 'https://www.google.com/') !== false) {
$id = 'http://specs.openid.net/auth/2.0/identifier_select';
$claimedId = 'http://specs.openid.net/auth/2.0/identifier_select';
}
This is right before:
$params['openid.identity'] = $id;
$params['openid.claimed_id'] = $claimedId;
And to get it to return the ID, once authorized:
Zend/Auth/Adapter/OpenId.php, line 278:
if(isset($_REQUEST['openid_identity']))
{
$this->_id = $_REQUEST['openid_identity'];
$id = $this->_id;
}
This is right before:
return new Zend_Auth_Result(
Zend_Auth_Result::SUCCESS,
$id,
array("Authentication successful"));
Note that I have not thoroughly tested this code. The code below is even more shakey.
I have spent more time and I've gotten it to work with my Google Apps domain with the following changes, in addition to the above:
Zend/OpenId/Consumer.php, line 734
$discovery_url = $id;
if(strpos($discovery_url, '/', strpos($discovery_url, '//')+2) !== false) {
$discovery_url = substr($discovery_url, 0, strpos($discovery_url, '/', strpos($discovery_url, '//')+2));
}
$discovery_url .= '/.well-known/host-meta';
$response = $this->_httpRequest($discovery_url, 'GET', array(), $status);
if ($status === 200 && is_string($response)) {
if (preg_match('/Link: <([^><]+)>/i', $response, $r)) {
$id = $r[1];
}
}
This is right after:
/* TODO: OpenID 2.0 (7.3) XRI and Yadis discovery */
I believe that was the only change I had to make. I'm pretty sure there's supposed to be some checking involved with the above for security reasons, but I haven't looked far enough into it to see what they would be.
Going over all the advice provided - I've decided to ditch using the zend_openid class [ sorry about that zend ] and instead I've switched to using JanRains OpenID library. Its taken a few hours to get it up and running with my project but atleast its working like a breeze. Had to make a lot of hacking and a bit of code spill over to get it working but its worth it.
I couldn't use any of Zend adapters with Zend-Auth to settle this new code library in as the library did the authentication on its own. SO I hacked and made a generic adapter that just returned a filled zend_result set to the Auth object thus I authenticate using my library and merely store the result in the Auth object pulling a bit of a fast one one the Zend-Auth object rather than have to rewrite my code again.
The library is available at http://openidenabled.com/php-openid/
Thanks for all the help guys.
I'm dealing with similar issues. I'm planning on using RPX now with Zend Framework. Maybe I'll write an adapter. Just to let you know.
Info: 'RPS now' provides an all-in-one interface and UI for user registration with
facebook
Google
Yahoo
mySpaceID
Windows LiveID
OpenID
aol
I'm pretty sure that Yahoo only works with OpenID 2.0. If you want to support Yahoo users, you're going to have to upgrade to a library with 2.0 support. That's going to be a matter of more than tweaking some parsing.
Did you check out the manual -- Zend_OpenId_Consumer basics? Check out 38.2.2 on that page and let me know if this helps, because it should.
Specifically, I don't know if Google offers OpenID. I know that Yahoo worked because I've tried it a while back.
Thanks for the information. I started by using JanRain's library, but I have problems with getting Simple Registration to work: I have not succeeded in getting any data that way. And there is no documentation on using Attribute Exchange. :(
So, I found and was trying Zend/OpenId, but had the same problem as you: no Yahoo!, Google and who knows what else support. Reading this, it seems I'll have to get back to JanRain; RPX is not an option in my case as it's a third party service.
Related
Good afternoon friends!
I am a programmer and I'm a little time learning about the Unity and the game development universe. I came a doubt that I could not find the answer very well.
What is the best architecture or solution to work with a mobile multiplayer game using a restful webservice? It's possible? It is the best way to do something online multiplayer?
I've been studying a bit WWWForm class and tried to simulate sending data via JSON using JSONObject but without much success. I can not actually send a javascript object.
An example:
public void enviar(JSONObject json, Objeto obj)
{
string url = "http://myurl/unity.php";
WWWForm form = new WWWForm();
form.AddField("var1", "[{\"Nome\":\""+obj.name+"\"}]");
WWW www = new WWW(url, form);
StartCoroutine(WaitForRequest(www));
}
IEnumerator WaitForRequest(WWW www)
{
yield return www;
// check for errors
if(www.error == null)
{
Debug.Log("WWW Ok!: " + www.text);
} else {
Debug.Log("WWW Error: "+ www.error);
}
}
and my PHP file I have the following test:
$t = $_POST['var1'];
$novot = json_decode($t);
foreach ($novot as $novo){
$fp = fopen("bloco1.txt", "a");
$escreve = fwrite($fp, $novo);
fclose($fp);
}
All I can back is a stdClass, I can handle, but that to me is something very manual. There is no simple and correct way of working with webservices?
Are you asking how send more more rich / structured data back and forth? Yes, JSON would be an obvious choice.
REST API's are simple, client-server, stateless. etc. Typical web paradigm. There are some frameworks that can help with authentication and wrapping object-oriented code to expose it as a service. Many of these fall into the 'mirco framework' category. Slim for example. Zend Framework has some related classes too. Zend also has a standalone offering called pigility - not suggesting you purchase it but it could give you some ideas.
I'd search Git Hub for "rest server" or similar.
Also if you are not writing good OOP code you will continue to find things "very manual". The DRY (Don't Repeat Yourself) principal is a good one to adhere to when starting out.
Best of luck. Been having fun myself with Unity3d of late teaching my little brother some coding skills.
Unity doesn't have the best built in WebServices, but developers have built a lot of plugins that are on the Asset Store. Additionally, I use the BestHTTP plugin, and absolutely love it! (although it does cost money).
I'm implementing the Rabo OmniKassa (which is a bit like Paypal) into a CakePHP application. I've read the Rabo manual, I tested it on an 'empty' project (without Security) and it all worked perfectly.
Now I'm implementing it in the actual application, and there are some problems with the data the Rabo OmniKassa sends back to my application -- which are caused by the Security component.
The Security component blocks the POST data the RaboKassa sends me, because it might be a threat to the application (external server inserting data etc...). It's returning a black hole.
When I just load the page without the redirect from the RaboKassa, it obviously loads, but since it has no POST data, it doesn't really do anything.
I've tried quite a few options I found on the internet like
$this->Components->disable('Security');
and
$this->Security->csrfCheck = false;
and
$this->Security->unlockedActions = array(
'kassareturn' // which is the function the RaboKassa has to return to
);
but none of them seem to work.
I can't seem to solve this problem, so is there anyone who's tried this or something similar before?
I can't alter the RaboKassa, so I have to receive the POST data...
I'm using CakePHP 2.1.3.
I'd recommend to always check the official docs first before you start trying stuff you find somewhere on the internet.
POST data validation needs to be disabled too
Besides the CSRF check there's also POST data validation. When receiving POST data from external sources you'll have to disable both checks.
$this->Security->csrfCheck = false;
$this->Security->validatePost = false;
And don't forget to make sure that you're disabling this only for your specific action!
public function beforeFilter() {
parent::beforeFilter();
if($this->request->params['action'] === 'kassareturn') {
$this->Security->csrfCheck = false;
$this->Security->validatePost = false;
}
}
See also
http://book.cakephp.org/.../core-libraries/components/security-component.html#usage
http://book.cakephp.org/.../security-component.html#SecurityComponent::$csrfCheck
http://book.cakephp.org/.../security-component.html#SecurityComponent::$validatePost
SecurityComponent::$unlockedActions as of CakePHP 2.3
I think you'll notice that using SecurityComponent::$unlockedActions will magically start working once you've updated your CakePHP installation to at least 2.3.x, as this feature is only available as of CakePHP 2.3
See also http://book.cakephp.org/...disabling-csrf-and-post-data-validation-for-specific-actions
Im looking to pull a status field from a web management interface of a UPS so that the data could be utilised in another web application I am writing. I was wondering if anyone would know a way to go about this as I cant seem to find the information I'm looking for through my web searches. Id also need it the value to refresh or re check. Example of UPS web interface below looking at the online field first off:
This is a very basic example, that I haven't tested (php isnt installed).
You need to look at the source of your control panel, and find out how to identify the elements that contain your desired information.
The code below (hopefully) searches for an element with an id server-status if that element exists it then checks its class attribute to determine the state of the server.
You do not have to use the dom stuff, you could also do it with regex or whatever. So long as you can accurately find the information you need.
You may also need to use cURL or something a little more advanced than file_get_contents() as you will likely require login credentials to view the page in question.
<?php
$html = file_get_contents("http://path.to/your/control.panel");
// you may need to use cURL or something more advanced if you need to provide login credentials
$dom = new DOMDocument;
$dom->loadHTML($html);
$test = $dom->getElementById('server-status');
if ($test == NULL) {
// unable to find element, somethings up!
} else {
if ($test->getAttribute('class') == "online") {
// status element has "online" class, server is online
} else {
// status element does not have "online" class, somethings up!
}
}
?>
Update
Had a quick look at a demo of that management software and it wont be quite as simple as my example as there don't appear to be any helpful element id or class names. Its still do-able though.
This is the code I am using, but it does return blank in most cases.
<?php
$xml=file_get_contents('http://twitter.com/users/show.xml?screen_name=MyTwitterUsernameBla');
if (preg_match('/followers_count>(.*)</',$xml,$match)!=0) {
$count = $match[1];
}
echo $count;
?>
I want to show Twitter followers count in simple way, no plugins..it's a website, and not a blog.
Thank you very much :)
If it works on your localhost but not on your public host, then chances are that Twitter is either blocking or throttling your public server's IP. Many shared hosts get blocked/throttled because there are multiple sites banging away at the Twitter API without authentication. Twitter views them as one app and throttles the IP as a whole.
To get around this, you're going to need to authenticate using oAuth. It's a pain in the ass, but it's a necessary step. Here are some resources that you might find to be handy:
http://blog.evandavey.com/2010/02/how-to-php-oauth-twitter.html
http://pear.php.net/package/HTTP_OAuth/redirected
Twitter offers you some credentials in the "Your Apps" section of the Twitter Developer website. Once you've registered your site as an app, click on My Access Token. That will give you a key/token that you can use to successfully authenticate.
Another thought is that Twitter is simply throttling your app. If this is the case, it's because you've got too much traffic and you're not caching the API results. Cache the results of the API for, say, an hour before fetching a new copy. Twitter will stop singling you out if you do this.
if(filemtime("cache.xml") < (int)$_SERVER["REQUEST_TIME"] - 3600) {
$data = file_get_contents("http://twitter.com/users/show.xml?screen_name=username");
file_put_contents("cache.xml", $data);
} else
$data = file_get_contents("cache.xml");
Think your reg. exp. is too greedy.. believe it will match everything up until the last '< /'
try something like a non-greedy match:
/followers_count>(.*?)</
or match everything except '<' :
/followers_count>([^<]*)</
Parsing the XML might be easier, and if you want to extract a lot from the xml, more "correct". But seems like overkill in your case.
It's much better (more reliable and easier to maintain) to use an XML parser than to try to fetch bits with regular expressions.
Simply:
$xml = new SimpleXMLElement('http://twitter.com/users/show.xml?screen_name=username', null, true);
echo $xml->followers_count;
Howdy. I've been tasked with making a Facebook game, but I'm new to Facebook development, so I'm just getting started. Apologies in advance if this is a no-brainer to people.
I'm having trouble following all the examples I see on sites, and I keep running into missing pages in the Facebook documentation when I am trying to read up. I think it's because there's a new version of the PHP Client Library for Facebook, and everything I'm finding is referring to the old client.
For instance, I see this code in a lot of examples:
require 'facebook.php';
$facebook = new Facebook( array( 'appId' => '(id)', 'secret' => '(secret)' ) );
$facebook_account = $facebook->require_login();
...but there's no "require_login()" in the client library provided in the facebook.php file.
From what I can tell, it looks like Facebook has very recently rolled out some new system for development, but I don't see any sample code anywhere to deal with it. The new library comes with an "example.php" file, but it appears to be only for adding "Log in with Facebook" functionality to other sites (what I'm assuming is what they mean by "Facebook Connect" sites), not for just running apps in a Canvas page on Facebook itself.
Specifically, what I need to do is let users visit an application page within Facebook, have it bring up the dialog box allowing them to authorize the app, have it show up in their "games" page, and then have it pass me the relevant info about the user so I can start creating the game. But I can't seem to find any tutorials or examples that show how to do this using the new library. Seems like this should be pretty straightforward, but I'm running into roadblocks.
Or am I missing something about the PHP client library? Should require_login() be working for me, and there's something broken with my implementation, such as having the wrong client library or something? I downloaded from GitHub yesterday, so I'm pretty sure I have the most recent version of the code I have, but perhaps I'm downloading the wrong "facebook.php" file...?
The following is a rewrite of the old require_login function. It exactly duplicates the old functionality.
function facebook_require_login($required_permissions = '')
{
global $facebook; // NOTE GLOBAL FACEBOOK OBJECT, MUST ALREADY BE INSTANTIATED
$user = $facebook->get_loggedin_user();
$has_permissions = true;
if ($required_permissions) {
$facebook->require_frame();
$permissions = array_map('trim', explode(',', $required_permissions));
foreach ($permissions as $permission) {
if (!in_array($permission, $facebook->ext_perms)) {
$has_permissions = false;
break;
}
}
}
if ($user && $has_permissions) return $user;
$facebook->redirect(
$facebook->get_login_url(Facebook::current_url(), $facebook->in_frame(),
$required_permissions));
}
phpfour solution is the only correct one - since it utilizes the new php-sdk library from github.
The best solution is to edit the new facebook.php and add a require_login() function (so all existing pages who rely on it can stay the same)
public function require_login(){
if ( !$this->getSession() ) {
$url = $this->getLoginUrl( array(
'canvas' => 1,
'fbconnect' => 0
));
echo "<script type='text/javascript'>top.location.href = '$url';</script>";
}
else
return $this->getUser();
}
The new php script on git hub is a wraper for facebooks api, graph I presume but I've seen code for fql too so who knows. The forums are currently down and IRC was dead when I went across. I have been looking for the same solution as your require authorisation to call ->api(\me). Since the script extends another class if I remember right, you could try using the reflection class/function to see what methods are available. Hopefully some solid documentation is on its way! Please let me know if you solve this. (Sorry for poor formatting I'm on my mobile)
Well, I have been able to find a solution to the problem of authorizing application using the new PHP SDK. You can check my blog post here.
In short, you will need to get an authenticated session and then you can call the functions to get the logged in user's ID. In this case, you will call the "/me" path from the Graph API.