📜 ⬆️ ⬇️

Writing uLogin module for Kohana 3.2

Not so long ago on Habré there was an article about the uLogin authorization widget.
What I really liked about it, is the ability to specify the required fields, while, if they are not received from the provider, the user is invited to fill them in manually. So there was a desire to write a module in Kohana, which would allow easy user registration using the uLogin widget.


A bit about the structure of the modules


Each module is placed in a separate folder in the MODPATH folder (default modules)
Inside may be the folder classes, config, and all the same as in the application. This is the so-called cascade file system, read more here.
')
For our module, you need only the classes and config folders.
In the config folder will be the default configuration file, and, if desired, you can override it in application / config.
The classes folder contains the ulogin.php file, which contains the definition of the Ulogin class:
<?php defined('SYSPATH') or die('No direct script access.'); class Ulogin extends Kohana_Ulogin {} 

This class is inherited from Kohana_Ulogin, which will, if necessary, override it by placing it in the file application / classes / ulogin.php.

Since the base class is called Kohana_Ulogin, it should be in classes / kohana / ulogin.php, since Kohana replaces the underscore with a slash when searching for a class for autoloading.

Before use, the module must be connected to bootstrap.php:
 Kohana::modules(array( ...... 'ulogin' => MODPATH.'ulogin', // uLogin )); 


Widget display

The authorization widget is displayed as follows:
 echo Ulogin::factory()->render() 


What happens when this happens:

Static function
  public static function factory(array $config = array()) { return new Ulogin($config); } 

It creates an instance of the Ulogin class, while transferring the emu array with the configuration, this is done to be able to overwrite the default settings directly when called.

Constructor class:
  public function __construct(array $config = array()) { $this->config = array_merge($this->config, Kohana::$config->load('ulogin')->as_array(), $config); if ($this->config['redirect_uri'] === NULL) $this->config['redirect_uri'] = Request::initial()->url(true); } 

Loads the config using Kohana :: $ config-> load Kohans function and checks redirect_uri to NULL. In the case of a positive test result, the current address that the user contacted is simply set, receiving it by calling Request :: initial () -> url (true). The true parameter tells Kokhane to include the protocol in the address. Request :: initial () is used to get the initial address.

The render () function:
  public function render() { $params = 'display='.$this->config['type']. '&fields='.implode(',', array_merge($this->config['username'], $this->config['fields'])). '&providers='.implode(',', $this->config['providers']). '&hidden='.implode(',', $this->config['hidden']). '&redirect_uri='.$this->config['redirect_uri']. '&optional='.implode(',', $this->config['optional']); if (count(self::$_used_id) == 0) { $view = View::factory('ulogin/first'); self::$_used_id[] = 'uLogin'; } else { $view = View::factory('ulogin/second'); do { $uniq_id = "uLogin_".rand(); } while(in_array($uniq_id, self::$_used_id)); self::$_used_id[] = $uniq_id; $view->set('uniq_id', $uniq_id); } return $view->set('cfg', $this->config)->set('params', $params)->render(); } 

First of all, you need to make the parameters for the transfer to the uLogin script. http_build_query () is not suitable here, since it encodes the data (in particular commas) into their hexadecimal codes (% xx). Then it is checked whether the first is a launch (in the self :: $ _ used_id array is empty), or not.
If the first one, then the View ulogin / first.php is loaded:
 <?php if ($cfg['type'] == 'window') :?> <a href="#" id="uLogin"> <img src="http://ulogin.ru/img/button.png" width=187 height=30 alt=""/> </a> <script src="http://ulogin.ru/js/widget.js?<?php echo $params; ?>"></script> <?php else: ?> <div id="uLogin"></div> <script src="http://ulogin.ru/js/widget.js?<?php echo $params; ?>"></script> <?php endif; ?> 

Depending on the selected mode, it displays the HTML code for calling the widget.

If this is a second step, then we generate a unique identifier and load View ulogin / second.php:
 <div id="<?php echo $uniq_id; ?>"></div> <script type='text/javascript'>uLogin.init('id=<?php echo $uniq_id; ?>&<?php echo $params; ?>');</script> 

It just calls the widget according to the documentation located on the official website.

That's all that is needed to display the authorization widget

Result processing


Processing using the module looks like this:
  $ulogin = Ulogin::factory(); if (!$ulogin->mode()) $this->template->content = $ulogin->render(); else { try { $ulogin->login(); } catch(ORM_Validation_Exception $e) { $this->template->errors = $e->errors(''); } } 


That is, we check the mode by calling mode (), after which we either display the widget or authorize / register the user. try / catch is needed to verify the user's registration, for example, a matching e-mail /

The mode () function simply checks for $ _POST ['token']:
  public function mode() { return !empty($_POST['token']); } 


C login () is more complicated:
  public function login() { if (empty($_POST['token'])) throw new Kohana_Exception('Empty token.'); if (!($domain = parse_url(URL::base(), PHP_URL_HOST))) { $domain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']; } $s = Request::factory('http://ulogin.ru/token.php?token=' . $_POST['token'] . '&host=' . $domain)->execute()->body(); $user = json_decode($s, true); $orm_user = ORM::factory('user', array('identity' => $user['identity'])); if (!$orm_user->loaded()) { $data['username'] = ''; foreach($this->config['username'] as $part_of_name) $data['username'] .= (empty($user[$part_of_name]) ? '' : (' '.$user[$part_of_name])); $data['username'] = trim($data['username']); if (!$data['username']) throw new Kohana_Exception('Username fields not set in config/ulogin.php'); $data['password'] = 'ulogin_autogenerated_password'; $data['identity'] = $user['identity']; $data['network'] = $user['network']; $cfg_fields = array_merge($this->config['fields'], $this->config['optional']); foreach($cfg_fields as $field) { if (!empty($user[$field])) $data[$field] = $user[$field]; } $orm_user->values($data); $orm_user->create(); $orm_user->add('roles', ORM::factory('role', array('name' => 'login'))); Auth::instance()->force_login($orm_user); } else { Auth::instance()->force_login($orm_user); } } 


What's going on here:
We re-check the token (if someone just called login ()), then we try to get a host for transmission to uLogin: either from the base address (specified in bootstrap.php in Kohana :: init ()), or through $ _SERVER [ 'HTTP_HOST'] or $ _SERVER ['SERVER_NAME'].

Then we make a request to uLogin, to obtain user data:

  $s = Request::factory('http://ulogin.ru/token.php?token=' . $_POST['token'] . '&host=' . $domain)->execute()->body(); $user = json_decode($s, true); 

As a result, we get something like this (Google example):
 array(6) ( "network" => string(6) "google" "identity" => string(50) "  ,  https://plus.google.com/u/0/google+ /" "uid" => string(21) "google+ " "email" => string(21) "e-mail" "first_name" => string(10) "" "last_name" => string(14) "" ) 


Next, we try to find it in the database, use its unique URL: $ user ['identity']:
 $orm_user = ORM::factory('user', array('identity' => $user['identity'])); 

If found ($ orm_user-> loaded () == true), simply authorize it:
 Auth::instance()->force_login($orm_user); 

Otherwise, it must be registered:

  1. Make up the username:
     $data['username'] = ''; foreach($this->config['username'] as $part_of_name) $data['username'] .= (empty($user[$part_of_name]) ? '' : (' '.$user[$part_of_name])); $data['username'] = trim($data['username']); 


  2. Fill in the fields of the model:
     $data['password'] = 'ulogin_autogenerated_password'; $data['identity'] = $user['identity']; $data['network'] = $user['network']; $cfg_fields = array_merge($this->config['fields'], $this->config['optional']); foreach($cfg_fields as $field) { if (!empty($user[$field])) $data[$field] = $user[$field]; } $orm_user->values($data); 

  3. Create a user, add the login role to it, and then authorize it:
     $orm_user->create(); $orm_user->add('roles', ORM::factory('role', array('name' => 'login'))); Auth::instance()->force_login($orm_user); 



Source codes are available on github.

As you can see, the use of uLogin and the writing of modules to Kohana do not pose any difficulties.
Good luck!

UPD: Added views
UPD2: Rewritten some code and article, thanks dohlik

Source: https://habr.com/ru/post/132124/


All Articles