Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Eloquent - Encrypting/Decrypt Data on call

I can use Crypt to encrypt/decrypt my data. I want to encrypt some information in my db (such as the name, email, phone number to name a few).

Assuming that I want EVERYTHING to be encrypted, I want to be able to do this in the background by itself, which I can perform by overwriting the create and save functions:

// For instance, the save() function could become
public function save(array $options = array())
{
    foreach ($this->attributes as $key => $value)
    {
        if (isset($value)) $this->attributes[$key] = Crypt::encrypt($value);
    }
    return parent::save($options);
}

Now, I want the decryption to be performed the same way, so that when I say User::find($id), the returned $user is already decrypted. Also other functions such as firstOrFail() get() first() and all to work as well.

I also would like this functionality to be extended when I use relationships (so User::with('someOtherTable')->find($id) also work).

Would this be possible? If this is not possible, I am thinking of creating a helper function decyrpt()

function decrypt($array)
{
    if (!is_array($array)) return Crypt::decrypt($array);

    $result = [];

    foreach($array as $key => $value) $result[$key] = decrypt($value);

    return $result;
}

And pass all my results through this first, and then start using them, but it would be nicer if Laravel would provide this, or if there was a "Laravel Way" of doing this.

like image 463
Kousha Avatar asked Jul 10 '14 22:07

Kousha


1 Answers

It doesn't really make sense to encrypt everything. For example, you never want to encrypt the primary key; that doesn't even make sense. Likewise you probably don't want to encrypt the date fields; you'll lose the ability to perform any sort of SQL query on them.

With that in mind, you can try something like this:

class BaseModel extends Eloquent {

    protected $encrypt = [];

    public function setAttribute($key, $value)
    {
        if (in_array($key, $this->encrypt))
        {
            $value = Crypt::encrypt($value);
        }

        return parent::setAttribute($key, $value);
    }

    public function getAttribute($key)
    {
        if (in_array($key, $this->encrypt))
        {
            return Crypt::decrypt($this->attributes[$key]);
        }

        return parent::getAttribute($key);
    }

    public function attributesToArray()
    {
        $attributes = parent::attributesToArray();

        foreach ($attributes as $key => $value)
        {
            if (in_array($key, $this->encrypt))
            {
                $attributes[$key] = Crypt::decrypt($value);
            }
        }

        return $attributes;
    }

}

then have all you models extend this one, and set the $encrypt property to whatever columns you want encrypted for that particular model.


P.S. If you want to use Eloquent's accessor functionality, you'll have to play with this a bit more.

like image 90
Joseph Silber Avatar answered Oct 20 '22 17:10

Joseph Silber