Version 4.1.19
This commit is contained in:
1 parent
28bd025b35
commit
2bd5025018
2674 files changed
+233518
-77766
No files matched your search
+121
-35
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Text input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -39,7 +39,7 @@ class _Text extends TextArea
|
||||
'unique' => TRUE, // Specifies if the values must be unique
|
||||
'forceLower' => TRUE, // If TRUE, all values will be converted to lowercase
|
||||
'minLength' => 5, // The minimum length of each tag (characters) - if not specified, will be unlimited
|
||||
'maxLength' => 10, // The minimum length of each tag (characters) - if not specified, will be unlimited
|
||||
'maxLength' => 10, // The maximum length of each tag (characters) - if not specified, will be unlimited
|
||||
'prefix' => TRUE, // If TRUE, user will have option to specify one tag as a prefix
|
||||
'resultItemTemplate'=> 'core.foo.bar', // Can be used to specify a custom JavaScript template to use for the result
|
||||
'minAjaxLength' => 3, // Minimum length of value before sending AJAX lookup call
|
||||
@@ -50,6 +50,7 @@ class _Text extends TextArea
|
||||
'nullLang' => 'no_value', // If provided, an "or X" checkbox will appear with X being the value of this language key. When checked, NULL will be returned as the value.
|
||||
'accountUsername' => TRUE, // If TRUE or an \IPS\Member, additional checks will be performed to ensure provided value is acceptable for use as a username. Pass an \IPS\Member object to exclude that member from the duplicate checks
|
||||
'trim' => TRUE, // If TRUE (which is the default), whitespace will be stripped from the start and end of the value
|
||||
'bypassProfanity' => FALSE, // If TRUE, profanity filter will be bypassed when it is not appropriate to do so (ex: on the login form). Defaults to FALSE.
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
@@ -64,6 +65,7 @@ class _Text extends TextArea
|
||||
'nullLang' => NULL,
|
||||
'accountUsername' => FALSE,
|
||||
'trim' => TRUE,
|
||||
'bypassProfanity' => FALSE,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -92,11 +94,12 @@ class _Text extends TextArea
|
||||
$args = func_get_args();
|
||||
if ( isset( $args[3]['accountUsername'] ) and $args[3]['accountUsername'] !== FALSE )
|
||||
{
|
||||
$args[3]['minLength'] = \IPS\Settings::i()->min_user_name_length;
|
||||
$args[3]['maxLength'] = \IPS\Settings::i()->max_user_name_length;
|
||||
|
||||
if ( \IPS\Settings::i()->username_characters )
|
||||
{
|
||||
$args[3]['regex'] = '/^[' . str_replace( '\-', '-', preg_quote( \IPS\Settings::i()->username_characters, '/' ) ) . ']*$/i';
|
||||
$args[3]['regex'] = '/^[' . str_replace( '\-', '-', preg_quote( \IPS\Settings::i()->username_characters, '/' ) ) . ']*$/iu';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +128,7 @@ class _Text extends TextArea
|
||||
{
|
||||
/* 10/19/15 - adding htmlspecialchars around value if autocomplete is enabled so that html tag characters can be used (e.g. for members) */
|
||||
/* This value is decoded by the JS widget before use. See https://community.invisionpower.com/4bugtrack/active-reports/cannot-pm-certain-members-r6181/ */
|
||||
if( $this->options['autocomplete'] and !empty( $this->value ) )
|
||||
if( $this->options['autocomplete'] and !empty( $this->value ) and is_array( $this->value ) )
|
||||
{
|
||||
foreach( $this->value as $key => $value )
|
||||
{
|
||||
@@ -168,18 +171,28 @@ class _Text extends TextArea
|
||||
if ( isset( $this->options['autocomplete'] ) )
|
||||
{
|
||||
$return = htmlspecialchars_decode( $return, ENT_QUOTES );
|
||||
|
||||
if ( !is_array( $return ) )
|
||||
{
|
||||
$return = array_filter( explode( "\n", $return ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove all invisible characters */
|
||||
$return = preg_replace( '/\p{C}+/u', '', $return );
|
||||
if ( !is_array( $return ) )
|
||||
{
|
||||
$return = preg_replace( '/\p{C}+/u', '', $return );
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( $return as $k => $v )
|
||||
{
|
||||
$return = preg_replace( '/\p{C}+/u', '', $return );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $this->options['autocomplete']['prefix'] ) and $this->options['autocomplete']['prefix'] )
|
||||
{
|
||||
if ( !is_array( $return ) )
|
||||
{
|
||||
$return = array_filter( explode( ',', $return ) );
|
||||
}
|
||||
|
||||
$firstAsPrefix = $this->name . '_first_as_prefix';
|
||||
$freechoicePrefixCheckbox = $this->name . '_freechoice_prefix';
|
||||
$freechoicePrefix = $this->name . '_prefix';
|
||||
@@ -220,7 +233,7 @@ class _Text extends TextArea
|
||||
{
|
||||
if ( $this->options['autocomplete'] !== NULL and ( !isset( $this->options['autocomplete']['maxItems'] ) or $this->options['autocomplete']['maxItems'] != 1 ) and !is_array( $this->value ) and $this->value !== NULL )
|
||||
{
|
||||
return array_filter( array_map( 'trim', explode( ',', $this->value ) ) );
|
||||
return array_filter( array_map( 'trim', explode( "\n", $this->value ) ) );
|
||||
}
|
||||
|
||||
return $this->value;
|
||||
@@ -237,19 +250,37 @@ class _Text extends TextArea
|
||||
{
|
||||
parent::validate();
|
||||
|
||||
/* skip validation if it's an username field and if the name wasn't changed */
|
||||
if ( $this->options['accountUsername'] AND $this->options['accountUsername'] instanceOf \IPS\Member AND $this->options['accountUsername']->name == $this->value )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( \IPS\Dispatcher::i() instanceof \IPS\Dispatcher\Front and !\IPS\Member::loggedIn()->group['g_bypass_badwords'] )
|
||||
{
|
||||
$looseProfanity = array();
|
||||
$exactProfanity = array();
|
||||
|
||||
/* Set up profanity filters */
|
||||
$exactProfanity = iterator_to_array( \IPS\Db::i()->select( '*', 'core_profanity_filters', array('m_exact=?', TRUE) )->setKeyField( 'type' )->setValueField( 'swop' ) );
|
||||
$looseProfanity = iterator_to_array( \IPS\Db::i()->select( '*', 'core_profanity_filters', array('m_exact=?', FALSE) )->setKeyField( 'type' )->setValueField( 'swop' ) );
|
||||
foreach( \IPS\core\Profanity::getProfanity() AS $profanity )
|
||||
{
|
||||
if ( $profanity->m_exact )
|
||||
{
|
||||
$exactProfanity[ $profanity->type ] = $profanity;
|
||||
}
|
||||
else
|
||||
{
|
||||
$looseProfanity[ $profanity->type ] = $profanity;
|
||||
}
|
||||
}
|
||||
|
||||
foreach( $exactProfanity as $key => $value )
|
||||
{
|
||||
$exactProfanity[mb_strtolower( $key )] = $value;
|
||||
$exactProfanity[ mb_strtolower( $key ) ] = $value;
|
||||
}
|
||||
|
||||
/* Construct break points */
|
||||
$breakPoints = array();
|
||||
$exactProfanityBreakpoints = array();
|
||||
if( count( $exactProfanity ) )
|
||||
{
|
||||
$array = array();
|
||||
@@ -259,7 +290,7 @@ class _Text extends TextArea
|
||||
}
|
||||
|
||||
/* @note: We use \b because of http://community.invisionpower.com/resources/bugs.html/_/4-0-0/anacronym-doesnt-work-in-middle-of-a-phrase-r47612 */
|
||||
$breakPoints[] = '((?=<^|\b)(?:' . implode( '|', $array ) . ')(?=\b|$))';
|
||||
$exactProfanityBreakpoints[] = '((?=<^|\b)(?:' . implode( '|', $array ) . ')(?=\b|$))';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,11 +346,11 @@ class _Text extends TextArea
|
||||
|
||||
if ( isset( $this->options['autocomplete']['maxItems'] ) and count( $values ) > $this->options['autocomplete']['maxItems'] )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_max', FALSE, array( 'pluralize' => $this->options['autocomplete']['maxItems'] ) ) );
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_max', FALSE, array( 'pluralize' => array( $this->options['autocomplete']['maxItems'] ) ) ) );
|
||||
}
|
||||
if ( isset( $this->options['autocomplete']['minItems'] ) and ( $this->required or count( $values ) > 0 ) and count( $values ) < $this->options['autocomplete']['minItems'] )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_min', FALSE, array( 'pluralize' => $this->options['autocomplete']['minItems'] ) ) );
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_min', FALSE, array( 'pluralize' => array( $this->options['autocomplete']['minItems'] ) ) ) );
|
||||
}
|
||||
|
||||
if ( isset( $this->options['autocomplete']['minLength'] ) )
|
||||
@@ -338,7 +369,7 @@ class _Text extends TextArea
|
||||
{
|
||||
if ( mb_strlen( $v ) > $this->options['autocomplete']['maxLength'] )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_length_max', FALSE, array( 'pluralize' => $this->options['autocomplete']['maxLength'] ) ) );
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_length_max', FALSE, array( 'pluralize' => array( $this->options['autocomplete']['maxLength'] ) ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,11 +379,35 @@ class _Text extends TextArea
|
||||
{
|
||||
if ( array_key_exists( $v, $exactProfanity ) )
|
||||
{
|
||||
$this->value[ $k ] = $exactProfanity[ $v ];
|
||||
if ( $exactProfanity[ $v ]->action == 'swap' )
|
||||
{
|
||||
$this->value[ $k ] = $exactProfanity[ $v ]->swop;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \DomainException( 'Profanity Filter' ); // @todo proper lang string
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->value[ $k ] = str_replace( array_keys( $looseProfanity ), array_values( $looseProfanity ), $v );
|
||||
$swaps = array();
|
||||
foreach( $looseProfanity AS $type => $row )
|
||||
{
|
||||
if ( $row->action == 'swap' )
|
||||
{
|
||||
$swaps[ $row->type ] = $row->swop;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mb_stristr( $value, $type ) )
|
||||
{
|
||||
throw new \DomainException( 'Profanity Filter' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Still here? Normal swaps. */
|
||||
$this->value[ $k ] = str_ireplace( array_keys( $swaps ), array_values( $swaps ), $this->value[ $k ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,34 +424,42 @@ class _Text extends TextArea
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_array ( $this->value ) AND isset( $this->options['autocomplete']['source'] ) AND is_array( $this->options['autocomplete']['source'] ) AND !$this->options['autocomplete']['freeChoice'] )
|
||||
if ( is_array ( $this->value ) AND isset( $this->options['autocomplete']['source'] ) AND is_array( $this->options['autocomplete']['source'] ) AND ( !isset( $this->options['autocomplete']['freeChoice'] ) OR !$this->options['autocomplete']['freeChoice'] ) )
|
||||
{
|
||||
$this->value = array_uintersect( $this->value, $this->options['autocomplete']['source'], function( $a, $b ){
|
||||
return ( mb_strtolower( $a ) === mb_strtolower( $b ) );
|
||||
} );
|
||||
if( isset( $this->options['autocomplete']['forceLower'] ) AND $this->options['autocomplete']['forceLower'] )
|
||||
{
|
||||
$this->value = array_uintersect( array_map( 'mb_strtolower', $this->value ), array_map( 'mb_strtolower', $this->options['autocomplete']['source'] ), 'strcasecmp' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->value = array_uintersect( $this->value, $this->options['autocomplete']['source'], 'strcasecmp' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Split on profanity */
|
||||
if( is_string( $this->value ) and \IPS\Dispatcher::i() instanceof \IPS\Dispatcher\Front and !\IPS\Member::loggedIn()->group['g_bypass_badwords'] )
|
||||
if( $this->options['bypassProfanity'] === FALSE and is_string( $this->value ) and \IPS\Dispatcher::i() instanceof \IPS\Dispatcher\Front and !\IPS\Member::loggedIn()->group['g_bypass_badwords'] )
|
||||
{
|
||||
$newVal = NULL;
|
||||
if ( count( $breakPoints ) )
|
||||
if ( count( $exactProfanityBreakpoints ) )
|
||||
{
|
||||
/* preg_split can return boolean false*/
|
||||
$split = preg_split( '/' . implode( '|', $breakPoints ) . '/iu', $this->value, null, PREG_SPLIT_DELIM_CAPTURE );
|
||||
$split = preg_split( '/' . implode( '|', $exactProfanityBreakpoints ) . '/iu', $this->value, null, PREG_SPLIT_DELIM_CAPTURE );
|
||||
|
||||
if( is_array( $split ) )
|
||||
{
|
||||
foreach ( $split as $section )
|
||||
{
|
||||
/* Replace loose profanity */
|
||||
$section = str_ireplace( array_keys( $looseProfanity ), array_values( $looseProfanity ), $section );
|
||||
|
||||
if ( isset( $exactProfanity[ mb_strtolower( $section ) ] ) )
|
||||
{
|
||||
$newVal .= $exactProfanity[ mb_strtolower( $section ) ];
|
||||
|
||||
if ( $exactProfanity[ mb_strtolower( $section ) ]->action == 'swap' )
|
||||
{
|
||||
$newVal .= $exactProfanity[ mb_strtolower( $section ) ]->swop;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \DomainException( 'Profanity Filter' );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -405,8 +468,31 @@ class _Text extends TextArea
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$value = $newVal ?: $this->value;
|
||||
|
||||
if ( count( $looseProfanity ) )
|
||||
{
|
||||
$swaps = array();
|
||||
foreach( $looseProfanity AS $type => $row )
|
||||
{
|
||||
if ( $row->action == 'swap' )
|
||||
{
|
||||
$swaps[ $row->type ] = $row->swop;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mb_stristr( $value, $type ) )
|
||||
{
|
||||
throw new \DomainException( 'Profanity Filter' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$value = str_ireplace( array_keys( $swaps ), array_values( $swaps ), $value );
|
||||
}
|
||||
|
||||
$this->value = $newVal ?: $this->value;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
Reference in new issue
Block a user