<?php
/**
* @version	$Id: password_formatter.php 13043 2010-01-07 20:59:33Z dmitrya $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

class kPasswordFormatter extends kFormatter
{

	function PrepareOptions($field_name, &$field_options, &$object)
	{
		if ( isset( $field_options['verify_field'] ) ) {
			$add_fields = Array ();
			$options = Array ('master_field' => $field_name, 'formatter' => 'kPasswordFormatter');

			$copy_options = Array ('encryption_method', 'salt', 'required', 'skip_empty');
			foreach ($copy_options as $copy_option) {
				if (array_key_exists($copy_option, $field_options)) {
					$options[$copy_option] = $field_options[$copy_option];
				}
			}

			$add_fields[ $field_options['verify_field'] ] = $options;

			$add_fields[$field_name.'_plain'] = Array('type'=>'string', 'error_field'=>$field_name);
			$add_fields[ $field_options['verify_field'].'_plain' ] = Array('type'=>'string', 'error_field'=>$field_options['verify_field'] );

			$add_fields = array_merge_recursive2($add_fields, $object->VirtualFields);
			$object->setVirtualFields($add_fields);
		}
	}

	function Format($value, $field_name, &$object, $format=null)
	{
		return $value;
	}

	/**
	 * Performs password & verify password field validation
	 *
	 * @param mixed $value
	 * @param string $field_name
	 * @param kDBItem $object
	 * @return string
	 */
	function Parse($value, $field_name, &$object)
	{
		$options = $object->GetFieldOptions($field_name);

		$flip_count = 0;
		$fields_set = true;
		$fields = Array ('master_field', 'verify_field');

		// 1. collect values from both Password and VerifyPassword fields
		while ($flip_count < 2) {
			if ( getArrayValue($options, $fields[0]) ) {
				$object->SetDBField($field_name.'_plain', $value);

				if ( !getArrayValue($object->Fields[ $options[ $fields[0] ] ], $fields[1].'_set') ) {
					$object->Fields[ $options[ $fields[0] ] ][$fields[1].'_set'] = true;
				}

				$password_field = $options[ $fields[0] ];
				$verify_field = $field_name;
			}

			$fields = array_reverse($fields);
			$flip_count++;
		}

		$salt = isset($object->Fields[$password_field]['salt']) ? $object->Fields[$password_field]['salt'] : '';

		if (getArrayValue($object->Fields[$password_field], 'verify_field_set') && getArrayValue($object->Fields[$verify_field], 'master_field_set')) {
			$new_password = $object->GetDBField($password_field . '_plain');
			$verify_password = $object->GetDBField($verify_field . '_plain');

			if ($new_password == '' && $verify_password == '') {
				// both passwords are empty -> keep old password
				if ($object->GetDBField($password_field) != $this->EncryptPassword('', $salt)) {
					if ($options['encryption_method'] == 'plain') {
						return $value;
					}

					return $this->EncryptPassword($value);
				}
				else {
					return $value;
				}
			}
			
			// determine admin or front
			$phrase_error_prefix = $this->Application->isAdmin ? 'la' : 'lu';

			if ($new_password != $verify_password) {
				// passwords don't match (no matter what is their length)				
				$object->SetError($verify_field, 'passwords_do_not_match', $phrase_error_prefix.'_passwords_do_not_match');
			}

			$min_length = $this->Application->ConfigValue('Min_Password'); // for error message too
			if (mb_strlen($new_password) < $min_length) {				
				$error_msg = '+' . sprintf($this->Application->Phrase($phrase_error_prefix.'_passwords_too_short'), $min_length); // + -> not phrase
				$object->SetError($password_field, 'passwords_min_length', $error_msg);
			}
		}

		if ($value == '') {
			return $object->GetDBField($field_name);
		}

		if ($options['encryption_method'] == 'plain') {
			return $value;
		}

		return $this->EncryptPassword($value, $salt);
	}

	function EncryptPassword($value, $salt=null)
	{
		if (!isset($salt) || !$salt) {
			// if empty salt, assume, that it's not passed at all
			return md5($value);
		}
		return md5(md5($value).$salt);
	}
}