/// <summary> /// Определяет, является ли указанное название файла валидным /// </summary> /// <param name="Input"></param> /// <returns></returns> public static Boolean IsValidFilename(String Input) { if (Input.HasVisibleChars() == false) { return false; } if (Input.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) { return false; } if (Input.Length > MAX_FILENAME) { return false; } if (Input.EndsWith(" ", StringComparison.InvariantCultureIgnoreCase) == true) { return false; } String part = Input.Trim().Split(new char[1] { '.' }, StringSplitOptions.RemoveEmptyEntries)[0].Trim(); if (part.IsIn(StringComparison.OrdinalIgnoreCase, FilePathTools.IllegalFilenames) == true) { return false; } return true; }
/// <summary> /// Определяет, является ли указанный путь валидным. Поддерживает абсолютные и относительные пути, с названиями файлов и без, а также названия файлов без путей /// </summary> /// <param name="Input"></param> /// <returns></returns> public static Boolean IsValidFilePath(String Input) { if (Input.HasVisibleChars() == false) { return false; } if (Input.IndexOfAny(Path.GetInvalidPathChars()) >= 0) { return false; } if(Input.Length >= MAX_PATH) {return false; } String[] parts = Input.Split(new char[1] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries); for (Int32 i = 0; i < parts.Length - 1; i++) { String current = parts[i]; if (i < parts.Length - 1) { if(current.Length >= MAX_DIRECTORYNAME) {return false; } } if (current.HasVisibleChars() == false) { return false; } String first_part = current.Trim().Split(new char[1] { '.' }, StringSplitOptions.RemoveEmptyEntries)[0]; if (first_part.Trim().IsIn(StringComparison.OrdinalIgnoreCase, IllegalFilenames) == true) { return false; } } return FilePathTools.IsValidFilename(parts[parts.Length - 1]); }
/// <summary> /// Устанавливает новое или дополняет существующее текстовое сообщение о выполнении процесса /// </summary> /// <param name="SetOrAppend">true - set; false - append</param> /// <param name="Message"></param> private void SetOrAppendMessage(Boolean SetOrAppend, String Message) { if (this.rtb_DownloadFailed.InvokeRequired == false) { if (SetOrAppend == true) { this.rtb_DownloadFailed.Text = Message.IsStringNullEmptyWhiteSpace() == true ? "" : Message; } else { if (Message.HasVisibleChars() == false) {return;} this.rtb_DownloadFailed.Text = this.rtb_DownloadFailed.Text + "\r\n" + Message; } } else { this.rtb_DownloadFailed.Invoke((Action<Boolean, String>) this.SetOrAppendMessage, SetOrAppend, Message); } }
/// <summary> /// Защищает входную строку от SQL-инъекции, экранируя одинарные кавычки /// </summary> /// <param name="Input"></param> /// <returns></returns> public static String SecureSQLQuery(String Input) { if (Input.HasVisibleChars() == false) { return Input; } String output = Input.Replace("'", "''"); return output; }
public Boolean HasVisibleCharsTest(String input) { return input.HasVisibleChars(); }
/// <summary> /// Пытается очистить указанную строку, представляющую название файла (без пути), от недопустимых символов, если таковые присутствуют. /// Если очистка успешна, возвращает 'true' и очищенное коректное имя файла через выводной параметр. /// Если же указанную строку невозможно очистить, возвращает 'false' и NULL через выводной параметр. /// </summary> /// <param name="Input">Строка, представляющая имя файла без пути</param> /// <param name="FixedFilename">Выводной параметр, содержащий очищенное имя файла, если его удалось очистить</param> /// <returns></returns> public static Boolean TryCleanFilename(String Input, out String FixedFilename) { FixedFilename = null; if (Input.HasVisibleChars() == false) { return false; } StringBuilder sb = new StringBuilder(Input.Length); Char[] invalid_chars = Path.GetInvalidFileNameChars(); foreach (Char current in Input) { if (current.IsIn(invalid_chars) == false) { sb.Append(current); } } String output = sb.Trim().ToString(); if (output.HasVisibleChars() == false) { return false; } String[] all_segments = output.Split(new char[1] { '.' }, StringSplitOptions.RemoveEmptyEntries); String first_segment = all_segments.First(); if (first_segment.IsIn(StringComparison.OrdinalIgnoreCase, FilePathTools.IllegalFilenames) == true) { if (all_segments.Length < 3) { return false; } else { output = output.TrimStart(first_segment + ".", StringComparison.OrdinalIgnoreCase, false); } } FixedFilename = output; return true; }
/// <summary> /// Возвращает количество цифр, которые присутствуют во входной строке /// </summary> /// <param name="Input"></param> /// <returns></returns> public static UInt16 GetNumberOfDigits(String Input) { if (Input.HasVisibleChars() == false) { return 0; } UInt16 digits_count = 0; foreach (Char c in Input) { if (Char.IsDigit(c) == true) { digits_count++; } } return digits_count; }
/// <summary> /// Возвращает одно ближайшее целое положительное число, извлечённое из начала или конца входной строки. /// В зависимости от параметра RaiseException, если входная строка некорректная или в ней не найдено ни одной цифры, метод выбрасывает исключение или возвращает NULL. /// </summary> /// <param name="Input">Входная строка</param> /// <param name="Dir">Направление, по которому ищется число: с начала входной строки или с конца</param> /// <param name="RaiseException">Если true - при некорректной строке или ненахождении числа выбрасывается исключение; если false - возвращается NULL</param> /// <returns>Целое положительное число или NULL (если RaiseException = false)</returns> /// <exception cref="ArgumentException">Параметр RaiseException выставлен в true и входня строка пуста или не содержит ни одной цифры</exception> /// <exception cref="InvalidEnumArgumentException">Значение перечисления направления находится некорректно</exception> public static Nullable<UInt32> GetNearestUnsignedIntegerFromString(String Input, StringTools.Direction Dir, Boolean RaiseException) { if (Input.HasVisibleChars() == false) { if (RaiseException == true) { throw new ArgumentException("Входная строка не может быть NULL, пустой или не содержать ни одного видимого символа", "Input"); } else { return null; } } Char[] input_array = Input.ToCharArray(); Boolean found = false; String number = String.Empty; switch (Dir) { case StringTools.Direction.FromStartToEnd: foreach (Char symbol in input_array) { if (Char.IsDigit(symbol) == true) { number = number + symbol.ToString(); found = true; } else if (Char.IsDigit(symbol) == false && found == true) { break; } } { UInt32 result; if (UInt32.TryParse(number, out result) == true) { return result; } else { if (RaiseException == true) { throw new ArgumentException("Входная строка не содержит ни одной цифры", "Input"); } else { return null; } } } case StringTools.Direction.FromEndToStart: for (Int32 i = input_array.Length - 1; i >= 0; i--) { if (Char.IsDigit(input_array[i]) == true) { number = input_array[i] + number; found = true; } else if (Char.IsDigit(input_array[i]) == false && found == true) { break; } } { UInt32 result; if (UInt32.TryParse(number, out result) == true) { return result; } else { if (RaiseException == true) { throw new ArgumentException("Входная строка не содержит ни одной цифры", "Input"); } else { return null; } } } default: throw new InvalidEnumArgumentException("Dir", (Int32)Dir, Dir.GetType()); } }
/// <summary> /// Экранирует во входной строке все тэги <script> и </script> для защиты от самых распространённых XSS-инъекций. /// </summary> /// <param name="InputHTML"></param> /// <returns></returns> public static String SecureScriptXSS(String InputHTML) { if (InputHTML.HasVisibleChars() == false) { return InputHTML; } if (StringTools.ContainsHelpers.ContainsAllOf(InputHTML, new char[] { '<', '>' }) == false) { return InputHTML; } List<Substring> tags_with_positions = StringTools.SubstringHelpers.GetInnerStringsBetweenTokens(InputHTML, "<", ">", 0, false, StringComparison.OrdinalIgnoreCase); if (tags_with_positions.Any() == false) { return InputHTML; } StringBuilder output = new StringBuilder(InputHTML.Length); Int32 start_position = 0; foreach (Substring one_possible_tag in tags_with_positions) { String tag_name; HtmlTools.HtmlTagType tag_type = HtmlTools.ValidateHtmlTag("<" + one_possible_tag.Value + ">", out tag_name); if (tag_type == HtmlTagType.NotTag || tag_name.Equals("script", StringComparison.OrdinalIgnoreCase) == false) { output.Append(InputHTML.SubstringWithEnd(start_position, one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1)); } else { if (tag_type == HtmlTagType.PairOpen) { output.Append(InputHTML.Substring(start_position, one_possible_tag.StartIndex - 1 - start_position)); output.Append("<script>"); } else if (tag_type == HtmlTagType.PairClose) { output.Append(InputHTML.Substring(start_position, one_possible_tag.StartIndex - 1 - start_position)); output.Append("</script>"); } else if (tag_type == HtmlTagType.Single) { output.Append(InputHTML.Substring(start_position, one_possible_tag.StartIndex - 1 - start_position)); output.Append("<script/>"); } else { throw new UnreachableCodeException(); } } start_position = one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1; } output.Append(InputHTML.Substring(start_position)); return output.ToString(); }
/// <summary> /// Конвертирует указанную строку в HTML-совместимую форму, заменяя пробельные отступы и символы переноса, а также кодируя HTML-тэги, защищая клиент от атак XSS /// </summary> /// <param name="InputHTML"></param> /// <returns></returns> public static String AdjustTextToHtml(String InputHTML) { if (InputHTML.HasVisibleChars() == false) { return InputHTML; } InputHTML = HttpUtility.HtmlEncode(InputHTML); const Char ordinal_space = ' '; const Char carriage_return = '\r'; const Char new_line = '\n'; const String combined_enter = "\r\n"; const String html_space = " "; const String html_enter = "<br/>"; String temp = InputHTML .Replace(combined_enter, html_enter) .Replace(carriage_return.ToString(), html_enter) .Replace(new_line.ToString(), html_enter); StringBuilder output = new StringBuilder(temp.Length); Int32 start_spaces = StringTools.StringAnalyzers.StartWithCount(temp, ordinal_space); Int32 start_index; if (start_spaces == 0) { start_index = 0; } else { output.Append(html_space.Replicate((UInt16)start_spaces)); start_index = start_spaces; } Int32 found_spaces_count = 0; for (Int32 i = start_index; i < temp.Length; i++) { Char ch = temp[i]; if (ch.Equals(ordinal_space) || Char.IsWhiteSpace(ch) == true) { found_spaces_count = found_spaces_count + 1; continue; } if (found_spaces_count > 1) { output.Append(html_space.Replicate(found_spaces_count) + ch.ToString()); found_spaces_count = 0; continue; } if (found_spaces_count == 1) { output.Append(ordinal_space.ToString() + ch.ToString()); found_spaces_count = 0; continue; } //found_spaces_count == 0 output.Append(ch); } return output.ToString(); }
/// <summary> /// Удаляет из входной строки все парные HTML-тэги со всеми их атрибутами, которые не содержат внутри контента. /// HTML-тэги, содержащие вложенные пустые тэги, также удаляются. Одиночные тэги не удаляются. /// </summary> /// <param name="InputHTML">Входная строка</param> /// <returns>Новая очищенная от пустых парных тэгов строка</returns> public static String RemoveEmptyPairHTMLTags(String InputHTML) { if (InputHTML.HasVisibleChars() == false) { return InputHTML; } const Char opening_bracket = '<'; const Char closing_bracket = '>'; const String closing_token = "</"; const Char space = ' '; StringBuilder output = new StringBuilder(InputHTML.Length); Int32 offset = 0; while (true) { Int32 index_of_opening_bracket_opening_tag = InputHTML.IndexOf(opening_bracket, offset); if (index_of_opening_bracket_opening_tag == -1) { break; } Int32 index_of_closing_bracket_opening_tag = InputHTML.IndexOf(closing_bracket, index_of_opening_bracket_opening_tag + 1); if (index_of_closing_bracket_opening_tag == -1) { break; } String opening_tag = InputHTML.SubstringWithEnd(index_of_opening_bracket_opening_tag + 1, index_of_closing_bracket_opening_tag).Trim(); if (opening_tag.Contains(space) == true) { opening_tag = opening_tag.Split(new Char[1] { space }, StringSplitOptions.RemoveEmptyEntries)[0]; } Int32 index_of_opening_bracket_closing_tag = InputHTML.IndexOf(closing_token + opening_tag, index_of_closing_bracket_opening_tag + 1, StringComparison.OrdinalIgnoreCase); if (index_of_opening_bracket_closing_tag == -1) { String temp = InputHTML.SubstringWithEnd(offset, index_of_closing_bracket_opening_tag + 1); output.Append(temp); offset = index_of_closing_bracket_opening_tag + 1; continue; } Int32 index_of_closing_bracket_closing_tag = InputHTML.IndexOf(closing_bracket, index_of_opening_bracket_closing_tag + 1); if (index_of_closing_bracket_closing_tag == -1) { break; } #if Debug String closing_tag = InputHTML.SubstringWithEnd(index_of_opening_bracket_closing_tag + 2, index_of_closing_bracket_closing_tag).Trim(); #endif String between_offset_and_opening_tag = InputHTML.SubstringWithEnd(offset, index_of_opening_bracket_opening_tag); output.Append(between_offset_and_opening_tag); String inner = InputHTML.SubstringWithEnd(index_of_closing_bracket_opening_tag + 1, index_of_opening_bracket_closing_tag); if (inner.HasVisibleChars() == true) { String temp = RemoveEmptyPairHTMLTags(inner); if (temp.HasVisibleChars() == true) { String temp2 = InputHTML.SubstringWithEnd(index_of_opening_bracket_opening_tag, index_of_closing_bracket_opening_tag + 1) + temp + InputHTML.SubstringWithEnd(index_of_opening_bracket_closing_tag, index_of_closing_bracket_closing_tag + 1); output.Append(temp2); } } offset = index_of_closing_bracket_closing_tag + 1; } if (offset == 0) { output.Append(InputHTML); } else if (offset > 0 && offset < InputHTML.Length) { output.Append(InputHTML.Substring(offset + 1)); } String result = output.ToString(); return result; }
/// <summary> /// Удаляет из входной строки все одинарные и парные HTML-тэги с их атрибутами, оставляя их содержимое. Если входная строка не содержит HTML-тэгов, метод возвращает её без изменений. /// Удаляются также некорректно расположенные HTML-тэги (неоткрытые, незакрытые и перехлестывающиеся). Заменяет все HTML-пробелы и переносы строк на их символьные аналоги. /// </summary> /// <param name="InputHTML">Входная HTML-содержащая строка</param> /// <returns>Копия входной строки, не содержащая никаких HTML-тегов</returns> public static String IntelliRemoveHTMLTags(String InputHTML) { if (InputHTML.HasVisibleChars() == false) { return InputHTML; } if (StringTools.ContainsHelpers.ContainsAllOf(InputHTML, new char[] { '<', '>' }) == false) { return InputHTML; } List<Substring> tags_with_positions = StringTools.SubstringHelpers.GetInnerStringsBetweenTokens (InputHTML, "<", ">", 0, false, StringComparison.OrdinalIgnoreCase); if (tags_with_positions.Any() == false) { return InputHTML; } const String combined_enter = "\r\n", space = " "; StringBuilder temp = new StringBuilder(InputHTML.Length); Int32 start_position = 0; foreach (Substring one_possible_tag in tags_with_positions) { if (start_position < one_possible_tag.StartIndex - 1) { temp.Append(InputHTML.SubstringWithEnd(start_position, one_possible_tag.StartIndex - 1, true, false, true)); } if (one_possible_tag.Value.Contains("br", StringComparison.OrdinalIgnoreCase)==true && StringTools.ContainsHelpers.ContainsOnlyAllowed(one_possible_tag.Value, new char[] { ' ', '/', 'b', 'r', 'B', 'R' }) == true) { temp.Append(combined_enter); } start_position = one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1; } String temp2 = InputHTML.Substring(start_position); if (temp2.HasVisibleChars() == true) { String temp3 = StringTools.SubstringHelpers.GetSubstringToToken(temp2, "<", false, StringTools.Direction.FromStartToEnd, StringComparison.OrdinalIgnoreCase); temp.Append(temp3); } else { temp.Append(temp2); } temp.Replace(" ", space).Replace(" ", space); return temp.ToString(); }
/// <summary> /// Удаляет из входной строки все одинарные и парные HTML-тэги с их атрибутами, оставляя их содержимое. Если входная строка не содержит HTML-тэгов, метод возвращает её без изменений. /// Удаляются также некорректно расположенные HTML-тэги (неоткрытые, незакрытые и перехлестывающиеся). /// </summary> /// <param name="InputHTML">Входная HTML-содержащая строка</param> /// <returns>Копия входной строки, не содержащая никаких HTML-тегов</returns> public static String RemoveHTMLTags(String InputHTML) { if (InputHTML.HasVisibleChars() == false) { return InputHTML; } List<Substring> tags_with_positions = StringTools.SubstringHelpers.GetInnerStringsBetweenTokens(InputHTML, "<", ">", 0, false, StringComparison.OrdinalIgnoreCase); if (tags_with_positions.Any() == false || tags_with_positions.TrueForAll((Substring item) => item == null)) { return InputHTML; } StringBuilder temp = new StringBuilder(InputHTML.Length); Int32 start_position = 0; foreach (Substring one_possible_tag in tags_with_positions) { if (one_possible_tag == null) { continue; } if (CommonTools.AreAllEqual<Int32>(start_position, one_possible_tag.StartIndex - 1, 0) == true || start_position == one_possible_tag.StartIndex - 1) { start_position = one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1; continue; } temp.Append(InputHTML.SubstringWithEnd(start_position, one_possible_tag.StartIndex - 1, true, false, true)); start_position = one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1; } String temp2 = InputHTML.Substring(start_position); if (temp2.HasVisibleChars() == true && StringTools.ContainsHelpers.ContainsAllOf(temp2, new char[] { '<', '>' }) == false) { String temp3 = StringTools.SubstringHelpers.GetSubstringToToken(temp2, "<", false, StringTools.Direction.FromStartToEnd, StringComparison.OrdinalIgnoreCase); temp.Append(temp3); } else { temp.Append(temp2); } return temp.ToString(); }