PHP Regex для имен людей

У меня возникла небольшая проблема с регулярным выражением, которое я использую для имен людей.

$rexName = '/^[a-z' -]$/i';

Предположим, пользователь по имени Юрген хочет зарегистрироваться? Или Боб? Это довольно обычное дело в Европе. Есть ли для этого специальные обозначения?

РЕДАКТИРОВАТЬ: просто бросил имя Юрген против создателя регулярных выражений, и оно разбивает слово на букву ü...

http://www.txt2re.com/index.php3?s=J%FCrgen+Blalock&submit=Show+Matches

EDIT2: Хорошо, поскольку проверка таких конкретных вещей сложна, почему бы не использовать регулярное выражение, которое просто проверяет наличие недопустимых символов?

$rexSafety = "/^[^<,\"@/{}()*$%?=>:|;#]*$/i";

(теперь какие из них действительно могут быть использованы при любой попытке взлома?)

Например. Это позволяет ' и ​​- знаки, но вам нужен ; чтобы заставить его работать в SQL, и они будут остановлены. Любые другие символы, которые обычно используются для HTML-инъекций атак SQL, которые я пропустил?


person KdgDev    schedule 11.08.2009    source источник
comment
Просто не подтверждайте эту датум.   -  person Gumbo    schedule 11.08.2009
comment
Я тоже об этом задумывался...   -  person Meep3D    schedule 11.08.2009
comment
Я согласен с @Gumbo, вероятно, нет веской причины проверять символы в имени. Более подходящим решением может быть запуск поля против регулярного выражения черного списка, а не попытка принять белый список допустимых символов. Что происходит, когда 陳 пытается отправить вашу форму? Собираетесь ли вы иметь регулярное выражение с каждым международным символом в нем? :)   -  person Rob Hruska    schedule 11.08.2009


Ответы (4)


Я бы действительно сказал: не пытайтесь проверять имена: рано или поздно ваш код встретит имя, которое он считает «неправильным». >ваше имя неверно" ?

В зависимости от того, чего вы действительно хотите достичь, вы можете рассмотреть возможность использования какого-либо черного списка / фильтров, чтобы исключить «не-имена», о которых вы думали: это, возможно, пропустит некоторые «плохие имена», но, по крайней мере, это не должен препятствовать доступу любого существующего имени к вашему приложению.

Вот несколько примеров правил, которые приходят на ум:

  • нет номера
  • нет специального символа, например "~{()}@^$%?;:/*§£ø и, возможно, некоторых других
  • не более 3 пробелов?
  • none of "admin", "support", "moderator", "test", and a few other obvious non-names that people tend to use when they don't want to type in their real name...
    • (but, if they don't want to give you their name, their still won't, even if you forbid them from typing some random letters, they could just use a real name... Which is not their's)

Да, это не идеально; и да, это пропустит некоторые не имена... Но, вероятно, это намного лучше для вашего приложения, чем говорить кому-то "ваше имя неправильно" (да, я настаиваю ^^ )


И, чтобы ответить на комментарий, который вы оставили под другим ответом:

Я мог бы просто запретить большинство командных символов для SQL-инъекций и XSS-атак,

Что касается SQL-инъекций, вы должны экранировать свои данные перед отправкой их в базу данных; и, если вы всегда экранируете эти данные (вы должны!), вам не нужно заботиться о том, что пользователи могут вводить или нет: поскольку они всегда экранируются, для вас нет риска.

То же самое с XSS: поскольку вы всегда избегаете своих данных при их выводе (вы должны!), нет риска инъекции ;-)


EDIT: если вы просто используете это регулярное выражение, оно не будет работать достаточно хорошо:

Следующий код:

$rexSafety = "/^[^<,\"@/{}()*$%?=>:|;#]*$/i";
if (preg_match($rexSafety, 'martin')) {
    var_dump('bad name');
} else {
    var_dump('ok');
}

Вы получите хотя бы предупреждение:

Warning: preg_match() [function.preg-match]: Unknown modifier '{'

Вы должны экранировать по крайней мере некоторые из этих специальных символов; Я позволю вам изучить Шаблоны PCRE для получения дополнительной информации (здесь действительно много нужно знать о PCRE/регулярных выражениях, и я не смогу все объяснить)

Если вы действительно хотите проверить, что ни один из этих символов не находится внутри данного фрагмента данных, вы можете получить что-то вроде этого:

$rexSafety = "/[\^<,\"@\/\{\}\(\)\*\$%\?=>:\|;#]+/i";
if (preg_match($rexSafety, 'martin')) {
    var_dump('bad name');
} else {
    var_dump('ok');
}

(Это быстрое и грязное предложение, которое нужно уточнить!)

На этом написано "ОК" (ну, я очень надеюсь, что мое собственное имя подойдет!)
И тот же пример с некоторыми специальными символами, например:

$rexSafety = "/[\^<,\"@\/\{\}\(\)\*\$%\?=>:\|;#]+/i";
if (preg_match($rexSafety, 'ma{rtin')) {
    var_dump('bad name');
} else {
    var_dump('ok');
}

Скажет "плохое имя"

Но учтите, что я не полностью протестировал это, и, вероятно, требуется дополнительная работа! Не используйте это на своем сайте, если вы не протестировали его очень тщательно!


Также обратите внимание, что одинарная кавычка может быть полезна при попытке выполнить SQL-инъекцию... Но, вероятно, это символ, допустимый в некоторых именах... Таким образом, простого исключения некоторых символов может быть недостаточно ;-)

person Pascal MARTIN    schedule 11.08.2009
comment
Да, он будет экранирован... но все равно внесен в базу данных. Мне бы не понравилось, если бы на моем сайте была пара сотен профилей, не отображающих ничего, кроме кучи SQL-кода... - person KdgDev; 11.08.2009
comment
В этом случае может быть интересно добавить некоторые слова, такие как select, update, delete, where, order by и подобные вещи в черный список запрещенных слов; в конце концов, почти наверняка они не используются в именах ;-) ; И вы также можете сделать так, чтобы пользователь не мог регистрироваться слишком много раз (это не обязательно лучший вариант, довольно простая идея может состоять в том, чтобы установить ограничение на количество регистраций, которые могут происходить с одного IP-адреса в одном час, например) - person Pascal MARTIN; 11.08.2009
comment
Обновлен исходный пост с переменной rexSafety. - person KdgDev; 11.08.2009
comment
Возможно, лучше задать себе вопрос: какие персонажи ВСЕГДА нужны хакерам? Например, я могу разрешить одинарную кавычку и знак минус, но запретить = @ и ; Идея быть строкой, предназначенной для обхода безопасности, никогда не будет одним символом. Так что это процесс отсеивания: что общеупотребительно в человеческих именах, а что нет. Мне не нужно запрещать символ ', так как он всегда будет сопровождать знак @ или =. Это не на 100% правда, но я надеюсь, вы понимаете, к чему я клоню. - person KdgDev; 12.08.2009
comment
Единственная проблема с запретом символов: en.wikipedia.org/wiki/Prince_%28musician% 29 - person Thomas Owens; 14.08.2009

реализация PCRE на PHP поддерживает свойства символов Unicode, которые охватывают больший набор символов. Таким образом, вы можете использовать комбинацию \p{L} (буквы), \p{P} (знаки препинания) и \p{Zs} (символы-разделители):

/^[\p{L}\p{P}\p{Zs}]+$/

Но могут быть персонажи, которые не охватываются этими категориями персонажей, в то время как некоторые могут быть включены, которые вы не хотите разрешать.

Поэтому я советую вам не использовать регулярные выражения для данных с таким расплывчатым диапазоном значений, как имя реального человека.


Изменить   Поскольку вы отредактировали свой вопрос и теперь видите, что вы просто хотите предотвратить определенные атаки путем внедрения кода: вам лучше избегать этих символов, а не отвергать их как потенциальную попытку атаки.

Используйте mysql_real_escape_string или подготовленные операторы для запросов SQL, htmlspecialchars для вывода HTML и другие соответствующие функции для других языков.

person Gumbo    schedule 11.08.2009
comment
Я не только хочу предотвратить внедрение кода, я даже не хочу, чтобы экранированный код когда-либо попадал в базу данных. Как я уже говорил: представьте себе веб-сайт профиля пользователя (например, myspace). Представьте себе, что вы наткнулись на профиль с SQL-инъекциями. Все сбежали... Что за служба, к черту? Почему я должен позволять хакерам заполнять мою базу данных такой бесполезной чепухой, когда единственное, что они пытаются сделать, это взломать мой сайт? - person KdgDev; 11.08.2009

Это проблема, не имеющая простого общего решения. Дело в том, что вы действительно не можете предсказать, какие символы может содержать имя. Возможно, лучшим решением будет определить маску отрицательного символа, чтобы исключить некоторые специальные символы, которые вы действительно не хотите использовать в имени.

Вы можете сделать это, используя:

$regexp = "/^[^‹поместите сюда нежелательные символы›]+$/

person sebasgo    schedule 11.08.2009
comment
Итак, если я не могу предсказать символы, не лучше ли использовать регулярное выражение, которое запрещает что-то, а не то, которое разрешает? Я мог бы просто запретить большинство командных символов для SQL-инъекций и XSS-атак, что разрешило бы такие вещи, как ü. - person KdgDev; 11.08.2009
comment
Нет, не фильтруйте ключевые слова SQL и подобные вещи. Это очень плохой стиль кодирования. Вместо этого правильно экранируйте данные. Используйте mysql_realescape() для предотвращения SQL-инъекций и htmlentities() для XSS-атак. - person sebasgo; 11.08.2009
comment
Да, себасго в самый раз. Это пустая трата вашего времени, если вы пытаетесь предотвратить SQL-инъекции. Используйте функции, предназначенные для этой цели, не изобретайте велосипед :P - person hobodave; 11.08.2009
comment
Это очень плохой стиль кодирования. Это бессмысленно. Добавление пары символов в регулярное выражение из черного списка нельзя назвать крайне плохим стилем кодирования. Я могу понять, если вы предпочитаете использовать функции, о которых вы упомянули, но не говорите, что люди, которые делают по-другому, имеют очень плохой стиль кодирования. - person KdgDev; 11.08.2009
comment
Если вы отфильтруете ключевые слова SQL, бедняги Bobby Tables не смогут посещать школу. - person Stefano Borini; 11.08.2009
comment
Кроме того, функция mysql_real_escape_string() просто превращает потенциально опасный код в бесполезный. Это делает его безвредным... но он все равно занесен в базу данных, а я этого не хочу. Представьте, что на профильном сайте, где профиль пользователя отображает целую кучу кода SQL... - person KdgDev; 11.08.2009
comment
Я читаю XKCD, Стефано. Также я вообще не фильтрую ключевые слова, я фильтрую символы. Хакер может ввести столько ключевых слов, сколько он хочет, если ; символ найден в строке, то это не имеет значения, он будет отклонен. - person KdgDev; 11.08.2009

Если вы пытаетесь разобрать человеческое имя в PHP, я рекомендую скрипт nameparse.php Кита Бекмана.

person Jonathon Hill    schedule 01.11.2009