I have two doubts about my development in Silex PHP.
usersController.php
namespace myworkplaces\controllers;
use Silex\Application;
use Silex\Api\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use myworkplaces\models;
class usersController implements ControllerProviderInterface {
public function connect(Application $app) {
$controllers = $app['controllers_factory'];
$controllers->put('/login', array($this, 'login'))->bind('login');
return $controllers;
}
public function login(Application $app, Request $request) {
$email = $app->escape($request->get('email'));
$password = $app->escape($request->get('password'));
if (!filter_var($email, FILTER_VALIDATE_EMAIL))
return $app->json(array ('type' => 'error', 'message' => 'El email no tiene el formato correcto.'), 202);
if (strlen($password) < 5)
return $app->json(array ('type' => 'error', 'message' => 'La contraseña no puede ser menor a 6 carácteres.'), 202);
if (models\usersModel::checkLogin($app, $email, $password)) {
return $app->json(array ('type' => 'info', 'message' => '¡Ten un buen día!'), 201);
} else {
return $app->json(array ('type' => 'error', 'message' => 'Error en la autentificación.'), 202);
}
}}
usersModel.php
namespace myworkplaces\models;
class usersModel {
function checkEmail($app, $email) {
if (($app['db']->users)->findOne([ 'email' => $email ], [ 'projection' => [ 'email' => 1 ] ]) != NULL) {
return true;
} else {
return false;
}
}
function getDataUser($app, $id) {
return ($app['db']->users)->findOne([ '_id' => new \MongoDB\BSON\ObjectID($id) ]);
}
function checkLogin($app, $email, $password) {
if (!checkEmail($app, $email))
return false;
if (password_verify($password, ($app['db']->users)->findOne([ 'email' => $email ], [ 'projection' => [ 'hashPassword' => 1 ] ])['hashPassword'])) {
$user = getDataUser($app, (string)getID($email));
$app['session']->set('user', array('id' => (string)$user['_id'], 'email' => $user['email'], 'username' => $user['username'], 'superadmin' => $user['superadmin'], 'adminPlaces' => $user['adminPlaces']));
return true;
} else {
return false;
}
}}
To access the checkLogin() function inside the myworkplaces\models namespace and within the class usersModel, I could only access using this call models\usersModel::checkLogin(), and I do not think it's the right thing. Should not I be able to call the function with models\usersModel\checkLogin()?
The second problem is in the function checkLogin, I want to call the checkEmail function inside the same namespace and within the same class, however with a call like checkEmail () you should be able to call it without error. The error that occurs is, Attempted to call function "checkEmail" from namespace "myworkplaces\models". Where is the problem?
I use the autoload of composer
"autoload": {
"psr-4": {
"myworkplaces\\": "src/"
}
}
Thanks!
Here i am assuming no other syntax errors and your class loader is working fine.
In your controller.php
Change this to:
if (models\usersModel::checkLogin($app, $email, $password)) {
This:
if (\myworkplaces\models\usersModel::checkLogin($app, $email, $password)) {
In your usersModel.php
Change this to:
function checkEmail($app, $email) {
This:
public function static checkEmail($app, $email) {
Change this to:
if (!checkEmail($app, $email))
This:
if (!self::checkEmail($app, $email))
Related
I am getting error from IE when I redirect to "dashboard" controller after settings session values in "login" function ( return redirect()->to(base_url('dashboard'));). I have this working on Chrome, Firefox, Edge, and Opera.
I am using public $sessionDriver = 'CodeIgniter\Session\Handlers\DatabaseHandler'; for session storage. this works well with other borwsers.
<?php
namespace App\Controllers;
use App\Controllers\BaseController;
use App\Models\UserModel;
class User extends BaseController
{
public function login()
{
$data = [];
if ($this->request->getMethod() == 'post') {
$rules = [
'email' => 'required|min_length[6]|max_length[50]|valid_email',
'password' => 'required|min_length[8]|max_length[255]|validateUser[email,password]',
];
$errors = [
'password' => [
'validateUser' => "Email or Password don't match",
],
];
if (!$this->validate($rules, $errors)) {
return view('login', [
"validation" => $this->validator,
]);
} else {
$model = new UserModel();
$user = $model->where('email', $this->request->getVar('email'))
->first();
// Stroing session values
$this->setUserSession($user);
// Redirecting to dashboard after login
return redirect()->to(base_url('dashboard'));
}
}
return view('login');
}
private function setUserSession($user)
{
$data = [
'id' => $user['id'],
'name' => $user['name'],
'phone_no' => $user['phone_no'],
'email' => $user['email'],
'isLoggedIn' => true,
];
session()->set($data);
return true;
}
public function register()
{
$data = [];
if ($this->request->getMethod() == 'post') {
//let's do the validation here
$rules = [
'name' => 'required|min_length[3]|max_length[20]',
'phone_no' => 'required|min_length[9]|max_length[20]',
'email' => 'required|min_length[6]|max_length[50]|valid_email|is_unique[tbl_users.email]',
'password' => 'required|min_length[8]|max_length[255]',
'password_confirm' => 'matches[password]',
];
if (!$this->validate($rules)) {
return view('register', [
"validation" => $this->validator,
]);
} else {
$model = new UserModel();
$newData = [
'name' => $this->request->getVar('name'),
'phone_no' => $this->request->getVar('phone_no'),
'email' => $this->request->getVar('email'),
'password' => $this->request->getVar('password'),
];
$model->save($newData);
$session = session();
$session->setFlashdata('success', 'Successful Registration');
return redirect()->to(base_url('login'));
}
}
return view('register');
}
public function profile()
{
$data = [];
$model = new UserModel();
$data['user'] = $model->where('id', session()->get('id'))->first();
return view('profile', $data);
}
public function logout()
{
session()->destroy();
return redirect()->to('login');
}
}
CodeIgniter4 has its "user agent class" this should help you to be able to validate if you are using IE, I share the documentation and I hope it helps you.
You can validate using that class and redirect with another method.
https://codeigniter.com/user_guide/libraries/user_agent.html
In ZF3 I created a form with two fields: text and url. Only one of them may be filled out by user and at least one must be filled out.
Imagine: one can put the contents of the site or the url of the site. The form may be used to grab certain data from the site or text.
I prepared two validator classes. One for each input. The classes were getting the input value of the other one from context parameter. The StringLength validator was used for both fields.
This worked almost fine but the bad issue was coming when both fields were submitted empty. Then the data did pass the validation while it should no.
At the case of this issue the fields have required turned to false.
When I switched them to true both of fields got required but I wanted only one to be required.
So the goal is that when both fields were empty the validation result would get false. Then the only one message should appear. I mean the message more or less like this: One of fields must be filled out. Not the 'required' message.
Here you are the form class and both validator classes.
<?php
namespace Application\Filter;
use Application\Form\Test as Form;
use Application\Validator\Text;
use Application\Validator\Url;
use Zend\InputFilter\InputFilter;
class Test extends InputFilter
{
public function init()
{
$this->add([
'name' => Form::TEXT,
'required' => false,
'validators' => [
['name' => Text::class],
],
]);
$this->add([
'name' => Form::URL,
'required' => false,
'validators' => [
['name' => Url::class],
],
]);
}
}
<?php
namespace Application\Validator;
use Zend\Validator\StringLength;
use Zend\Validator\ValidatorInterface;
class Text implements ValidatorInterface
{
protected $stringLength;
protected $messages = [];
public function __construct()
{
$this->stringLengthValidator = new StringLength();
}
public function isValid($value, $context = null)
{
if (empty($context['url'])) {
$this->stringLengthValidator->setMin(3);
$this->stringLengthValidator->setMax(5000);
if ($this->stringLengthValidator->isValid($value)) {
return true;
}
$this->messages = $this->stringLengthValidator->getMessages();
return false;
}
if (!empty($value)) return false;
}
public function getMessages()
{
return $this->messages;
}
}
<?php
namespace Application\Validator;
use Zend\Validator\StringLength;
use Zend\Validator\ValidatorInterface;
class Url implements ValidatorInterface
{
const ERROR_NOT_ALLOWED_STRING = 'string-not-allowed';
protected $stringLength;
protected $messages = [
self::ERROR_NOT_ALLOWED_STRING => 'Only one of text and url field may by filled.',
];
public function __construct()
{
$this->stringLengthValidator = new StringLength();
}
public function isValid($value, $context = null)
{
if (empty($context['text'])) {
$this->stringLengthValidator->setMin(3);
$this->stringLengthValidator->setMax(500);
if ($this->stringLengthValidator->isValid($value)) {
return true;
}
$this->messages = $this->stringLengthValidator->getMessages();
return false;
}
if (!empty($value)) return false;
}
public function getMessages()
{
return $this->messages;
}
}
Update
I used advises from #Crisp and had to do some correction in the code. Added returns and message handling. The working code is below:
<?php
namespace Application\Filter;
use Application\Form\Test as Form;
use Application\Validator\Text;
use Application\Validator\Url;
use Zend\InputFilter\InputFilter;
class Test extends InputFilter
{
public function init()
{
$this->add([
'name' => Form::TEXT,
'required' => false,
'allow_empty' => true,
'continue_if_empty' => true,
'validators' => [
['name' => Text::class],
],
]);
$this->add([
'name' => Form::URL,
'required' => false,
'allow_empty' => true,
'continue_if_empty' => true,
'validators' => [
['name' => Url::class],
],
]);
}
}
<?php
namespace Application\Validator;
use Zend\Validator\StringLength;
use Zend\Validator\ValidatorInterface;
class Text implements ValidatorInterface
{
protected $stringLength;
protected $messages = [];
public function __construct()
{
$this->stringLengthValidator = new StringLength();
}
public function isValid($value, $context = null)
{
if (empty($context['url'])) {
if (empty($value)) return false;
$this->stringLengthValidator->setMin(3);
$this->stringLengthValidator->setMax(5000);
if ($this->stringLengthValidator->isValid($value)) {
return true;
}
$this->messages = $this->stringLengthValidator->getMessages();
return false;
}
if (!empty($value)) return false;
return true;
}
public function getMessages()
{
return $this->messages;
}
}
<?php
namespace Application\Validator;
use Zend\Validator\StringLength;
use Zend\Validator\ValidatorInterface;
class Url implements ValidatorInterface
{
const ERROR_NOT_ALLOWED_STRING = 'string-not-allowed';
const ERROR_EMPTY_FIELDS = 'empty-fields';
protected $stringLength;
protected $messages = [
self::ERROR_NOT_ALLOWED_STRING => 'Only one of text and url field may be filled out.',
];
public function __construct()
{
$this->stringLengthValidator = new StringLength();
}
public function isValid($value, $context = null)
{
if (empty($context['text'])) {
if (empty($value)) {
$this->messages = [
self::ERROR_EMPTY_FIELDS => 'One of the fields must be filled out.',
];
return false;
}
$this->stringLengthValidator->setMin(3);
$this->stringLengthValidator->setMax(500);
if ($this->stringLengthValidator->isValid($value)) {
return true;
}
$this->messages = $this->stringLengthValidator->getMessages();
return false;
}
if (!empty($value)) return false;
return true;
}
public function getMessages()
{
return $this->messages;
}
}
To ensure your validators always run, even for an empty value, you need to add the allow_empty and continue_if_empty options to your input specs. Otherwise validation is skipped for any value that isn't required.
The following combination should work
class Test extends InputFilter
{
public function init()
{
$this->add([
'name' => Form::TEXT,
'required' => false,
'allow_empty' => true,
'continue_if_empty' => true,
'validators' => [
['name' => Text::class],
],
]);
$this->add([
'name' => Form::URL,
'required' => false,
'allow_empty' => true,
'continue_if_empty' => true,
'validators' => [
['name' => Url::class],
],
]);
}
}
That combination should ensure your validators are applied when empty values are encountered.
Rob Allen (#akrabat) wrote a useful blog post detailing the combinations which is worth bookmarking akrabat.com/zend-input-empty-values/
Recently I try to change the encoding of the password on CakePHP by directly adding a new file. Unfortunately I do not seem to connect, namely that her works perfectly with the class Simple in sha256
AppController
class AppController extends Controller {
public $components = array('Auth' => array(
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'email','password' => 'password'),
'passwordHasher' => array(
'className' => 'Custom'),
'scope' => array('active' => '1')
)
)
));
UsersController(login)
App::uses('CustomPasswordHasher', 'Controller/Component/Auth');
class UsersController extends AppController{
public function login()
{
$erreur = false;
if($this->request->is('post')) {
if(!empty($this->data)) {
if(!$this->Auth->user('id')) {
if($this->Auth->login()) {
echo 'ok';
} else {
$erreur = "Identifiant incorrect.";
}
} else {
$erreur = "Vous êtes déjà connecter.";
}
} else {
$erreur = "Veuillez saisir vos identifiants";
}
$this->set(compact('erreur'));
}
}
}
CustomPasswordHasher
App::uses('AbstractPasswordHasher', 'Controller/Component/Auth');
class CustomPasswordHasher extends AbstractPasswordHasher {
public function hash($password)
{
$before = substr(Configure::read('Security.salt'),0,43);
$after = substr(Configure::read('Security.salt'),43,42);
$chaine = $before.$password.$after;
return hash("sha256",$chaine);
}
public function check($password, $email, $hashType = null) {
$this->User = ClassRegistry::init('User');
$u = $this->User->find('first', array(
'fields' => array('user.password'),
'conditions' => array('user.email' => $email)
));
if($u) {
return $this->hash($password) == $u['User']['password'];
}
return false;
}
}
An idea where my problem might come?
Thank you !
I am new to laravel framework any help would appreciate
When i try to execute the below code i get this error
FatalErrorException in SocialController.php line 27: Class 'App\Http\Controllers\Hybrid_Auth' not found in SocialController.php line 27
when i remove the namespace from SocialController.php i get this error saying BaseController not found.
onclick this button
<i class="fa fa-facebook"></i> Facebook
SocialController.php
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class SocialController extends BaseController
{
//this is the code for facebook Login
public function getFacebookLogin($auth=NULL)
{
if ($auth == 'auth')
{
try
{
Hybrid_Endpoint::process();
}
catch (Exception $e)
{
return Redirect::to('fbauth');
}
return;
}
$oauth = new Hybrid_Auth(app_path(). '/config/fb_auth.php');
$provider = $oauth->authenticate('Facebook');
$profile = $provider->getUserProfile();
return var_dump($profile).'Log Out';
}
public function getLoggedOut()
{
$fauth = new Hybrid_auth(app_path().'/config/fb_auth.php');
$fauth->logoutAllProviders();
return view::make('/');
}
}
fb_auth.php
<?php
return array(
"base_url" => "http://urmk.com/fbauth/auth",
"providers" => array (
"Facebook" => array (
"enabled" => true,
"keys" => array ( "id" => "APP_ID", "secret" => "APP_SECRET" ),
"scope" => "email"
)
)
);
Routes.php
Route::get('fbauth/{auth?}' ,array('as'=>'facebook', 'uses'=>'SocialController#getFacebookLogin'));
Route::get('logout',array('as'=>'logout','uses'=>'SocialController#getLoggedOut'));
You will need to add the namespace to your Hybrid Auth class. At the moment, when you are trying to instantiate the Hybrid_Auth object, it's not finding the class definition.
Here is my setup for Laravel:
app/Providers/AppServiceProvider.php
public function register()
{
$this->app->bind('Hybrid_Auth', function($app) {
return new \Hybrid_Auth(config_path('hybridauth.php'));
});
}
config/hybridauth.php
<?php
return [
'base_url' => env('APP_URL').'/auth/endpoint',
'providers' => [
'Facebook' => [
'enabled' => true,
'display' => 'popup',
'keys' => [
'id' => 'xxxx',
'secret' => 'xxx'
],
'scope' => 'email'
],
]
];
app/Http/routes.php
Route::group(['prefix' => 'auth'], function()
{
Route::get('login', 'AuthenticateController#login');
Route::get('endpoint', 'AuthenticateController#endpoint');
Route::get('logout', 'AuthenticateController#logout');
});
app/Http/Controllers/AuthenticateController.php
public function login(\Hybrid_Auth $auth)
{
$provider = $auth->authenticate('facebook');
$profile = $provider->getUserProfile();
$user = User::where('facebook', '=', $profile->identifier);
if($user->first()) {
return response()->json(['token' => $this->signin($user->first())]);
} else {
$user = new User;
$user->facebook = $profile->identifier;
$user->save();
return response()->json(['token' => $this->signin($user)]);
}
}
public function endpoint() {
\Hybrid_Endpoint::process();
}
public function logout(\Hybrid_Auth $auth) {
$auth->logoutAllProviders();
}
I can't seem to figure out how I unit test the update of my controller. i'm getting the following error:
method update() from Mockery_0_App.... Should be called exactly 1 times but called 0 times.
After I remove the if statement in the update (after checking if the allergy exists), I get the following error on the line where I add the id the the unique validation rule:
Trying to get property of on object
My Code:
Controller:
class AllergyController extends \App\Controllers\BaseController
{
public function __construct(IAllergyRepository $allergy){
$this->allergy = $allergy;
}
...other methods (index,show,destroy) ...
public function update($id)
{
$allergy = $this->allergy->find($id);
//if ($allergy != null) {
//define validation rules
$rules = array(
'name' => Config::get('Patient::validation.allergy.edit.name') . $allergy->name
);
//execute validation rules
$validator = Validator::make(Input::all(), $rules);
$validator->setAttributeNames(Config::get('Patient::validation.allergy.messages'));
if ($validator->fails()) {
return Response::json(array('status' => false, 'data' => $validator->messages()));
} else {
$allergy = $this->allergy->update($allergy, Input::all());
if ($allergy) {
return Response::json(array('status' => true, 'data' => $allergy));
} else {
$messages = new \Illuminate\Support\MessageBag;
$messages->add('error', 'Create failed! Please contact the site administrator or try again!');
return Response::json(array('status' => false, 'data' => $messages));
}
}
//}
$messages = new \Illuminate\Support\MessageBag;
$messages->add('error', 'Cannot update the allergy!');
return Response::json(array('status' => false, 'data' => $messages));
}
}
TestCase:
class AllergyControllerTest extends TestCase
{
public function setUp()
{
parent::setUp();
$this->allergy = $this->mock('App\Modules\Patient\Repositories\IAllergyRepository');
}
public function mock($class)
{
$mock = Mockery::mock($class);
$this->app->instance($class, $mock);
return $mock;
}
public function tearDown()
{
parent::tearDown();
Mockery::close();
}
public function testIndex()
{
$this->allergy->shouldReceive('all')->once();
$this->call('GET', 'api/allergy');
$this->assertResponseOk();
}
...Other tests for Index and Show ...
public function testUpdate()
{
$validator = Mockery::mock('stdClass');
Validator::swap($validator);
$input = array('name' => 'bar');
$this->allergy->shouldReceive('find')->with(1)->once();
$validator->shouldReceive('make')->once()->andReturn($validator);
$validator->shouldReceive('setAttributeNames')->once();
$validator->shouldReceive('fails')->once()->andReturn(false);;
$this->allergy->shouldReceive('update')->once();
$this->call('PUT', 'api/allergy/1', $input);
$this->assertResponseOk();
}
}
Config validation rules file:
return array(
'allergy' => array(
'add' => array(
'name' => 'required|unique:Allergy'
),
'edit' => array(
'name' => 'required|unique:Allergy,name,'
),
'messages' => array(
'name' => 'Name'
)
)
);
Is there a way to actually mock the value provided into the validation rule? Or what is the best way to solve this?
I changed my code to this and now it works! :)
$validator = Mockery::mock('stdClass');
Validator::swap($validator);
$allergyObj = Mockery::mock('stdClass');
$allergyObj->name = 1;
$input = array('name' => 'bar');
$this->allergyRepo->shouldReceive('find')->with(1)->once()->andReturn($allergyObj);
$validator->shouldReceive('make')->once()->andReturn($validator);
$validator->shouldReceive('setAttributeNames')->once();
$validator->shouldReceive('fails')->once()->andReturn(false);;
$this->allergyRepo->shouldReceive('update')->once();
$this->call('PUT', 'api/allergy/1', $input);
$this->assertResponseOk();