| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- <?php
- class MyModel extends Model {
- var $recursive = -1;
- var $actsAs = array('Containable');
- /**
- * @return string Error message with error number
- * 2010-11-06 ms
- */
- public function lastError() {
- $db = $this->getDataSource();
- return $db->lastError();
- }
- /** Validation Functions **/
- /**
- * validates a primary or foreign key depending on the current schema data for this field
- * recognizes uuid (char36) and aiid (int10 unsigned) - not yet mixed (varchar36)
- * more useful than using numeric or notEmpty which are type specific
- * @param array $data
- * @param array $options
- * - allowEmpty
- * 2011-06-21 ms
- */
- function validateKey($data = array(), $options = array()) {
- $key = array_shift(array_keys($data));
- $value = array_shift($data);
- $schema = $this->schema($key);
- if (!$schema) {
- return true;
- }
-
- $defaults = array(
- 'allowEmpty' => false,
- );
- $options = am($defaults, $options);
-
- if ($schema['type'] != 'integer') {
- if ($options['allowEmpty'] && $value === '') {
- return true;
- }
- return Validation::uuid($value);
- }
- if ($options['allowEmpty'] && $value === 0) {
- return true;
- }
- return is_numeric($value) && (int)$value == $value && $value > 0;
- }
- /**
- * checks if the passed enum value is valid
- * 2010-02-09 ms
- */
- function validateEnum($field = array(), $enum = null, $additionalKeys = array()) {
- $valueKey = array_shift(array_keys($field)); # auto-retrieve
- $value = $field[$valueKey];
- $keys = array();
- if ($enum === true) {
- $enum = $valueKey;
- }
- if ($enum !== null) {
- if (!method_exists($this, $enum)) {
- trigger_error('Enum method \'' . $enum . '()\' not exists', E_USER_ERROR);
- return false;
- }
- //TODO: make static
- $keys = $this->{$enum}();
- }
- $keys = array_merge($additionalKeys, array_keys($keys));
- if (!empty($keys) && in_array($value, $keys)) {
- return true;
- }
- return false;
- }
- /**
- * checks if the content of 2 fields are equal
- * Does not check on empty fields! Return TRUE even if both are empty (secure against empty in another rule)!
- * 2009-01-22 ms
- */
- function validateIdentical($data = array(), $compareWith = null, $options = array()) {
- if (is_array($data)) {
- $value = array_shift($data);
- } else {
- $value = $data;
- }
- $compareValue = $this->data[$this->alias][$compareWith];
- $matching = array('string' => 'string', 'int' => 'integer', 'float' => 'float', 'bool' => 'boolean');
- if (!empty($options['cast']) && array_key_exists($options['cast'], $matching)) {
- # cast values to string/int/float/bool if desired
- settype($compareValue, $matching[$options['cast']]);
- settype($value, $matching[$options['cast']]);
- }
- return ($compareValue === $value);
- }
- /**
- * checks a record, if it is unique - depending on other fields in this table (transfered as array)
- * example in model: 'rule' => array ('validateUnique',array('belongs_to_table_id','some_id','user_id')),
- * if all keys (of the array transferred) match a record, return false, otherwise true
- * @param ARRAY other fields
- * TODO: add possibity of deep nested validation (User -> Comment -> CommentCategory: UNIQUE comment_id, Comment.user_id)
- * 2010-01-30 ms
- */
- function validateUnique($data, $fields = array(), $options = array()) {
- $id = (!empty($this->data[$this->alias]['id']) ? $this->data[$this->alias]['id'] : 0);
- foreach ($data as $key => $value) {
- $fieldName = $key;
- $fieldValue = $value; // equals: $this->data[$this->alias][$fieldName]
- }
- if (empty($fieldName) || empty($fieldValue)) { // return true, if nothing is transfered (check on that first)
- return true;
- }
- $conditions = array($this->alias . '.' . $fieldName => $fieldValue, // Model.field => $this->data['Model']['field']
- $this->alias . '.id !=' => $id, );
- # careful, if fields is not manually filled, the options will be the second param!!! big problem...
- foreach ((array )$fields as $dependingField) {
- if (isset($this->data[$this->alias][$dependingField])) { // add ONLY if some content is transfered (check on that first!)
- $conditions[$this->alias . '.' . $dependingField] = $this->data[$this->alias][$dependingField];
- } elseif (!empty($this->data['Validation'][$dependingField])) { // add ONLY if some content is transfered (check on that first!
- $conditions[$this->alias . '.' . $dependingField] = $this->data['Validation'][$dependingField];
- } elseif (!empty($id)) {
- # manual query! (only possible on edit)
- $res = $this->find('first', array('fields' => array($this->alias.'.'.$dependingField), 'conditions' => array($this->alias.'.id' => $this->data[$this->alias]['id'])));
- if (!empty($res)) {
- $conditions[$this->alias . '.' . $dependingField] = $res[$this->alias][$dependingField];
- }
- }
- }
- $this->recursive = -1;
- if (count($conditions) > 2) {
- $this->recursive = 0;
- }
- $res = $this->find('first', array('fields' => array($this->alias . '.id'), 'conditions' => $conditions));
- if (!empty($res)) {
- return false;
- }
- return true;
- }
- /**
- * @param array $data
- * @param array $options
- * - scope (array of other fields as scope - isUnique dependent on other fields of the table)
- * - batch (defaults to true, remembers previous values in order to validate batch imports)
- * example in model: 'rule' => array ('validateUniqueExt', array('scope'=>array('belongs_to_table_id','some_id','user_id'))),
- * http://groups.google.com/group/cake-php/browse_thread/thread/880ee963456739ec
- * //TODO: test!!!
- * 2011-03-27 ms
- */
- function validateUniqueExt($data, $options = array()) {
- foreach ($data as $key => $value) {
- $fieldName = $key;
- $fieldValue = $value;
- }
- $defaults = array('batch' => true, 'scope' => array());
- $options = array_merge($defaults, $options);
- # for batch
- if ($options['batch'] !== false && !empty($this->batchRecords)) {
- if (array_key_exists($value, $this->batchRecords[$fieldName])) {
- return $options['scope'] === $this->batchRecords[$fieldName][$value];
- }
- }
- # continue with validation
- if (!$this->validateUnique($data, $options['scope'])) {
- return false;
- }
- # for batch
- if ($options['batch'] !== false) {
- if (!isset($this->batchRecords)) {
- $this->batchRecords = array();
- }
- $this->batchRecords[$fieldName][$value] = $scope;
- }
- return true;
- }
- /**
- * checks if a url is valid AND accessable (returns false otherwise)
- * @param array/string $data: full url(!) starting with http://...
- * @options
- * - allowEmpty TRUE/FALSE (TRUE: if empty => return TRUE)
- * - required TRUE/FALSE (TRUE: overrides allowEmpty)
- * - autoComplete (default: TRUE)
- * - deep (default: TRUE)
- * 2010-10-18 ms
- */
- function validateUrl($data, $options = array()) {
- //$arguments = func_get_args();
- if (is_array($data)) {
- $url = array_shift($data);
- } else {
- $url = $data;
- }
- if (empty($url)) {
- if (!empty($options['allowEmpty']) && empty($options['required'])) {
- return true;
- }
- return false;
- }
- if (!isset($options['autoComplete']) || $options['autoComplete'] !== false) {
- $url = $this->_autoCompleteUrl($url);
- }
- if (!isset($options['strict']) || $options['strict'] !== false) {
- $options['strict'] = true;
- }
- # validation
- if (!Validation::url($url, $options['strict'])) {
- return false;
- }
-
- # same domain?
- if (!empty($options['sameDomain']) && !empty($_SERVER['HTTP_HOST'])) {
- $is = parse_url($url, PHP_URL_HOST);
- $expected = $_SERVER['HTTP_HOST'];
- if (mb_strtolower($is) !== mb_strtolower($expected)) {
- return false;
- }
- }
- if (isset($options['deep']) && $options['deep'] === false) {
- return true;
- }
- return $this->_validUrl($url);
- }
- function _autoCompleteUrl($url) {
- if (mb_strpos($url, '://') === false && mb_strpos($url, 'www.') === 0) {
- $url = 'http://' . $url;
- } elseif (mb_strpos($url, '/') === 0) {
- $url = Router::url($url, true);
- }
- return $url;
- }
- /**
- * checks if a url is valid
- * @param string url
- * 2009-02-27 ms
- */
- function _validUrl($url = null) {
- App::import('Component', 'Tools.Common');
- $headers = CommonComponent::getHeaderFromUrl($url);
- if ($headers !== false) {
- $headers = implode("\n", $headers);
- return ((bool)preg_match('#^HTTP/.*\s+[(200|301|302)]+\s#i', $headers) && !(bool)preg_match('#^HTTP/.*\s+[(404|999)]+\s#i', $headers));
- }
- return false;
- }
- /**
- * Validation of DateTime Fields (both Date and Time together)
- * @param options
- * - dateFormat (defaults to 'ymd')
- * - allowEmpty
- * - after/before (fieldName to validate against)
- * - min/max (defaults to >= 1 - at least 1 minute apart)
- * 2011-03-02 ms
- */
- function validateDateTime($data, $options = array()) {
- $format = !empty($options['dateFormat']) ? $options['dateFormat'] : 'ymd';
- if (is_array($data)) {
- $value = array_shift($data);
- } else {
- $value = $data;
- }
- $dateTime = explode(' ', trim($value), 2);
- $date = $dateTime[0];
- $time = (!empty($dateTime[1]) ? $dateTime[1] : '');
- if (!empty($options['allowEmpty']) && (empty($date) && empty($time) || $date == DEFAULT_DATE && $time == DEFAULT_TIME || $date == DEFAULT_DATE && empty($time))) {
- return true;
- }
- /*
- if ($this->validateDate($date, $options) && $this->validateTime($time, $options)) {
- return true;
- }
- */
- if (Validation::date($date, $format) && Validation::time($time)) {
- # after/before?
- $minutes = isset($options['min']) ? $options['min'] : 1;
- if (!empty($options['after']) && isset($this->data[$this->alias][$options['after']])) {
- if (strtotime($this->data[$this->alias][$options['after']]) > strtotime($value) - $minutes) {
- return false;
- }
- }
- if (!empty($options['before']) && isset($this->data[$this->alias][$options['before']])) {
- if (strtotime($this->data[$this->alias][$options['before']]) < strtotime($value) + $minutes) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
- /**
- * Validation of Date Fields (as the core one is buggy!!!)
- * @param options
- * - dateFormat (defaults to 'ymd')
- * - allowEmpty
- * - after/before (fieldName to validate against)
- * - min (defaults to 0 - equal is OK too)
- * 2011-03-02 ms
- */
- function validateDate($data, $options = array()) {
- $format = !empty($options['format']) ? $options['format'] : 'ymd';
- if (is_array($data)) {
- $value = array_shift($data);
- } else {
- $value = $data;
- }
- $dateTime = explode(' ', trim($value), 2);
- $date = $dateTime[0];
- if (!empty($options['allowEmpty']) && (empty($date) || $date == DEFAULT_DATE)) {
- return true;
- }
- if (Validation::date($date, $format)) {
- # after/before?
- $days = !empty($options['min']) ? $options['min'] : 0;
- if (!empty($options['after']) && isset($this->data[$this->alias][$options['after']])) {
- if ($this->data[$this->alias][$options['after']] > date(FORMAT_DB_DATE, strtotime($date) - $days * DAY)) {
- return false;
- }
- }
- if (!empty($options['before']) && isset($this->data[$this->alias][$options['before']])) {
- if ($this->data[$this->alias][$options['before']] < date(FORMAT_DB_DATE, strtotime($date) + $days * DAY)) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
- /**
- * @param options
- * - timeFormat (defaults to 'hms')
- * - allowEmpty
- * - after/before (fieldName to validate against)
- * - min/max (defaults to >= 1 - at least 1 minute apart)
- * 2011-03-02 ms
- */
- function validateTime($data, $options = array()) {
- if (is_array($data)) {
- $value = array_shift($data);
- } else {
- $value = $data;
- }
- $dateTime = explode(' ', trim($value), 2);
- $value = array_pop($dateTime);
- if (Validation::time($value)) {
- # after/before?
- if (!empty($options['after']) && isset($this->data[$this->alias][$options['after']])) {
- if ($this->data[$this->alias][$options['after']] >= $value) {
- return false;
- }
- }
- if (!empty($options['before']) && isset($this->data[$this->alias][$options['before']])) {
- if ($this->data[$this->alias][$options['before']] <= $value) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
- //TODO
- /**
- * Validation of Date Fields (>= minDate && <= maxDate)
- * @param options
- * - min/max (TODO!!)
- * 2010-01-20 ms
- */
- function validateDateRange($data, $options = array()) {
- }
- //TODO
- /**
- * Validation of Time Fields (>= minTime && <= maxTime)
- * @param options
- * - min/max (TODO!!)
- * 2010-01-20 ms
- */
- function validateTimeRange($data, $options = array()) {
- }
- /**
- * model validation rule for email addresses
- * 2010-01-14 ms
- */
- function validateUndisposable($data, $proceed = false) {
- $email = array_shift($data);
- if (empty($email)) {
- return true;
- }
- return $this->isUndisposableEmail($email, false, $proceed);
- }
- /**
- * NOW: can be set to work offline only (if server is down etc)
- *
- * checks if a email is not from a garbige hoster
- * @param string email (neccessary)
- * @return boolean true if valid, else false
- * 2009-03-09 ms
- */
- function isUndisposableEmail($email, $onlineMode = false, $proceed = false) {
- if (!isset($this->UndisposableEmail)) {
- App::import('Vendor', 'undisposable');
- $this->UndisposableEmail = new UndisposableEmail();
- }
- if (!$onlineMode) {
- # crashed with white screen of death otherwise... (if foreign page is 404)
- $this->UndisposableEmail->useOnlineList(false);
- }
- if (!class_exists('Validation')) {
- App::import('Core', 'Validation');
- }
- if (!Validation::email($email)) {
- return false;
- }
- if ($this->UndisposableEmail->isUndisposableEmail($email) === false) {
- # trigger log
- $this->log('Disposable Email detected: ' . h($email).' (IP '.env('REMOTE_ADDR').')', 'undisposable');
- if ($proceed === true) {
- return true;
- }
- return false;
- }
- return true;
- }
- /**
- * //TODO: move outside of MyModel? use more generic "blocked" plugin!
- * is blocked email?
- * 2009-12-22 ms
- */
- function validateNotBlocked($params) {
- foreach ($params as $key => $value) {
- $email = $value;
- }
- if (!isset($this->BlockedEmail)) {
- if (!App::import('Model', 'Tools.BlockedEmail')) {
- trigger_error('Model Tools.BlockedEmail not available');
- return true;
- }
- $this->BlockedEmail = ClassRegistry::init('Tools.BlockedEmail');
- }
- if ($this->BlockedEmail->isBlocked($email)) {
- return false;
- }
- return true;
- }
- /**
- * Overrides the Core invalidate function from the Model class
- * with the addition to use internationalization (I18n and L10n)
- * @param string $field Name of the table column
- * @param mixed $value The message or value which should be returned
- * @param bool $translate If translation should be done here
- * 2010-01-22 ms
- */
- function invalidate($field, $value = null, $translate = true) {
- if (!is_array($this->validationErrors)) {
- $this->validationErrors = array();
- }
- if (empty($value)) {
- $value = true;
- } else {
- $value = (array)$value;
- }
- if (is_array($value)) {
- $value[0] = $translate ? __($value[0], true) : $value[0];
-
- $args = array_slice($value, 1);
- $value = vsprintf($value[0], $args);
- }
- $this->validationErrors[$field] = $value;
- }
- /** DEPRECATED STUFF - will be removed in stage 2 **/
- /**
- * @param string $value or array $keys or NULL for complete array result
- * @return string/array
- * static enums
- * @deprecated
- * 2009-11-05 ms
- */
- public static function enum($value, $options, $default = '') {
- if ($value !== null && !is_array($value)) {
- if (array_key_exists($value, $options)) {
- return $options[$value];
- }
- return $default;
- } elseif ($value !== null) {
- $newOptions = array();
- foreach ($value as $v) {
- $newOptions[$v] = $options[$v];
- }
- return $newOptions;
- }
- return $options;
- }
- }
|