3 ? 2 : 1; if ( $length + $units > $limit ) { break; } $result .= $character; $length += $units; } return $result; } public static function sanitize( $clean, $raw ) { $text = in_array( $clean['type'], array( 'text', 'email', 'tel', 'url', 'textarea' ), true ); if ( isset( $raw['autocomplete'] ) && '' !== $raw['autocomplete'] ) { $allowed = array( 'off', 'on', 'name', 'given-name', 'family-name', 'nickname', 'email', 'tel', 'organization', 'organization-title', 'url', 'street-address', 'address-line1', 'address-line2', 'address-level1', 'address-level2', 'postal-code', 'country-name', 'bday' ); if ( ( ! $text && 'date' !== $clean['type'] ) || ! is_string( $raw['autocomplete'] ) || ! in_array( $raw['autocomplete'], $allowed, true ) ) { return self::error(); } $clean['autocomplete'] = $raw['autocomplete']; } if ( ! isset( $raw['validation'] ) ) { return $clean; } $input = $raw['validation']; if ( ! is_array( $input ) || count( $input ) > 5 ) { return self::error(); } $rules = array(); if ( $text ) { $ceiling = 'textarea' === $clean['type'] ? 10000 : 1000; foreach ( array( 'min_length' => 0, 'max_length' => $ceiling ) as $key => $fallback ) { $value = isset( $input[ $key ] ) ? $input[ $key ] : $fallback; if ( ! is_int( $value ) || $value < 0 || $value > $ceiling || ( 'max_length' === $key && 0 === $value ) ) { return self::error(); } $rules[ $key ] = $value; } if ( $rules['min_length'] > $rules['max_length'] ) { return self::error(); } } elseif ( in_array( $clean['type'], array( 'number', 'date', 'time' ), true ) ) { foreach ( array( 'min', 'max' ) as $key ) { $value = isset( $input[ $key ] ) ? $input[ $key ] : ''; if ( ! is_string( $value ) || strlen( $value ) > 40 ) { return self::error(); } if ( '' !== $value && ( ( 'number' === $clean['type'] && ( ! is_numeric( $value ) || ! is_finite( (float) $value ) ) ) || ( 'date' === $clean['type'] && ! KCONV_Core::valid_date( $value ) ) || ( 'time' === $clean['type'] && ! preg_match( '/^(?:[01]\d|2[0-3]):[0-5]\d$/D', $value ) ) ) ) { return self::error(); } $rules[ $key ] = $value; } if ( '' !== $rules['min'] && '' !== $rules['max'] && ( 'number' === $clean['type'] ? KCONV_Conditions::compare_numbers( $rules['min'], $rules['max'] ) > 0 : strcmp( $rules['min'], $rules['max'] ) > 0 ) ) { return self::error(); } if ( 'number' === $clean['type'] ) { $step = isset( $input['step'] ) ? $input['step'] : 'any'; if ( ! is_string( $step ) || strlen( $step ) > 40 || ( 'any' !== $step && ( ! is_numeric( $step ) || ! is_finite( (float) $step ) || (float) $step <= 0 ) ) ) { return self::error(); } $rules['step'] = $step; } } else { return self::error(); } $clean['validation'] = $rules; return $clean; } public static function attributes( $field ) { $attributes = ''; if ( ! empty( $field['autocomplete'] ) ) { $attributes .= ' autocomplete="' . esc_attr( $field['autocomplete'] ) . '"'; } $rules = isset( $field['validation'] ) ? $field['validation'] : array(); foreach ( array( 'min' => 'min', 'max' => 'max', 'step' => 'step', 'min_length' => 'minlength', 'max_length' => 'maxlength' ) as $key => $html ) { if ( isset( $rules[ $key ] ) && '' !== $rules[ $key ] ) { $attributes .= ' ' . $html . '="' . esc_attr( $rules[ $key ] ) . '"'; } } if ( 'number' === $field['type'] && ! isset( $rules['step'] ) ) { $attributes .= ' step="any"'; } if ( in_array( $field['type'], array( 'text', 'email', 'tel', 'url', 'textarea' ), true ) && ! isset( $rules['max_length'] ) ) { $attributes .= ' maxlength="' . ( 'textarea' === $field['type'] ? '10000' : '1000' ) . '"'; } return $attributes; } public static function validate( $field, $value ) { if ( '' === $value || ! isset( $field['validation'] ) ) { return ''; } $rules = $field['validation']; /* translators: %d: minimum number of characters. */ if ( isset( $rules['min_length'] ) && self::length( $value ) < $rules['min_length'] ) { return sprintf( __( 'Use at least %d characters.', 'killerconversions' ), $rules['min_length'] ); } /* translators: %d: maximum number of characters. */ if ( isset( $rules['max_length'] ) && self::length( $value ) > $rules['max_length'] ) { return sprintf( __( 'Use no more than %d characters.', 'killerconversions' ), $rules['max_length'] ); } $number = 'number' === $field['type']; foreach ( array( 'min', 'max' ) as $key ) { if ( ! isset( $rules[ $key ] ) || '' === $rules[ $key ] ) { continue; } $comparison = $number ? KCONV_Conditions::compare_numbers( $value, $rules[ $key ] ) : strcmp( $value, $rules[ $key ] ); /* translators: %s: inclusive minimum or maximum field value. */ if ( ( 'min' === $key && $comparison < 0 ) || ( 'max' === $key && $comparison > 0 ) ) { return sprintf( 'min' === $key ? __( 'Use a value of %s or greater.', 'killerconversions' ) : __( 'Use a value of %s or less.', 'killerconversions' ), $rules[ $key ] ); } } if ( $number && isset( $rules['step'] ) && 'any' !== $rules['step'] ) { $base = isset( $rules['min'] ) && '' !== $rules['min'] ? $rules['min'] : '0'; /* translators: %s: allowed number increment. */ if ( ! KCONV_Conditions::step_matches( $value, $base, $rules['step'] ) ) { return sprintf( __( 'Use increments of %s from the minimum, or from zero when no minimum is set.', 'killerconversions' ), $rules['step'] ); } } return ''; } private static function error() { return new WP_Error( 'field_constraints', __( 'Check field limits and autofill settings. Minimums must not exceed maximums; number steps must be positive.', 'killerconversions' ) ); } }