PHP regex для проверки правильности URL, filter_var слишком разрешен

Сначала давайте определим «URL» в соответствии с моими требованиями.

Возможны только протоколы http:// и https://

то обязательное имя домена, например stackoverflow.com

затем необязательно остальные компоненты url ( path , query , hash , …)

Для справки: список действительных и недействительных URL в соответствии с моими требованиями

ДЕЙСТВУЕТ

  • stackoverflow.com
  • stackoverflow.com/questions/ask
  • https://stackoverflow.com/questions/ask
  • http://www.amazon.com/Computers-Internet-Books/b/ref=bhp_bb0309A_comint2?ie=UTF8&node=5&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=browse&pf_rd_r=0AH7GM29WF81Q72VPFDH&pf_rd_t=101&pf_rd_p=1273387142&pf_rd_i=283155
  • amazon.com/Computers-Internet-Books/b/ref=bhp_bb0309A_comint2?ie=UTF8&node=5&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=browse&pf_rd_r=0AH7GM29WF81Q72VPFDH&pf_rd_t=101&pf_rd_p=1273387142&pf_rd_i=283155

  • http://test-site.com (filter_var отвергает это !!! У меня есть доменные имена с тире)

ИНВАЛИД

  • http: // www (php filter_var разрешить это, да, я знаю, это valid url)
  • Google
  • http: //www..des (php filter_var разрешает это)
  • Любой URL-адрес с недопустимыми символами в доменном имени

Для полноты здесь приведена моя версия php: 5.3.2-1ubuntu4.2

В качестве отправной точки вы можете использовать это, это для JS , но легко преобразовать его для работы в PHP preg_match .

 /^(https?\://)?(www\.)?([a-z0-9]([a-z0-9]|(\-[a-z0-9]))*\.)+[az]+$/i 

Для PHP должен работать этот:

 $reg = '@^(https?\://)?(www\.)?([a-z0-9]([a-z0-9]|(\-[a-z0-9]))*\.)+[az]+$@i'; 

Это регулярное выражение в любом случае проверяет только часть домена , но вы можете работать над этим или разделить URL-адрес на 1-ое слэш '/' (после "://" ) и отдельно проверять часть домена и остальные.

BTW: Он также подтвердил бы "http://www.domain.com.com" но это не ошибка, потому что URL-адрес субдомена может быть следующим: "http://www.subdomain.domain.com" и это действительно! И почти нет способа (или, по крайней мере, нет оперативно простого) для проверки правильности домена tld с регулярным выражением, потому что вам нужно будет написать inline в ваше регулярное выражение все возможные доменные имена tlds ONE BY ONE следующим образом:

 /^(https?\://)?(www\.)?([a-z0-9]([a-z0-9]|(\-[a-z0-9]))*\.)+(com|it|net|uk|de)$/i 

(этот последний, например, будет проверять только домен, заканчивающийся на .com / .net / .de / .it / .co.uk). Новые tlds всегда выходят , поэтому вам придется настраивать ваше регулярное выражение каждый раз, когда появляется новый tld, это боль в шее!

Вы можете использовать parse_url чтобы разбить адрес на его компоненты. Хотя он явно не создан для проверки URL-адреса, анализ полученных компонентов и сопоставление их с вашими требованиями, по крайней мере, будет началом.

Он может меняться, но в большинстве случаев вам действительно не нужно проверять правильность любого URL-адреса.

Если это жизненно важная информация, и вы доверяете своему пользователю достаточно, чтобы позволить ему передать его через URL-адрес, вы можете доверять ему достаточно, чтобы указать действительный URL-адрес.

Если это не важная информация, вам просто нужно проверить попытки XSS и отобразить URL-адрес, который требуется пользователю.

Вы можете добавить вручную «http: //», если вы не обнаружите его, чтобы избежать проблем с навигацией.


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