การตรวจสอบ PHP / regex สำหรับ URL


125

ฉันกำลังมองหา regex ง่ายๆสำหรับ URL มีใครมีประโยชน์ที่ใช้งานได้ดีบ้างไหม ฉันไม่พบคลาสการตรวจสอบความถูกต้องของเฟรมเวิร์ก zend และได้เห็นการใช้งานหลายอย่าง


1
นี่เป็นแหล่งข้อมูลที่ดีทีเดียว ให้รายการรูปแบบและการทดสอบที่แตกต่างกันมากมาย: mathiasbynens.be/demo/url-regex
omar j

คำตอบ:


79

ฉันใช้สิ่งนี้ในบางโครงการฉันไม่เชื่อว่าฉันประสบปัญหา แต่ฉันแน่ใจว่ามันไม่ครบถ้วนสมบูรณ์:

$text = preg_replace(
  '#((https?|ftp)://(\S*?\.\S*?))([\s)\[\]{},;"\':<]|\.\s|$)#i',
  "'<a href=\"$1\" target=\"_blank\">$3</a>$4'",
  $text
);

ขยะแบบสุ่มส่วนใหญ่ในตอนท้ายคือการจัดการกับสถานการณ์เช่นhttp://domain.com.ในประโยค (เพื่อหลีกเลี่ยงการจับคู่ช่วงเวลาต่อท้าย) ฉันแน่ใจว่ามันสามารถทำความสะอาดได้ แต่เนื่องจากมันใช้งานได้ ฉันคัดลอกจากโครงการหนึ่งไปอีกโครงการหนึ่งไม่มากก็น้อย


7
บางสิ่งที่โดดเด่นที่ฉัน: การใช้การสลับที่เรียกคลาสอักขระ (ทางเลือกทุกตัวจะตรงกับอักขระหนึ่งตัว); และการแทนที่ไม่ควรจำเป็นต้องใช้เครื่องหมายอัญประกาศคู่ด้านนอก (จำเป็นเพียงเพราะตัวปรับแต่ง / e ที่ไม่มีจุดหมายบน regex)
Alan Moore

1
@John Scipione: google.comเป็นเพียงเส้นทาง URL สัมพัทธ์ที่ถูกต้อง แต่ไม่ใช่ URL ที่สมบูรณ์ที่ถูกต้อง และฉันคิดว่านั่นคือสิ่งที่เขากำลังมองหา
Gumbo

นี้ไม่ได้ทำงานในกรณีนี้ - มันรวมถึงการต่อท้าย ": 3 cantari น้อยใน albumul <a href=" audio.resursecrestine.ro/cantece/index-autori/andrei-rosu/... >
อ่อนแอ

1
@Softy สิ่งที่ชอบhttp://example.com/somedir/...คือ URL ที่ถูกต้องตามกฎหมายอย่างสมบูรณ์โดยขอไฟล์ชื่อ...- ซึ่งเป็นชื่อไฟล์ที่ถูกต้อง
Stephen P

ฉันใช้ Zend \ Validator \ Regex เพื่อตรวจสอบ URL โดยใช้รูปแบบของคุณ แต่ก็ยังตรวจพบhttp://www.exampleว่าถูกต้อง
Joko Wandiro

207

ใช้filter_var()ฟังก์ชันเพื่อตรวจสอบว่าสตริงเป็น URL หรือไม่:

var_dump(filter_var('example.com', FILTER_VALIDATE_URL));

การใช้นิพจน์ทั่วไปเมื่อไม่จำเป็นเป็นการปฏิบัติที่ไม่ดี

แก้ไข : โปรดใช้ความระมัดระวังโซลูชันนี้ไม่ปลอดภัยต่อยูนิโคดและไม่ปลอดภัยต่อ XSS หากคุณต้องการการตรวจสอบความถูกต้องที่ซับซ้อนอาจจะดีกว่าถ้าคุณมองหาที่อื่น


29
มีข้อผิดพลาดใน 5.2.13 (และฉันคิดว่า 5.3.2) ที่ป้องกันไม่ให้ url ที่มีขีดกลางตรวจสอบความถูกต้องโดยใช้วิธีนี้
vamin

14
filter_var จะปฏิเสธtest-site.comฉันมีชื่อโดเมนที่มีขีดกลางว่าถูกต้องหรือไม่ ฉันไม่คิดว่า filter_var เป็นวิธีที่ดีที่สุดในการตรวจสอบ url จะอนุญาต URL เช่นhttp://www
Cesar

4
> มันจะอนุญาตให้ url เช่น ' www ' มันใช้ได้เมื่อ URL เช่น ' localhost '
Stanislav

12
ปัญหาอื่น ๆ ของวิธีนี้คือไม่ปลอดภัยต่อยูนิโคด
Benji XVI

3
FILTER_VALIDATE_URL มีปัญหามากมายที่ต้องแก้ไข นอกจากนี้เอกสารที่อธิบายแฟล็กไม่ได้สะท้อนถึงซอร์สโค้ดจริงซึ่งการอ้างอิงถึงแฟล็กบางส่วนถูกลบออกทั้งหมด ข้อมูลเพิ่มเติมที่นี่: news.php.net/php.internals/99018
S. Imp

29

ตามคู่มือ PHP - ไม่ควรใช้ parse_url เพื่อตรวจสอบความถูกต้องของ URL

น่าเสียดายที่ดูเหมือนว่าfilter_var('example.com', FILTER_VALIDATE_URL)จะไม่ดีขึ้นเลย

ทั้งสองparse_url()และfilter_var()จะส่ง URL ที่ผิดรูปแบบเช่นhttp://...

ดังนั้นในกรณีนี้ - regex เป็นวิธีที่ดีกว่า


10
ข้อโต้แย้งนี้ไม่เป็นไปตาม หาก FILTER_VALIDATE_URL อนุญาตมากกว่าที่คุณต้องการเล็กน้อยให้ตรวจสอบเพิ่มเติมเพื่อจัดการกับขอบกรณีเหล่านั้น การสร้างวงล้อใหม่ด้วยความพยายามของคุณเองที่ regex เทียบกับ urls จะช่วยให้คุณได้รับประโยชน์จากการตรวจสอบทั้งหมด
Kzqai

2
ดู regexes แบบช็อตดาวน์ทั้งหมดในหน้านี้เพื่อดูตัวอย่างเหตุผลที่ไม่ควรเขียนของคุณเอง
Kzqai

3
คุณทำให้ Tchalvak มีความยุติธรรม Regexes สำหรับบางสิ่งเช่น URL (ตามคำตอบอื่น ๆ ) นั้นยากมากที่จะทำให้ถูกต้อง Regex ไม่ใช่คำตอบเสมอไป ในทางกลับกัน regex ก็ไม่ใช่คำตอบที่ผิดเสมอไปเช่นกัน ประเด็นสำคัญคือการเลือกเครื่องมือที่เหมาะสม (regex หรืออื่น ๆ ) สำหรับงานและไม่เจาะจง regex "anti" หรือ "pro" ในการมองย้อนกลับไปคำตอบของคุณในการใช้ filter_var ร่วมกับข้อ จำกัด ใน edge-case ดูเหมือนว่าจะเป็นคำตอบที่ดีกว่า (โดยเฉพาะเมื่อคำตอบ regex เริ่มมีค่ามากกว่า 100 ตัวอักษรทำให้การบำรุงรักษา regex เป็นฝันร้าย)
catchdave

12

ในกรณีที่คุณต้องการทราบว่ามี URL อยู่จริงหรือไม่:

function url_exist($url){//se passar a URL existe
    $c=curl_init();
    curl_setopt($c,CURLOPT_URL,$url);
    curl_setopt($c,CURLOPT_HEADER,1);//get the header
    curl_setopt($c,CURLOPT_NOBODY,1);//and *only* get the header
    curl_setopt($c,CURLOPT_RETURNTRANSFER,1);//get the response as a string from curl_exec(), rather than echoing it
    curl_setopt($c,CURLOPT_FRESH_CONNECT,1);//don't use a cached version of the url
    if(!curl_exec($c)){
        //echo $url.' inexists';
        return false;
    }else{
        //echo $url.' exists';
        return true;
    }
    //$httpcode=curl_getinfo($c,CURLINFO_HTTP_CODE);
    //return ($httpcode<400);
}

1
ฉันยังคงทำการตรวจสอบความถูกต้องบางอย่าง$urlก่อนที่จะตรวจสอบว่า url เป็นของจริงเนื่องจากการดำเนินการข้างต้นมีราคาแพง - อาจมากถึง 200 มิลลิวินาทีขึ้นอยู่กับขนาดไฟล์ ในบางกรณี url อาจยังไม่มีทรัพยากรในตำแหน่งที่พร้อมใช้งาน (เช่นการสร้าง url ไปยังรูปภาพที่ยังไม่ได้อัปโหลด) นอกจากนี้คุณไม่ได้ใช้เวอร์ชันแคชดังนั้นจึงไม่เป็นเช่นfile_exists()นั้นที่จะแคชสถิติในไฟล์และส่งคืนเกือบจะในทันที วิธีแก้ปัญหาที่คุณให้ไว้ยังคงมีประโยชน์ ทำไมไม่ใช้fopen($url, 'r')?
Yzmir Ramirez

ขอบคุณสิ่งที่ฉันกำลังมองหา อย่างไรก็ตามฉันได้พยายามใช้มันผิดพลาด ฟังก์ชันนี้คือ "url_exist" ไม่ใช่ "url_exists" อ๊ะ ;-)
PJ Brunet

9
มีความเสี่ยงด้านความปลอดภัยในการเข้าถึง URL ที่ผู้ใช้ป้อนโดยตรงหรือไม่?
siliconpi

คุณต้องการเพิ่มการตรวจสอบว่าพบ 404 หรือไม่: <code> $ httpCode = curl_getinfo ($ c, CURLINFO_HTTP_CODE); // echo $ url. ''. $ httpCode 'ฟรี'; ถ้า ($ httpCode == 404) {echo $ url. ' 404' ; } </code>
Camaleo

ไม่ปลอดภัยเลย .. URL อินพุตใด ๆ จะถูกเข้าถึงอย่างแข็งขัน
dmmd

11

ตามJohn Gruber (Daring Fireball):

regex:

(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))

ใช้ใน preg_match ():

preg_match("/(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))/", $url)

นี่คือรูปแบบ regex แบบขยาย (พร้อมความคิดเห็น):

(?xi)
\b
(                       # Capture 1: entire matched URL
  (?:
    https?://               # http or https protocol
    |                       #   or
    www\d{0,3}[.]           # "www.", "www1.", "www2." … "www999."
    |                           #   or
    [a-z0-9.\-]+[.][a-z]{2,4}/  # looks like domain name followed by a slash
  )
  (?:                       # One or more:
    [^\s()<>]+                  # Run of non-space, non-()<>
    |                           #   or
    \(([^\s()<>]+|(\([^\s()<>]+\)))*\)  # balanced parens, up to 2 levels
  )+
  (?:                       # End with:
    \(([^\s()<>]+|(\([^\s()<>]+\)))*\)  # balanced parens, up to 2 levels
    |                               #   or
    [^\s`!()\[\]{};:'".,<>?«»“”‘’]        # not a space or one of these punct chars
  )
)

สำหรับรายละเอียดเพิ่มเติมโปรดดูที่: http://daringfireball.net/2010/07/improved_regex_for_matching_urls


9

ฉันไม่คิดว่าการใช้นิพจน์ทั่วไปเป็นสิ่งที่ชาญฉลาดในกรณีนี้ เป็นไปไม่ได้ที่จะจับคู่ความเป็นไปได้ทั้งหมดและแม้ว่าคุณจะทำเช่นนั้นก็ยังมีโอกาสที่ url จะไม่มีอยู่จริง

นี่คือวิธีง่ายๆในการทดสอบว่า url มีอยู่จริงหรือไม่และสามารถอ่านได้:

if (preg_match("#^https?://.+#", $link) and @fopen($link,"r")) echo "OK";

(ถ้าไม่มีpreg_matchสิ่งนี้จะตรวจสอบชื่อไฟล์ทั้งหมดบนเซิร์ฟเวอร์ของคุณด้วย)


7

ฉันใช้อันนี้ประสบความสำเร็จดี - ฉันจำไม่ได้ว่าได้มาจากไหน

$pattern = "/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i";

^ (http: // | https: //)? (([a-Z0-9] ([-a-Z0-9] * [a-Z0-9] +)) {1,63} \ .) + [az] {2,6} (อาจจะโลภเกินไปยังไม่แน่ใจ แต่มันยืดหยุ่นกว่าในโปรโตคอลและ www ชั้นนำ)
andrewbadera

7
    function validateURL($URL) {
      $pattern_1 = "/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i";
      $pattern_2 = "/^(www)((\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i";       
      if(preg_match($pattern_1, $URL) || preg_match($pattern_2, $URL)){
        return true;
      } else{
        return false;
      }
    }

ใช้ไม่ได้กับลิงก์เช่น 'www.w3schools.com/home/3/?a=l'
user3396065

5

และมีคำตอบของคุณ =) พยายามทำลายมันไม่ได้ !!!

function link_validate_url($text) {
$LINK_DOMAINS = 'aero|arpa|asia|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi|local';
  $LINK_ICHARS_DOMAIN = (string) html_entity_decode(implode("", array( // @TODO completing letters ...
    "&#x00E6;", // æ
    "&#x00C6;", // Æ
    "&#x00C0;", // À
    "&#x00E0;", // à
    "&#x00C1;", // Á
    "&#x00E1;", // á
    "&#x00C2;", // Â
    "&#x00E2;", // â
    "&#x00E5;", // å
    "&#x00C5;", // Å
    "&#x00E4;", // ä
    "&#x00C4;", // Ä
    "&#x00C7;", // Ç
    "&#x00E7;", // ç
    "&#x00D0;", // Ð
    "&#x00F0;", // ð
    "&#x00C8;", // È
    "&#x00E8;", // è
    "&#x00C9;", // É
    "&#x00E9;", // é
    "&#x00CA;", // Ê
    "&#x00EA;", // ê
    "&#x00CB;", // Ë
    "&#x00EB;", // ë
    "&#x00CE;", // Î
    "&#x00EE;", // î
    "&#x00CF;", // Ï
    "&#x00EF;", // ï
    "&#x00F8;", // ø
    "&#x00D8;", // Ø
    "&#x00F6;", // ö
    "&#x00D6;", // Ö
    "&#x00D4;", // Ô
    "&#x00F4;", // ô
    "&#x00D5;", // Õ
    "&#x00F5;", // õ
    "&#x0152;", // Œ
    "&#x0153;", // œ
    "&#x00FC;", // ü
    "&#x00DC;", // Ü
    "&#x00D9;", // Ù
    "&#x00F9;", // ù
    "&#x00DB;", // Û
    "&#x00FB;", // û
    "&#x0178;", // Ÿ
    "&#x00FF;", // ÿ 
    "&#x00D1;", // Ñ
    "&#x00F1;", // ñ
    "&#x00FE;", // þ
    "&#x00DE;", // Þ
    "&#x00FD;", // ý
    "&#x00DD;", // Ý
    "&#x00BF;", // ¿
  )), ENT_QUOTES, 'UTF-8');

  $LINK_ICHARS = $LINK_ICHARS_DOMAIN . (string) html_entity_decode(implode("", array(
    "&#x00DF;", // ß
  )), ENT_QUOTES, 'UTF-8');
  $allowed_protocols = array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal');

  // Starting a parenthesis group with (?: means that it is grouped, but is not captured
  $protocol = '((?:'. implode("|", $allowed_protocols) .'):\/\/)';
  $authentication = "(?:(?:(?:[\w\.\-\+!$&'\(\)*\+,;=" . $LINK_ICHARS . "]|%[0-9a-f]{2})+(?::(?:[\w". $LINK_ICHARS ."\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})*)?)?@)";
  $domain = '(?:(?:[a-z0-9' . $LINK_ICHARS_DOMAIN . ']([a-z0-9'. $LINK_ICHARS_DOMAIN . '\-_\[\]])*)(\.(([a-z0-9' . $LINK_ICHARS_DOMAIN . '\-_\[\]])+\.)*('. $LINK_DOMAINS .'|[a-z]{2}))?)';
  $ipv4 = '(?:[0-9]{1,3}(\.[0-9]{1,3}){3})';
  $ipv6 = '(?:[0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7})';
  $port = '(?::([0-9]{1,5}))';

  // Pattern specific to external links.
  $external_pattern = '/^'. $protocol .'?'. $authentication .'?('. $domain .'|'. $ipv4 .'|'. $ipv6 .' |localhost)'. $port .'?';

  // Pattern specific to internal links.
  $internal_pattern = "/^(?:[a-z0-9". $LINK_ICHARS ."_\-+\[\]]+)";
  $internal_pattern_file = "/^(?:[a-z0-9". $LINK_ICHARS ."_\-+\[\]\.]+)$/i";

  $directories = "(?:\/[a-z0-9". $LINK_ICHARS ."_\-\.~+%=&,$'#!():;*@\[\]]*)*";
  // Yes, four backslashes == a single backslash.
  $query = "(?:\/?\?([?a-z0-9". $LINK_ICHARS ."+_|\-\.~\/\\\\%=&,$'():;*@\[\]{} ]*))";
  $anchor = "(?:#[a-z0-9". $LINK_ICHARS ."_\-\.~+%=&,$'():;*@\[\]\/\?]*)";

  // The rest of the path for a standard URL.
  $end = $directories .'?'. $query .'?'. $anchor .'?'.'$/i';

  $message_id = '[^@].*@'. $domain;
  $newsgroup_name = '(?:[0-9a-z+-]*\.)*[0-9a-z+-]*';
  $news_pattern = '/^news:('. $newsgroup_name .'|'. $message_id .')$/i';

  $user = '[a-zA-Z0-9'. $LINK_ICHARS .'_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\'\[\]]+';
  $email_pattern = '/^mailto:'. $user .'@'.'(?:'. $domain .'|'. $ipv4 .'|'. $ipv6 .'|localhost)'. $query .'?$/';

  if (strpos($text, '<front>') === 0) {
    return false;
  }
  if (in_array('mailto', $allowed_protocols) && preg_match($email_pattern, $text)) {
    return false;
  }
  if (in_array('news', $allowed_protocols) && preg_match($news_pattern, $text)) {
    return false;
  }
  if (preg_match($internal_pattern . $end, $text)) {
    return false;
  }
  if (preg_match($external_pattern . $end, $text)) {
    return false;
  }
  if (preg_match($internal_pattern_file, $text)) {
    return false;
  }

  return true;
}

มีมากขึ้นเป็นโดเมนระดับบนสุด
Jeff Puckett

4

แก้ไข:
เนื่องจากอุบัติการณ์ชี้ให้เห็นว่าโค้ดนี้ถูกเลิกใช้งานด้วยการเปิดตัว PHP 5.3.0 (2009-06-30) และควรใช้ตามนั้น


แค่สองเซ็นต์ของฉัน แต่ฉันได้พัฒนาฟังก์ชั่นนี้และใช้มันมาระยะหนึ่งแล้วและประสบความสำเร็จ มีการจัดทำเอกสารอย่างดีและแยกออกจากกันเพื่อให้คุณสามารถเปลี่ยนแปลงได้อย่างง่ายดาย

// Checks if string is a URL
// @param string $url
// @return bool
function isURL($url = NULL) {
    if($url==NULL) return false;

    $protocol = '(http://|https://)';
    $allowed = '([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)';

    $regex = "^". $protocol . // must include the protocol
             '(' . $allowed . '{1,63}\.)+'. // 1 or several sub domains with a max of 63 chars
             '[a-z]' . '{2,6}'; // followed by a TLD
    if(eregi($regex, $url)==true) return true;
    else return false;
}

1
Eregi จะถูกลบออกใน PHP 6.0.0 และโดเมนที่มี "öäåø" จะไม่ตรวจสอบความถูกต้องกับฟังก์ชันของคุณ คุณควรแปลง URL เป็น punycode ก่อนหรือไม่?

@ บังเอิญเห็นด้วยอย่างยิ่ง ฉันเขียนสิ่งนี้ในเดือนมีนาคมและ PHP 5.3 ออกมาเมื่อปลายเดือนมิถุนายนเท่านั้นโดยตั้งค่า eregi เป็น DEPRECATED ขอบคุณ. จะแก้ไขและอัปเดต
Frankie

แก้ไขฉันถ้าฉันผิด แต่เรายังถือว่า TLD มีอักขระอย่างน้อย 2 ตัวและสูงสุด 6 อักขระได้หรือไม่
Yzmir Ramirez

2
@YzmirRamirez (ทุกปีต่อมา ... ) หากมีข้อสงสัยใด ๆ เมื่อคุณเขียนความคิดเห็นของคุณตอนนี้ยังไม่มีแน่นอนกับ TLD ในวันนี้เช่น. photos
Nick Rice

@NickRice คุณถูกต้อง ... เว็บเปลี่ยนไปแค่ไหนใน 5 ปี ตอนนี้ฉันไม่สามารถรอจนกว่าจะมีคนทำ TLD .supercalifragilisticexpialidocious
Yzmir Ramirez

4
function is_valid_url ($url="") {

        if ($url=="") {
            $url=$this->url;
        }

        $url = @parse_url($url);

        if ( ! $url) {


            return false;
        }

        $url = array_map('trim', $url);
        $url['port'] = (!isset($url['port'])) ? 80 : (int)$url['port'];
        $path = (isset($url['path'])) ? $url['path'] : '';

        if ($path == '') {
            $path = '/';
        }

        $path .= ( isset ( $url['query'] ) ) ? "?$url[query]" : '';



        if ( isset ( $url['host'] ) AND $url['host'] != gethostbyname ( $url['host'] ) ) {
            if ( PHP_VERSION >= 5 ) {
                $headers = get_headers("$url[scheme]://$url[host]:$url[port]$path");
            }
            else {
                $fp = fsockopen($url['host'], $url['port'], $errno, $errstr, 30);

                if ( ! $fp ) {
                    return false;
                }
                fputs($fp, "HEAD $path HTTP/1.1\r\nHost: $url[host]\r\n\r\n");
                $headers = fread ( $fp, 128 );
                fclose ( $fp );
            }
            $headers = ( is_array ( $headers ) ) ? implode ( "\n", $headers ) : $headers;
            return ( bool ) preg_match ( '#^HTTP/.*\s+[(200|301|302)]+\s#i', $headers );
        }

        return false;
    }

สวัสดีโซลูชันนี้เป็นสิ่งที่ดีและฉันโหวตแล้ว แต่ไม่ได้คำนึงถึงพอร์ตมาตรฐานสำหรับ https: - ขอแนะนำให้คุณแทนที่ 80 ด้วย '' ซึ่งจะใช้งานพอร์ตได้
pgee70

ฉันลงเอยด้วยการใช้รูปแบบนี้เนื่องจากโดเมนของฉันสนใจว่ามี URL อยู่จริงหรือไม่ :)
Raz0rwire

2

ได้รับแรงบันดาลใจจากคำถาม. NET StackOverflow นี้และในบทความที่อ้างอิงจากคำถามนั้นมีเครื่องมือตรวจสอบ URI นี้ (URI หมายถึงตรวจสอบความถูกต้องทั้ง URL และ URN)

if( ! preg_match( "/^([a-z][a-z0-9+.-]*):(?:\\/\\/((?:(?=((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*))(\\3)@)?(?=(\\[[0-9A-F:.]{2,}\\]|(?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*))\\5(?::(?=(\\d*))\\6)?)(\\/(?=((?:[a-z0-9-._~!$&'()*+,;=:@\\/]|%[0-9A-F]{2})*))\\8)?|(\\/?(?!\\/)(?=((?:[a-z0-9-._~!$&'()*+,;=:@\\/]|%[0-9A-F]{2})*))\\10)?)(?:\\?(?=((?:[a-z0-9-._~!$&'()*+,;=:@\\/?]|%[0-9A-F]{2})*))\\11)?(?:#(?=((?:[a-z0-9-._~!$&'()*+,;=:@\\/?]|%[0-9A-F]{2})*))\\12)?$/i", $uri ) )
{
    throw new \RuntimeException( "URI has not a valid format." );
}

ฉันมีประสบความสำเร็จในหน่วยทดสอบฟังก์ชั่นนี้ภายใน ValueObject ที่ผมทำชื่อและทดสอบโดยUriUriTest

UriTest.php (มีกรณีที่ถูกต้องและไม่ถูกต้องสำหรับทั้ง URL และ URN)

<?php

declare( strict_types = 1 );

namespace XaviMontero\ThrasherPortage\Tests\Tour;

use XaviMontero\ThrasherPortage\Tour\Uri;

class UriTest extends \PHPUnit_Framework_TestCase
{
    private $sut;

    public function testCreationIsOfProperClassWhenUriIsValid()
    {
        $sut = new Uri( 'http://example.com' );
        $this->assertInstanceOf( 'XaviMontero\\ThrasherPortage\\Tour\\Uri', $sut );
    }

    /**
     * @dataProvider urlIsValidProvider
     * @dataProvider urnIsValidProvider
     */
    public function testGetUriAsStringWhenUriIsValid( string $uri )
    {
        $sut = new Uri( $uri );
        $actual = $sut->getUriAsString();

        $this->assertInternalType( 'string', $actual );
        $this->assertEquals( $uri, $actual );
    }

    public function urlIsValidProvider()
    {
        return
            [
                [ 'http://example-server' ],
                [ 'http://example.com' ],
                [ 'http://example.com/' ],
                [ 'http://subdomain.example.com/path/?parameter1=value1&parameter2=value2' ],
                [ 'random-protocol://example.com' ],
                [ 'http://example.com:80' ],
                [ 'http://example.com?no-path-separator' ],
                [ 'http://example.com/pa%20th/' ],
                [ 'ftp://example.org/resource.txt' ],
                [ 'file://../../../relative/path/needs/protocol/resource.txt' ],
                [ 'http://example.com/#one-fragment' ],
                [ 'http://example.edu:8080#one-fragment' ],
            ];
    }

    public function urnIsValidProvider()
    {
        return
            [
                [ 'urn:isbn:0-486-27557-4' ],
                [ 'urn:example:mammal:monotreme:echidna' ],
                [ 'urn:mpeg:mpeg7:schema:2001' ],
                [ 'urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66' ],
                [ 'rare-urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66' ],
                [ 'urn:FOO:a123,456' ]
            ];
    }

    /**
     * @dataProvider urlIsNotValidProvider
     * @dataProvider urnIsNotValidProvider
     */
    public function testCreationThrowsExceptionWhenUriIsNotValid( string $uri )
    {
        $this->expectException( 'RuntimeException' );
        $this->sut = new Uri( $uri );
    }

    public function urlIsNotValidProvider()
    {
        return
            [
                [ 'only-text' ],
                [ 'http//missing.colon.example.com/path/?parameter1=value1&parameter2=value2' ],
                [ 'missing.protocol.example.com/path/' ],
                [ 'http://example.com\\bad-separator' ],
                [ 'http://example.com|bad-separator' ],
                [ 'ht tp://example.com' ],
                [ 'http://exampl e.com' ],
                [ 'http://example.com/pa th/' ],
                [ '../../../relative/path/needs/protocol/resource.txt' ],
                [ 'http://example.com/#two-fragments#not-allowed' ],
                [ 'http://example.edu:portMustBeANumber#one-fragment' ],
            ];
    }

    public function urnIsNotValidProvider()
    {
        return
            [
                [ 'urn:mpeg:mpeg7:sch ema:2001' ],
                [ 'urn|mpeg:mpeg7:schema:2001' ],
                [ 'urn?mpeg:mpeg7:schema:2001' ],
                [ 'urn%mpeg:mpeg7:schema:2001' ],
                [ 'urn#mpeg:mpeg7:schema:2001' ],
            ];
    }
}

Uri.php (ออบเจ็กต์ค่า)

<?php

declare( strict_types = 1 );

namespace XaviMontero\ThrasherPortage\Tour;

class Uri
{
    /** @var string */
    private $uri;

    public function __construct( string $uri )
    {
        $this->assertUriIsCorrect( $uri );
        $this->uri = $uri;
    }

    public function getUriAsString()
    {
        return $this->uri;
    }

    private function assertUriIsCorrect( string $uri )
    {
        // /programming/30847/regex-to-validate-uris
        // http://snipplr.com/view/6889/regular-expressions-for-uri-validationparsing/

        if( ! preg_match( "/^([a-z][a-z0-9+.-]*):(?:\\/\\/((?:(?=((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*))(\\3)@)?(?=(\\[[0-9A-F:.]{2,}\\]|(?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*))\\5(?::(?=(\\d*))\\6)?)(\\/(?=((?:[a-z0-9-._~!$&'()*+,;=:@\\/]|%[0-9A-F]{2})*))\\8)?|(\\/?(?!\\/)(?=((?:[a-z0-9-._~!$&'()*+,;=:@\\/]|%[0-9A-F]{2})*))\\10)?)(?:\\?(?=((?:[a-z0-9-._~!$&'()*+,;=:@\\/?]|%[0-9A-F]{2})*))\\11)?(?:#(?=((?:[a-z0-9-._~!$&'()*+,;=:@\\/?]|%[0-9A-F]{2})*))\\12)?$/i", $uri ) )
        {
            throw new \RuntimeException( "URI has not a valid format." );
        }
    }
}

กำลังเรียกใช้ UnitTests

มีการยืนยัน 65 ข้อในการทดสอบ 46 ครั้ง ข้อควรระวัง:มีผู้ให้บริการข้อมูล 2 รายที่ถูกต้องและอีก 2 รายสำหรับนิพจน์ที่ไม่ถูกต้อง อันหนึ่งใช้สำหรับ URL และอีกอันสำหรับ URN หากคุณใช้ PhpUnit เวอร์ชัน v5.6 * หรือก่อนหน้าคุณจะต้องรวมผู้ให้บริการข้อมูลสองรายเข้าเป็นรายเดียว

xavi@bromo:~/custom_www/hello-trip/mutant-migrant$ vendor/bin/phpunit
PHPUnit 5.7.3 by Sebastian Bergmann and contributors.

..............................................                    46 / 46 (100%)

Time: 82 ms, Memory: 4.00MB

OK (46 tests, 65 assertions)

ความครอบคลุมของรหัส

มีรหัสครอบคลุม 100% ในตัวตรวจสอบ URI ตัวอย่างนี้


2
"/(http(s?):\/\/)([a-z0-9\-]+\.)+[a-z]{2,4}(\.[a-z]{2,4})*(\/[^ ]+)*/i"
  1. (http (s?): //) หมายถึง http: // หรือ https: //

  2. ([a-z0-9 -] +.) + => 2.0 [a-z0-9-] หมายถึงอักขระ az ใด ๆ หรือเครื่องหมาย 0-9 หรือ (-))

                 2.1 (+) means the character can be one or more ex: a1w, 
                     a9-,c559s, f)
    
                 2.2 \. is (.)sign
    
                 2.3. the (+) sign after ([a-z0-9\-]+\.) mean do 2.1,2.2,2.3 
                    at least 1 time 
                  ex: abc.defgh0.ig, aa.b.ced.f.gh. also in case www.yyy.com
    
                 3.[a-z]{2,4} mean a-z at least 2 character but not more than 
                              4 characters for check that there will not be 
                              the case 
                              ex: https://www.google.co.kr.asdsdagfsdfsf
    
                 4.(\.[a-z]{2,4})*(\/[^ ]+)* mean 
    
                   4.1 \.[a-z]{2,4} means like number 3 but start with 
                       (.)sign 
    
                   4.2 * means (\.[a-z]{2,4})can be use or not use never mind
    
                   4.3 \/ means \
                   4.4 [^ ] means any character except blank
                   4.5 (+) means do 4.3,4.4,4.5 at least 1 times
                   4.6 (*) after (\/[^ ]+) mean use 4.3 - 4.5 or not use 
                       no problem
    
                   use for case https://stackoverflow.com/posts/51441301/edit
    
                   5. when you use regex write in "/ /" so it come

    "/(http(s?)://)([a-z0-9-]+.)+[az]{2,4}(.[az]{2,4}) (/ [^] + ) / ฉัน "

                   6. almost forgot: letter i on the back mean ignore case of 
                      Big letter or small letter ex: A same as a, SoRRy same 
                      as sorry.

หมายเหตุ: ขออภัยที่ภาษาอังกฤษไม่ดี ประเทศของฉันไม่นิยมใช้กัน


4
คุณสังเกตไหมว่าคำถามนี้มีอายุเท่าไหร่? โปรดอธิบาย regex ของคุณผู้ใช้ที่ยังไม่รู้จะเข้าใจยากหากไม่มีรายละเอียด
Nic3500

2

URL Regex ที่ดีที่สุดที่เหมาะกับฉัน:

function valid_URL($url){
    return preg_match('%^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@|\d{1,3}(?:\.\d{1,3}){3}|(?:(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)(?:\.(?:[a-z\d\x{00a1}-\x{ffff}]+-?)*[a-z\d\x{00a1}-\x{ffff}]+)*(?:\.[a-z\x{00a1}-\x{ffff}]{2,6}))(?::\d+)?(?:[^\s]*)?$%iu', $url);
}

ตัวอย่าง:

valid_URL('https://twitter.com'); // true
valid_URL('http://twitter.com');  // true
valid_URL('http://twitter.co');   // true
valid_URL('http://t.co');         // true
valid_URL('http://twitter.c');    // false
valid_URL('htt://twitter.com');   // false

valid_URL('http://example.com/?a=1&b=2&c=3'); // true
valid_URL('http://127.0.0.1');    // true
valid_URL('');                    // false
valid_URL(1);                     // false

ที่มา: http://urlregex.com/


1

ตกลงนี่จึงซับซ้อนกว่าเล็กน้อยจากนั้นก็เป็น regex ธรรมดา แต่อนุญาตให้ใช้ url ประเภทต่างๆได้

ตัวอย่าง:

ทั้งหมดที่ควรทำเครื่องหมายว่าถูกต้อง

function is_valid_url($url) {
    // First check: is the url just a domain name? (allow a slash at the end)
    $_domain_regex = "|^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(\.[A-Za-z]{2,})/?$|";
    if (preg_match($_domain_regex, $url)) {
        return true;
    }

    // Second: Check if it's a url with a scheme and all
    $_regex = '#^([a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))$#';
    if (preg_match($_regex, $url, $matches)) {
        // pull out the domain name, and make sure that the domain is valid.
        $_parts = parse_url($url);
        if (!in_array($_parts['scheme'], array( 'http', 'https' )))
            return false;

        // Check the domain using the regex, stops domains like "-example.com" passing through
        if (!preg_match($_domain_regex, $_parts['host']))
            return false;

        // This domain looks pretty valid. Only way to check it now is to download it!
        return true;
    }

    return false;
}

โปรดทราบว่ามีการตรวจสอบ in_array สำหรับโปรโตคอลที่คุณต้องการอนุญาต (ขณะนี้มีเพียง http และ https เท่านั้นที่อยู่ในรายการนั้น)

var_dump(is_valid_url('google.com'));         // true
var_dump(is_valid_url('google.com/'));        // true
var_dump(is_valid_url('http://google.com'));  // true
var_dump(is_valid_url('http://google.com/')); // true
var_dump(is_valid_url('https://google.com')); // true

พ่น: ErrorException: ดัชนีที่ไม่ได้กำหนด: แบบแผนหากไม่ได้ระบุโปรโตคอลฉันขอแนะนำให้ตรวจสอบว่าตั้งค่าไว้ก่อนหรือไม่
user3396065

@ user3396065 โปรดใส่ตัวอย่างข้อมูลที่พ่นนี้ได้ไหม
Tim Groeneveld

0

Regex ของปีเตอร์ไม่เหมาะกับฉันด้วยเหตุผลหลายประการ อนุญาตให้ใช้อักขระพิเศษทุกชนิดในชื่อโดเมนและไม่ได้ทดสอบมากนัก

ฟังก์ชั่นของ Frankie ดูดีสำหรับฉันและคุณสามารถสร้าง regex ที่ดีจากส่วนประกอบได้หากคุณไม่ต้องการฟังก์ชั่นดังนี้:

^(http://|https://)(([a-z0-9]([-a-z0-9]*[a-z0-9]+)?){1,63}\.)+[a-z]{2,6}

ยังไม่ทดสอบ แต่คิดว่าน่าจะใช้ได้

นอกจากนี้คำตอบของ Owen ก็ดูไม่ 100% เช่นกัน ฉันใช้ส่วนโดเมนของ regex และทดสอบบนเครื่องมือทดสอบ Regex http://erik.eae.net/playground/regexp/regexp.html

ฉันใส่บรรทัดต่อไปนี้:

(\S*?\.\S*?)

ในส่วน "regexp" และบรรทัดต่อไปนี้:

-hello.com

ใต้ส่วน "ข้อความตัวอย่าง"

ผลลัพธ์ทำให้อักขระลบผ่าน เนื่องจาก \ S หมายถึงอักขระที่ไม่ใช่ช่องว่าง

สังเกตว่า regex จาก Frankie จัดการกับเครื่องหมายลบเนื่องจากมีส่วนนี้สำหรับอักขระตัวแรก:

[a-z0-9]

ซึ่งจะไม่อนุญาตให้ใช้เครื่องหมายลบหรืออักขระพิเศษอื่น ๆ


0

นี่คือวิธีที่ฉันทำ แต่ฉันอยากจะเมนโทอินว่าฉันไม่ค่อยมั่นใจเกี่ยวกับ regex แต่น่าจะได้ผลนะ :)

$pattern = "#((http|https)://(\S*?\.\S*?))(\s|\;|\)|\]|\[|\{|\}|,|”|\"|'|:|\<|$|\.\s)#i";
        $text = preg_replace_callback($pattern,function($m){
                return "<a href=\"$m[1]\" target=\"_blank\">$m[1]</a>$m[4]";
            },
            $text);

วิธีนี้คุณจะไม่ต้องใช้เครื่องหมาย eval บนรูปแบบของคุณ

หวังว่าจะช่วยได้ :)


0

นี่คือคลาสง่ายๆสำหรับการตรวจสอบ URLโดยใช้ RegEx จากนั้นอ้างอิงข้ามโดเมนกับเซิร์ฟเวอร์ RBL (Realtime Blackhole Lists) ยอดนิยม:

ติดตั้ง:

require 'URLValidation.php';

การใช้งาน:

require 'URLValidation.php';
$urlVal = new UrlValidation(); //Create Object Instance

เพิ่ม URL เป็นพารามิเตอร์ของdomain()วิธีการและตรวจสอบผลตอบแทน

$urlArray = ['http://www.bokranzr.com/test.php?test=foo&test=dfdf', 'https://en-gb.facebook.com', 'https://www.google.com'];
foreach ($urlArray as $k=>$v) {

    echo var_dump($urlVal->domain($v)) . ' URL: ' . $v . '<br>';

}

เอาท์พุท:

bool(false) URL: http://www.bokranzr.com/test.php?test=foo&test=dfdf
bool(true) URL: https://en-gb.facebook.com
bool(true) URL: https://www.google.com

ดังที่คุณเห็นด้านบน www.bokranzr.com ถูกระบุว่าเป็นเว็บไซต์ที่เป็นอันตรายผ่านทาง RBL ดังนั้นโดเมนจึงถูกส่งกลับเป็นเท็จ


0

สำหรับทุกคนที่พัฒนาด้วย WordPress เพียงใช้

esc_url_raw($url) === $url

เพื่อตรวจสอบความถูกต้องของ URL ( นี่คือเอกสารของ WordPress บนesc_url_raw ) จัดการ URL ได้ดีกว่าfilter_var($url, FILTER_VALIDATE_URL)เนื่องจากเป็น Unicode และ XSS-safe ( นี่คือบทความที่ดีที่กล่าวถึงปัญหาทั้งหมดด้วยfilter_var )


-1

ฉันพบว่าสิ่งนี้มีประโยชน์ที่สุดสำหรับการจับคู่ URL ..

^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$

1
จะตรงกับ URL ที่ขึ้นต้นด้วยftp:หรือไม่
andrewsi

/^(https?:\/\/)?([\da-z\.-]+)\.([az\.]{2,6})( [\/\w \ .-] *) * \ /? $ /
Shahbaz

-1

มีฟังก์ชันเนทีฟ PHP สำหรับสิ่งนั้น:

$url = 'http://www.yoururl.co.uk/sub1/sub2/?param=1&param2/';

if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) {
    // Wrong
}
else {
    // Valid
}

ส่งคืนข้อมูลที่กรองหรือ FALSE หากตัวกรองล้มเหลว

ตรวจสอบได้ที่นี่


คำตอบนี้ซ้ำกับหนึ่งในคำตอบจากปี 2008!
สงสัย
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.