PHP OpenID geting nickname & email - php

For the OpenID authentication I'm using "PHP OpenID Library" (http://www.janrain.com/openid-enabled). How, with the help of this library, ask for additional information (nickname, email)?
I've got some problems with LightOpenID, when I ask email at yandex LightOpenID-> valid returns false(
class Ncw_OpenID extends LightOpenID
{
const OPENID_MODE_CANCEL = 'cancel';
public function __construct()
{
parent::__construct();
$this->required = array('namePerson/friendly', 'contact/email');
$this->optional = array('contact/email');
//$this->returnUrl = 'http://' . SITE_URI . '/users/login';
}
public function getAttributes() {
$attr = parent::getAttributes();
$newAttr = array();
foreach ($attr as $key => $value) {
if (isset(parent::$ax_to_sreg[$key])) $key = parent::$ax_to_sreg[$key];
$newAttr[$key] = $value;
}
return $newAttr;
}
}
class Users_IndexController extends Zend_Controller_Action
{
public function loginAction()
{
$openIDMode = $this->_request->getParam('openid_mode');
$openID = new Ncw_OpenID();
$form = new Users_Form_Login(array('action' => $this->view->url(array(), 'openIDLogin')));
if (null === $openIDMode) {
if ($this->_request->isPost() && $form->isValid($_POST)) {
$openID->identity = $form->getValue('openIDUri');
$this->_redirect($openID->authUrl());
exit();
}
$this->view->content = $form;
} elseif (Ncw_OpenID::OPENID_MODE_CANCEL == $openIDMode) {
$this->view->content = 'Cancel';
} else {
if ($openID->validate()) {
$this->view->content = 'Valid: ' . $openID->identity . ' = ' . var_export($openID->getAttributes(), true);
} else {
$this->view->content = 'Not Valid';
}
$this->view->content .= $form;
}
}
public function logoutAction()
{
// action body
}
}

Here is an incomplete example. It's incomplete in the sense that it's using only SREG, and not every provider supports it (for example, Google supports only AX).
As far as I know, php-openid doesn't offer a simple way to automatically detect what does the server support and accordingly use AX or SREG.
For more information, I'd look at the source code's comments or as the README suggests, generate documentation from them, using phpdoc.
However, if you can switch libraries, I'd recommend LightOpenID. It's easier to use and does most things automatically (contrary to php-openid).

Related

How to integrate msg91 php api with Prestasms or Prestashop?

<?php
error_reporting(E_ALL ^ E_NOTICE);ini_set('error_reporting', E_ALL ^ E_NOTICE);
define('IS_ADMIN_FLAG', false);
include_once(dirname(__FILE__).'/../../config/config.inc.php');
include_once(dirname(__FILE__).'/../../config/setting.inc.php');
include_once('includes/model/smsAdapter.php');
include_once('includes/model/sms.php');
include_once('includes/model/variables.php');
class ControllerSmsApi
{
public function __construct()
{
$this->index();
}
public function index()
{
die("DISABLED");
$to = $this->getVar("to");
$text = $this->getVar("text");
$unicode = $this->getVar("unicode");
$type = $this->getVar("type");
$transaction = $this->getVar("transaction");
if(isset($to) && strlen($to) > 4 && strlen($text) > 0)
{
$sms = new SmsModel(true, SmsModel::TYPE_SIMPLE, $type, ($transaction ? SmsModel::SMS_TRANSACTION : SmsModel::SMS_BULK));
$sms->number($to)->text($text)->unicode($unicode)->send();
if(!$sms->isError())
{
echo "SMSSTATUS:OK";
}
else
{
echo "SMSSTATUS:ERROR";
}
}
else
{
echo "SMSSTATUS:ERROR";
}
}
private function getVar($var)
{
if(filter_input(INPUT_POST, $var))
{
return filter_input(INPUT_POST, $var);
}
elseif(filter_input(INPUT_GET, $var))
{
return filter_input(INPUT_GET, $var);
}
else
{
return null;
}
}
}
new ControllerSmsApi();
?>
I have an ecommers website in which customer placed order and get all updation via email service ,but now i want to make it for sms service also for which i have sms api in msg91 for php. But unfortunately i am unable to integrate it with prestashop via prestasms or any other free module.
Actually making a Module should do the job and adding
various hooks might do the job, you can generate one with nearly all you will need here : https://validator.prestashop.com/
Based on your answer you will certainly need two hooks : actionOrderStatusUpdate and actionValidateOrder. You can also get an updated list here http://www.prestarocket.com/blog/prestashop-1-7-hook-list-liste-des-hooks/.
If you need example of a module well working, you can take a look at modules/dashactivity/ which one of the most compliant to Prestashops guidelines.
Your code might look like this in the end :
<?php
class Msg91SMS extends Module
{
public function __construct()
{
$this->name = 'msg91sms';
$this->tab = 'front_office';
$this->version = '1.0.1';
$this->author = 'YourName';
$this->displayName = $this->l('MSG91SMS');
$this->description = $this->l('Description');
// Hooks you need, setup on install so you might do it again
$this->hooks = array(
'actionValidateOrder',
'actionOrderStatusUpdate',
);
}
public function install() {
if (!parent::install()) {
return false;
} else {
if (isset($this->hooks) && !empty($this->hooks)) {
foreach ($this->hooks as $v) {
if (!$this->registerHook($v)) {
return false;
}
}
}
}
}
public function hookActionValidateOrder($params) {
$order = $params['order'];
// Do your magic here
}
public function hookActionOrderStatusUpdate($params) {
// Same as above, remember to check order state to see if it interests you some ways with $order->id_state and a switch / case
}
}

Load a PHP class multiple times

I've created a class which has multiple private an public functions and an construct function. It's an client to connect to the vCloud API. I want two objects loaded with different initiations of this class. They have to exist in parallel.
$vcloud1 = new vCloud(0, 'system');
$vcloud2 = new vCloud(211, 'org');
When I check the output of $vcloud1 it's loaded with info of $vcloud2. Is this correct, should this happen? Any idea how I can load a class multiple times and isolate both class loads?
This is part of my class, it holds the most important functions. Construct with user and org to login to. If info in the DB exists, then we authenticate with DB info, else we authenticate with system level credentials. So I would like to have two class loads, one with the user level login and one with system level login.
class vCloud {
private $client;
private $session_id;
private $sdk_ver = '7.0';
private $system_user = 'xxxxxxxxxxx';
private $system_password = 'xxxxxxxxxxxxxxxxx';
private $system_host = 'xxxxxxxxxxxxx';
private $org_user;
private $org_password;
private $org_host;
private $base_url;
public function __construct($customerId, $orgName) {
if ($this->vcloud_get_db_info($customerId)) {
$this->base_url = 'https://' . $this->org_host . '/api/';
$this->base_user = $this->org_user . "#" . $orgName;
$this->base_password = $this->org_password;
} else {
$this->base_url = 'https://' . $this->system_host . '/api/';
$this->base_user = $this->system_user;
$this->base_password = $this->system_password;
}
$response = \Httpful\Request::post($this->base_url . 'sessions')
->addHeaders([
'Accept' => 'application/*+xml;version=' . $this->sdk_ver
])
->authenticateWith($this->base_user, $this->base_password)
->send();
$this->client = Httpful\Request::init()
->addHeaders([
'Accept' => 'application/*+xml;version=' . $this->sdk_ver,
'x-vcloud-authorization' => $response->headers['x-vcloud-authorization']
]);
Httpful\Request::ini($this->client);
}
public function __destruct() {
$deleted = $this->vcloud_delete_session();
if (!$deleted) {
echo "vCloud API session could not be deleted. Contact administrator if you see this message.";
}
}
private function vcloud_delete_session() {
if (isset($this->client)) {
$response = $this->client::delete($this->base_url . 'session')->send();
return $response->code == 204;
} else {
return FALSE;
}
}
public function vcloud_get_db_info($customerId) {
global $db_handle;
$result = $db_handle->runQuery("SELECT * from vdc WHERE customer=" . $customerId);
if ($result) {
foreach ($result as $row) {
if ($row['org_host'] != "") {
$this->org_user = $row['org_user'];
$this->org_password = $row['org_password'];
$this->org_host = $row['org_host'];
return true;
} else {
return false;
}
}
} else {
return false;
}
}
public function vcloud_get_admin_orgs() {
$response = $this->client::get($this->base_url . 'query?type=organization&sortAsc=name&pageSize=100')->send();
return $response->body;
}
}
$vcloud1 = new vCloud('user1', 'system');
$vcloud2 = new vCloud('user2', 'org');
This is enough to make two instances which are not related.
I suppose your database is returning the same results.
How about providing a custom equals method to each object that retreives an instance of vCloud?
class vCloud {
//Other definitions
public function equals(vCloud $other){
//Return true if $other is same as this class (has same client_id etc etc)
}
}
So you just need to do as the code says:
$vcloud1 = new vCloud('user1', 'system');
$vcloud2 = new vCloud('user2', 'org');
if($vcloud1.equals($vclous2)){
echo "Entries are the same";
} else {
echo "Entries are NOT the same";
}
Also you may need to have various getter and setter methods into your class definitions. What is needed for you to do is to fill the equals method.

A cleaner way to go with my controller method

I am making an app that translates a word from one language to English and gets information about it (e.g. definition, use in a sentence, synonyms, sound representation)
What my function does:
Searches for the translation in the database. If it is found, we return it.
If it is not found we translate a word using google translate, or Yandex translate API.
If translation is found we download it's sound representation, save the translation to the database and add additional information from other API's
We return a json response with all of the information.
Now my controllers method is really big and I can't find a cleaner way to go about it.
Any help is appreciated.
public function store(Request $request)
{
$translated = $request->get('translated');
$translation = $this->translation->findBy('translated', $translated)->first();
if ($translation) {
return Response::json(['translation' => $this->translation->with(['examples', 'definitions', 'synonyms', 'images'])->find($translation->id)], ResponseCode::HTTP_CREATED);
}
$data = $request->all();
$data['translation'] = $this->translate($translated);
if ($translated == $data['translation']) {
Log::info('Translation not found: ' . $data['translation']);
return $this->translationNotFound();
}
$downloader = new Downloader(new GoogleSpeechDownloader());
$filename = $downloader->download($data['translation']);
if ($filename) $data['sound_name'] = $filename;
$translation = $this->translation->create($data);
$this->createDefinition($translation);
$this->createExample($translation);
$this->createSynonym($translation);
return Response::json(['translation' => $this->translation->with(['examples', 'definitions', 'synonyms', 'images'])->find($translation->id)], ResponseCode::HTTP_CREATED);
}
private function translationNotFound()
{
return Response::json(['error' => 'Vertimas nerastas.'], ResponseCode::HTTP_NOT_FOUND);
}
private function createDefinition($translation)
{
$definition = new Definition();
$definer = new Definer(new DictionaryApiDefiner());
try {
$definition->definition = $definer->getDefinition($translation->translation);
$definition->approved = true;
$translation->definitions()->save($definition);
} catch (\Exception $e) {
Log::alert('Definition for word ' . $translation->translation . ' not found.');
}
}
private function createExample($translation)
{
$example = new Example();
$exampler = new ExampleCreator(new YourDictionaryGouteParserExampler());
try {
$example->example = $exampler->getExample($translation->translation);
$example->approved = true;
$translation->examples()->save($example);
} catch (\Exception $e) {
Log::alert('Example for word ' . $translation->translation . ' not found.');
}
}
private function createSynonym($translation)
{
$creator = new SynonymCreator(new BigHugeLabsSynonymCreator());
foreach ($creator->getSynonyms($translation->translation) as $s) {
$synonym = new Synonym();
$synonym->synonym = $s;
$synonym->approved = true;
$translation->synonyms()->save($synonym);
}
}
private function translate($translated)
{
$translator = new Translator(new GoogleTranslator());
try {
return $translator->translate($translated);
} catch (\Exception $e) {
Log::critical($e->getMessage());
}
$translator = new Translator(new YandexTranslator());
return $translator->translate($translated);
}
If you want cleaner code, just make a class for this job. Two classes for this two API's and in the controller make the check for the word, if not exist in the database, check in the other two API's, just split every action to method in the new two classes that you will make.

jaxl return to function that it's called from

I have library for xmpp transactions used jaxl libraries:
class xmpp{
public function register_user($username, $password){
require_once 'JAXL/jaxl.php';
$this->client = new JAXL(array(
'jid' => 'localhost',
'log_level' => JAXL_ERROR
));
$this->username = $username;
$this->password = $password;
$this->client->require_xep(array(
'0077' // InBand Registration
));
$thisClassObject =& $this;
$this->client->add_cb('on_stream_features', function($stanza) use(&$thisClassObject) {
$thisClassObject->client->xeps['0077']->get_form('localhost');
return array($thisClassObject, 'wait_for_register_form');
});
$this->client->start();
return;
}
public function wait_for_register_response($event, $args) {
if($event == 'end_stream') {
return;
}
else if($event == 'stanza_cb') {
$stanza = $args[0];
if($stanza->name == 'iq') {
if($stanza->attrs['type'] == 'result') {
echo "registration successful".PHP_EOL."shutting down...".PHP_EOL;
$this->client->end_stream();
return 'logged_out';
}
else if($stanza->attrs['type'] == 'error') {
$error = $stanza->exists('error');
echo "registration failed with error code: ".$error->attrs['code']." and type: ".$error->attrs['type'].PHP_EOL;
echo "error text: ".$error->exists('text')->text.PHP_EOL;
echo "shutting down...".PHP_EOL;
$this->client->end_stream();
return "logged_out";
}
}
}
}
public function wait_for_register_form($event, $args) {
$stanza = $args[0];
$query = $stanza->exists('query', NS_INBAND_REGISTER);
if($query) {
$form = array();
$instructions = $query->exists('instructions');
if($instructions) {
echo $instructions->text.PHP_EOL;
}
$this->client->xeps['0077']->set_form($stanza->attrs['from'], array('username' => $this->username, 'password' => $this->password));
return array($this, "wait_for_register_response");
}
else {
$this->client->end_stream();
return "logged_out";
}
}
}
these code are same as register_user.php, but implemented in a class;
i use this class in my code in this way:
$xmppObj = new xmpp();
$xmppObj('user','password');
/*
some more code after this
/*
when it execute , create user successfully but it's print a message ('registration successful ...') and application exited and it doesn't execute "some code after this" after the class function, in the other word it doesn't follow the code...
What can I do for solve this problem, a person can help me that familiar with JAXL library.
Looks like you are pretty much using the same code as found inside examples/register_user.php. Once user registration is successful, script closes XMPPStream as evident from this section of the code:
if($stanza->attrs['type'] == 'result') {
echo "registration successful".PHP_EOL."shutting down...".PHP_EOL;
$this->client->end_stream();
return 'logged_out';
}
You MUST instead call $client->send_end_stream(); and not $client->end_stream();. This will make sure underlying XMPPStream makes proper FSM state transition. Also add a callback for on_disconnect event, inside this callback you can again try to connect back with newly registered XMPP account and it should just work fine.
Note: Kindly checkout latest code from the repository. I made some updates which will allow core JAXLLoop to be re-initialized. If you are interested in details, here is the commit log.

Why is this Zend Framework _redirect() call failing?

I am developing a Facebook app in Zend Framework. In startAction() I am getting the following error:
The URL http://apps.facebook.com/rails_across_europe/turn/move-trains-auto is not valid.
I have included the code for startAction() below. I have also included the code for moveTrainsAutoAction (these are all TurnController actions) I can't find anything wrong with my _redirect() in startAction(). I am using the same redirect in other actions and they execute flawlessly. Would you please review my code and let me know if you find a problem? I appreciate it! Thanks.
public function startAction() {
require_once 'Train.php';
$trainModel = new Train();
$config = Zend_Registry::get('config');
require_once 'Zend/Session/Namespace.php';
$userNamespace = new Zend_Session_Namespace('User');
$trainData = $trainModel->getTrain($userNamespace->gamePlayerId);
switch($trainData['type']) {
case 'STANDARD':
default:
$unitMovement = $config->train->standard->unit_movement;
break;
case 'FAST FREIGHT':
$unitMovement = $config->train->fast_freight->unit_movement;
break;
case 'SUPER FREIGHT':
$unitMovement = $config->train->superfreight->unit_movement;
break;
case 'HEAVY FREIGHT':
$unitMovement = $config->train->heavy_freight->unit_movement;
break;
}
$trainRow = array('track_units_remaining' => $unitMovement);
$where = $trainModel->getAdapter()->quoteInto('id = ?', $trainData['id']);
$trainModel->update($trainRow, $where);
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto');
}
.
.
.
public function moveTrainsAutoAction() {
$log = Zend_Registry::get('log');
$log->debug('moveTrainsAutoAction');
require_once 'Train.php';
$trainModel = new Train();
$userNamespace = new Zend_Session_Namespace('User');
$gameNamespace = new Zend_Session_Namespace('Game');
$trainData = $trainModel->getTrain($userNamespace->gamePlayerId);
$trainRow = $this->_helper->moveTrain($trainData['dest_city_id']);
if(count($trainRow) > 0) {
if($trainRow['status'] == 'ARRIVED') {
// Pass id for last city user selected so we can return user to previous map scroll postion
$this->_redirect($config->url->absolute->fb->canvas . '/turn/unload-cargo?city_id='.$gameNamespace->endTrackCity);
} else if($trainRow['track_units_remaining'] > 0) {
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto');
} else { /* Turn has ended */
$this->_redirect($config->url->absolute->fb->canvas . '/turn/end');
}
}
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto-error'); //-set-destination-error');
}
As #Jani Hartikainen points out in his comment, there is really no need to URL-encode underscores. Try to redirect with literal underscores and see if that works, since I believe redirect makes some url encoding of its own.
Not really related to your question, but in my opinion you should refactor your code a bit to get rid of the switch-case statements (or at least localize them to a single point):
controllers/TrainController.php
[...]
public function startAction() {
require_once 'Train.php';
$trainTable = new DbTable_Train();
$config = Zend_Registry::get('config');
require_once 'Zend/Session/Namespace.php';
$userNamespace = new Zend_Session_Namespace('User');
$train = $trainTable->getTrain($userNamespace->gamePlayerId);
// Add additional operations in your getTrain-method to create subclasses
// for the train
$trainTable->trackStart($train);
$this->_redirect(
$config->url->absolute->fb->canvas . '/turn/move-trains-auto'
);
}
[...]
models/dbTable/Train.php
class DbTable_Train extends Zend_Db_Table_Abstract
{
protected $_tableName = 'Train';
[...]
/**
*
*
* #return Train|false The train of $playerId, or false if the player
* does not yet have a train
*/
public function getTrain($playerId)
{
// Fetch train row
$row = [..];
return $this->trainFromDbRow($row);
}
private function trainFromDbRow(Zend_Db_Table_Row $row)
{
$data = $row->toArray();
$trainType = 'Train_Standard';
switch($row->type) {
case 'FAST FREIGHT':
$trainType = 'Train_Freight_Fast';
break;
case 'SUPER FREIGHT':
$trainType = 'Train_Freight_Super';
break;
case 'HEAVY FREIGHT':
$trainType = 'Train_Freight_Heavy';
break;
}
return new $trainType($data);
}
public function trackStart(Train $train)
{
// Since we have subclasses here, polymorphism will ensure that we
// get the correct speed etc without having to worry about the different
// types of trains.
$trainRow = array('track_units_remaining' => $train->getSpeed());
$where = $trainModel->getAdapter()->quoteInto('id = ?', $train->getId());
$this->update($trainRow, $where);
}
[...]
/models/Train.php
abstract class Train
{
public function __construct(array $data)
{
$this->setValues($data);
}
/**
* Sets multiple values on the model by calling the
* corresponding setter instead of setting the fields
* directly. This allows validation logic etc
* to be contained in the setter-methods.
*/
public function setValues(array $data)
{
foreach($data as $field => $value)
{
$methodName = 'set' . ucfirst($field);
if(method_exists($methodName, $this))
{
$this->$methodName($value);
}
}
}
/**
* Get the id of the train. The id uniquely
* identifies the train.
* #return int
*/
public final function getId ()
{
return $this->id;
}
/**
* #return int The speed of the train / turn
*/
public abstract function getSpeed ();
[..] //More common methods for trains
}
/models/Train/Standard.php
class Train_Standard extends Train
{
public function getSpeed ()
{
return 3;
}
[...]
}
/models/Train/Freight/Super.php
class Train_Freight_Super extends Train
{
public function getSpeed ()
{
return 1;
}
public function getCapacity ()
{
return A_VALUE_MUCH_LARGER_THAN_STANDARD;
}
[...]
}
By default, this will send an HTTP 302 Redirect. Since it is writing headers, if any output is written to the HTTP output, the program will stop sending headers. Try looking at the requests and response inside Firebug.
In other case, try using non default options to the _redirect() method. For example, you can try:
$ropts = { 'exit' => true, 'prependBase' => false };
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto', $ropts);
There is another interesting option for the _redirect() method, the code option, you can send for example a HTTP 301 Moved Permanently code.
$ropts = { 'exit' => true, 'prependBase' => false, 'code' => 301 };
$this->_redirect($config->url->absolute->fb->canvas . '/turn/move-trains-auto', $ropts);
I think I may have found the answer. It appears that Facebook does not play nice with redirect, so it is neccessary to use Facebook's 'fb:redirect' FBML. This appears to work:
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender();
echo '<fb:redirect url="' . $config->url->absolute->fb->canvas . '/turn/move-trains-auto"/>';

Categories