I am using Codeigniter 2.0.3 with DataMapper ORM 1.6.0. Integration DataMapper in CI has been implemented successfully and everything works fine, except password encryption.
I have model called users.php with class Users. I also have set validation rules:
var $validation = array(
array(
'field' => 'password',
'label' => 'Password',
'rules' => array('required', 'trim', 'unique', 'min_length' => 5, 'encrypt'),
),
array(
'field' => 'email',
'label' => 'Email Address',
'rules' => array('required', 'trim', 'valid_email')
)
);
My encrypt function in validation rule:
function _encrypt($field)
{
// Don't encrypt an empty string
if (!empty($this->{$field}))
{
// Generate a random salt if empty
if (empty($this->salt))
{
$this->salt = md5(uniqid(rand(), true));
}
$this->{$field} = sha1($this->salt . $this->{$field});
}
}
MySQL users table structure:
id
email
password
last_login
created_on
I simple create new user via controller:
$u = new Users();
$u->email = 'mario1#mario-design.info';
$u->password = 'mario';
$u->save();
EDIT 1:
Full code of users.php model here.
User successfully stored in the database but with original password not encrypted.
What am I doing wrong?
Thanks, Regards
Mario
I believe it's that your salt class variable is missing. In your _encrypt function, you call $this->salt, however, you never declare salt in the model. I think you need to add a salt variable in the class:
// in your Users model
<?php if (!defined('BASEPATH')) exit('No direct script access allowed.');
class Users extends DataMapper {
var $table = 'users';
var $has_one = array('profile');
var $salt = 'B1471tU77IK1411'; // any string - helps to make password encryption stronger
I solved problem with upgrading DataMapper to 1.8.x version. Now, it works just fine!
Related
I'm trying to implement a full access log in a Laravel 5.8 project and that's what I've come up so far: a table named access_logs in a secondary database so than non-relevant log data won't make the db bulky during backup, and custom primary key with no AUTO_INCREMET so can be purged old data without worrying about resetting incremental id while new data is being created. the model is following:
class AccessLog extends Model
{
public $timestamps = true;
public $incrementing = false; // custom id, purgeable
protected $connection= 'mysql2';
protected $fillable = [
'id', // custom id, purgeable
'auth_guard',
'auth_id',
'url',
'method',
'referer',
'request',
'session',
'additional_data',
'ip',
];
}
and the DB writing part in the middleware is following:
$logData = [
'id' => join('_', [
time(),
Auth::user()->id ?? 0,
rand(100000, 999999),
]),
'ip' => json_encode(request()->ips() ?? ''),
'auth_guard' => auth()->getDefaultDriver() ?? null,
'auth_id' => auth()->user()->id ?? null,
'url' => url()->current(),
'method' => request()->method(),
'referer' => url()->previous(),
'request' => json_encode([
$this->removeKeys(request()->all(), [
'password',
]),
$_FILES ?? [],
request()->headers->all(),
]),
'session' => json_encode(session()->all()),
];
AccessLog::create($logData);
the middleware is registered in the kernel file under protected $middlewareGroups['web'].
now my question is I'm trying to log form validation data (ErrorBag?) as well as flash messages, but it seems those do not exists or saved with the session data (session()->all()), how to include/save those with the log?
In my Laravel application, I am trying to send mail notification based on the company_id of the logged in user:
I have this:
$mail=DB::table('mail_settings')->first();
$config = array(
'driver' => $mail->driver,
'host' => $mail->host,
'port' => $mail->port,
'from' => array('address' => $mail->from_address, 'name' => $mail->from_name),
'encryption' => $mail->encryption,
'username' => $mail->username,
'password' => $mail->password,
'sendmail' => '/usr/sbin/sendmail -bs',
'pretend' => false
);
Config::set('mail',$config);
Models
class Company extends Model
{
protected $table = 'companies';
protected $fillable = [
'id',
'organization_name'
];
}
class User extends Authenticatable
{
protected $fillable = [
'name',
'company_id',
'email',
];
}
Is there any way to override default mail configuration (in app/config/mail.php) on-the-fly (e.g. configuration is stored in database) before mailer transport is created?
Thanks
Is there any way to recreate laravel swiftmailer transport so it can pick up updated config values?
The Mailer class is created in the Illuminate\Mail\MailManager class's resolve() method. If you want to dynamically create a mailer, you need to adapt this function in your Controller to use your $config array and return a Mailer from which you could chain the usual methods.
protected function resolve($name)
{
$config = $this->getConfig($name);
if (is_null($config)) {
throw new InvalidArgumentException("Mailer [{$name}] is not defined.");
}
// Once we have created the mailer instance we will set a container instance
// on the mailer. This allows us to resolve mailer classes via containers
// for maximum testability on said classes instead of passing Closures.
$mailer = new Mailer(
$name,
$this->app['view'],
$this->createSwiftMailer($config),
$this->app['events']
);
if ($this->app->bound('queue')) {
$mailer->setQueue($this->app['queue']);
}
// Next we will set all of the global addresses on this mailer, which allows
// for easy unification of all "from" addresses as well as easy debugging
// of sent messages since these will be sent to a single email address.
foreach (['from', 'reply_to', 'to', 'return_path'] as $type) {
$this->setGlobalAddress($mailer, $config, $type);
}
return $mailer;
}
I cannot understand how to choose which user data to save after login. I have noticed that I can only change the recursivity of the model, but I cannot choose individual fields to use.
For example, normally Cakephp saves in session all user fields except the password, even the data that I don't need and I do not want stored.
If I increase the recursion, Cakephp saves all the fields of related models.
Is there a way as for the "fields" parameter of the Model find method?
I know that after login I can recover the data that I miss and add them in session, merging to those already stored, but I want to avoid making another query and find a more elegant solution, if it exists.
Thanks.
As of Cake 2.2, you can add a contain key to your authentication options to pull related data. Since the contain key accepts a fields key, you can restrict the fields there:
public $components = array(
'Auth' => array(
'authenticate' => array(
'Form' => array(
'contain' => array(
'Profile' => array(
'fields' => array('name', 'birthdate')
)
)
)
)
)
);
If you want to change the fields the user model searches for, you can extend the authentication object you're using. Generally the users table contains a minimal amount of information, so this isn't usually necessary.
However, I'll give an example anyway. We'll use the FormAuthenticate object here, and use most of the _findUser method code from the BaseAuthenticate class. This is the function that Cake's authentication system uses to identify the user.
App::uses('FormAuthenticate', 'Controller/Component/Auth');
class MyFormAuthenticate extends FormAuthenticate {
// overrides BaseAuthenticate::_findUser()
protected function _findUser($username, $password) {
$userModel = $this->settings['userModel'];
list($plugin, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
$conditions = array(
$model . '.' . $fields['username'] => $username,
$model . '.' . $fields['password'] => $this->_password($password),
);
if (!empty($this->settings['scope'])) {
$conditions = array_merge($conditions, $this->settings['scope']);
}
$result = ClassRegistry::init($userModel)->find('first', array(
// below is the only line added
'fields' => $this->settings['findFields'],
'conditions' => $conditions,
'recursive' => (int)$this->settings['recursive']
));
if (empty($result) || empty($result[$model])) {
return false;
}
unset($result[$model][$fields['password']]);
return $result[$model];
}
}
Then use that authentication and pass our new setting:
public $components = array(
'Auth' => array(
'authenticate' => array(
'MyForm' => array(
'findFields' => array('username', 'email'),
'contain' => array(
'Profile' => array(
'fields' => array('name', 'birthdate')
)
)
)
)
)
);
I just spent a while on this problem, only to find out that a 'userFields' option has been implemented as of Cake 2.6
Have a look at the docs here:
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
When designing a relationship in Datamapper one is bound to call the relationship the same name as the related object, which is not too handy when you have something like Application_Model_User as a class name. For those of you who will rush to say that there is a configuration option with "class" key, I know. Been there tried that. It only works for getting a related object, not for updating them.
Here is a code snippet to reproduce the problem:
// User Model
class UserModel extends Datamapper
{
public $table = 'users';
public $has_many = array(
'roles' => array(
'class' => 'RoleModel',
'other_field' => 'usermodel',
'join_other_as' => 'role',
'join_self_as' => 'user',
'join_table' => 'users_roles'
),
);
}
class RoleModel extends DataMapper
{
public $table = 'roles';
public $has_many = array(
'usermodel' => array('class' => 'UserModel',
'other_field' => 'roles',
'join_other_as'=> 'user',
'join_self_as' => 'role',
'join_table' => 'users_roles' )
);
}
// controller code. Make sure you have a role with INT id = 2, and a user with INT id = 5 in your db
$user = new UserModel(2);
$role = new RoleModel(5);
$user->save($role);
This code gives an "Unable to relate usermodel with rolemodel." error, however it does work properly (meaning a new record is inserted in the join table user_roles) if the relation is renamed from "roles" to "rolemodel".
So, if there are any avid users of CI's Datamapper that could help, please let me know how to properly define relationships.
UPDATE
You can save an object as a relation using the relationship key:
$object->save( $related, $relationship_key ).
So you would need to use
$user->save($role, "roles");
See the bottom of this web page:
http://datamapper.wanwizard.eu/pages/save.html
Leaving this bit in case it helps someone else out.
It looks like you want to have a custom name on a relationship. (That's what I get after wading through all of the cynicism) -
You get to name the relationship anything that you want with the key in the relationship array. So, in the following snippet, you use book <-- this does or does not have to be the same name as the class - that's what the class key is for.
class Author extends DataMapper {
$has_many = array(
'book' => array( // YOU USE THIS KEY TO NAME THE RELATIONSHIP
'class' => 'book',
'other_field' => 'author',
'join_self_as' => 'author',
'join_other_as' => 'book',
'join_table' => 'authors_books'
)
);
}
If this is not working for you, my guess is you have something else wrong in the set up of your relationships.
http://datamapper.wanwizard.eu/pages/advancedrelations.html
I have an app that uses Auth component. Logedin members can alter their data as long as I have no validation rules in users model. When I add array $validate in model logedin users cannot submit data to database.
I use one mysql table named users.
In other words this works but I don't have validation in signup view
<?php
class User extends AppModel {
var $name = 'User';
?>
But when I add validation like this:
<?php
class User extends AppModel {
var $name = 'User';
var $validate = array(
'email' => array(
'email' => array('rule' => 'email','required'=>true,'message' => 'Enter proper mail')
)
);
}
?>
validation in signup view works but users in secret area cannot enter data to database.
My guess is: This is happening because you have set required to true.
This enforces the rule that when submitted data of the User model, the email key needs to be set. Therefore, this works in your Sign Up form which obviously has the email key. On the other hand, the form that you're using in the secret area probably does not have an email field.
Just remove the "required" condition from your validation rule:
'email' => array(
'email' => array(
'rule' => array('email'),
'message' => 'Please enter a valid email',
),
),
Let me know if this works for you.