Hidden model fields

Probably there are some fields in your models, usually holding sensitive data, that you do not want to display to the end users. In my case these are passwords, activation codes, etc. I want to ensure that values stored in these fields will be never exposed, neither intentionally nor by accident. So I came up with this little solution.

This is implementation of afterFind() callback function that should be placed inside of app_model.php file.

// app_model.php
class AppModel extends Model {
  var $hiddenFields = array();
 
  function afterFind($result, $primary = false) {
    foreach ($result as &$row)
      foreach ($this->hiddenFields as $field)
        if (isset($row[$this->name][$field]))
          unset($row[$this->name][$field]);
    return $result;
  }
}

The last thing to do is to define $hiddenFields variable in your model.

var $hiddenFields = array('password', 'activation_code');

As you may have noticed, values of these fields are retrieved from the database and later unset. If you don’t want them to be retrieved at all (this would be more secure), you should take care of filtering this fields out in beforeFind() callback method, however this could be quite cumbersome. For me it was OK enough to just unset them after retrieval, so I even didn’t try to do it through beforeFind().

There are also drawbacks. For example you can’t retrieve someone’s password and send it by e-mail when someone forgets it (in fact you can still get it with model’s query() method, but it’s not a ‘clean’ way). In such situations you should generate new random password instead of reminding the forgotten one.

If you have any views on this, please leave a comment.

  • JC

    Hi,
    I tried your method but get this error…

    Parse error: parse error, unexpected ‘&’, expecting T_VARIABLE or ‘$’ in /…../app/app_model.php on line 7

    is it because I’m running on PHP 4?

  • admin

    Hi,
    I didn’t test it on PHP4. That may be the case, but I’m not sure.

    Alternatively you can write:

    function afterFind($result, $primary = false) {
      foreach ($result as $k => $row)
        foreach ($this->hiddenFields as $field)
          if (isset($result[$k][$this->name][$field]))
            unset($result[$k][$this->name][$field]);
      return $result;
    }
    
  • Fahd

    Hey,

    Thanks for the code – just what I was looking for.

    Small problem though, I’m using the containable feature of CakePHP 1.2, and there are some HABTM/HasMany models such as PostsUsers … in that it returns all the Users info who made posts. The ‘password’ field is not being hidden in there. Basically the array is one level deeper and your code doesnt loop through that. I’m not sure how to modify your code to achieve that, maybe you can help out?

    Thanks

    • Michał Szajbe

      Hi,
      this code is a bit old now. In fact I didn’t use this for some time myself :)
      If I was to write this again, I’d probably encapsulate this in a Behavior, so that would be easier to hide fields from associated finds.