Validasi PHP / regex untuk URL

125

Saya telah mencari regex sederhana untuk URL, apakah ada yang punya yang berfungsi dengan baik? Saya tidak menemukan satu dengan kelas validasi kerangka zend dan telah melihat beberapa implementasi.

AndreLiem
sumber
1
Ini adalah sumber yang cukup bagus. Memberikan daftar banyak pola dan tes yang berbeda: mathiasbynens.be/demo/url-regex
omar j

Jawaban:

79

Saya menggunakan ini pada beberapa proyek, saya tidak yakin saya mengalami masalah, tetapi saya yakin itu tidak lengkap:

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

Sebagian besar sampah acak di akhir adalah menangani situasi seperti http://domain.com.dalam kalimat (untuk menghindari pencocokan titik akhir). Saya yakin itu bisa dibersihkan tetapi karena berhasil. Saya kurang lebih hanya menyalinnya dari proyek ke proyek.

Owen
sumber
7
Beberapa hal yang menarik perhatian saya: penggunaan pergantian di mana kelas karakter dipanggil (setiap alternatif cocok persis dengan satu karakter); dan penggantinya seharusnya tidak memerlukan tanda kutip ganda luar (mereka hanya diperlukan karena pengubah / e yang tidak berguna di regex).
Alan Moore
1
@ John Scipione: google.comhanya jalur URL relatif yang valid tetapi bukan URL absolut yang valid. Dan saya pikir itulah yang dia cari.
Gumbo
Ini tidak bekerja dalam hal ini - itu termasuk trailing ": 3 cantari noi di albumul <a href=" audio.resursecrestine.ro/cantece/index-autori/andrei-rosu/...>
Softy
1
@Softy sesuatu seperti http://example.com/somedir/...adalah URL yang sangat sah, meminta nama file ...- yang merupakan nama file yang sah.
Stephen P
Saya menggunakan Zend \ Validator \ Regex untuk memvalidasi url menggunakan pola Anda, tetapi masih terdeteksi http://www.examplevalid
Joko Wandiro
207

Gunakan filter_var()fungsi untuk memvalidasi apakah sebuah string adalah URL atau bukan:

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

Menggunakan ekspresi reguler jika tidak perlu merupakan praktik yang buruk.

EDIT : Hati-hati, solusi ini tidak aman untuk unicode dan tidak aman untuk XSS. Jika Anda memerlukan validasi yang kompleks, mungkin lebih baik mencari di tempat lain.

Stanislav
sumber
29
Ada bug di 5.2.13 (dan menurut saya 5.3.2) yang mencegah url dengan tanda hubung di dalamnya untuk memvalidasi menggunakan metode ini.
vamin
14
filter_var akan menolak test-site.com , saya memiliki nama domain dengan tanda hubung, apakah itu valid atau tidak. Saya tidak berpikir filter_var adalah cara terbaik untuk memvalidasi url. Ini akan memungkinkan url sepertihttp://www
Cesar
4
> Ini akan mengizinkan url seperti ' www ' Tidak apa-apa bila URL seperti ' localhost '
Stanislav
12
Masalah lain dengan metode ini adalah tidak aman untuk unicode.
Benji XVI
3
FILTER_VALIDATE_URL memiliki banyak masalah yang perlu diperbaiki. Selain itu, dokumen yang mendeskripsikan flag tidak mencerminkan kode sumber sebenarnya di mana referensi ke beberapa flag telah dihapus seluruhnya. Info lebih lanjut di sini: news.php.net/php.internals/99018
S. Imp
29

Sesuai manual PHP - parse_url tidak boleh digunakan untuk memvalidasi URL.

Sayangnya, tampaknya filter_var('example.com', FILTER_VALIDATE_URL)tidak ada yang lebih baik.

Keduanya parse_url()dan filter_var()akan mengirimkan URL yang salah format sepertihttp://...

Oleh karena itu dalam kasus ini - regex adalah metode yang lebih baik.

catchdave
sumber
10
Argumen ini tidak sesuai. Jika FILTER_VALIDATE_URL sedikit lebih permisif dari yang Anda inginkan, lakukan beberapa pemeriksaan tambahan untuk menangani kasus edge tersebut. Menemukan kembali roda dengan upaya Anda sendiri pada ekspresi reguler terhadap url hanya akan membawa Anda lebih jauh dari pemeriksaan lengkap.
Kzqai
2
Lihat semua regex shot-down di halaman ini untuk contoh mengapa -tidak- menulis milik Anda sendiri.
Kzqai
3
Anda membuat poin yang adil Tchalvak. Ekspresi reguler untuk sesuatu seperti URL bisa (sesuai tanggapan lainnya) sangat sulit dilakukan dengan benar. Regex tidak selalu menjadi jawabannya. Sebaliknya regex juga tidak selalu merupakan jawaban yang salah. Poin pentingnya adalah memilih alat yang tepat (regex atau sebaliknya) untuk pekerjaan tersebut dan tidak secara spesifik menjadi "anti" atau "pro" regex. Jika dipikir-pikir, jawaban Anda tentang penggunaan filter_var yang dikombinasikan dengan batasan pada kasus tepi, sepertinya jawaban yang lebih baik (terutama ketika jawaban regex mulai mencapai lebih dari 100 karakter atau lebih - membuat pemeliharaan regex tersebut menjadi mimpi buruk)
catchdave
12

Untuk berjaga-jaga jika Anda ingin tahu apakah url benar-benar ada:

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);
}
Roger
sumber
1
Saya masih akan melakukan semacam validasi $urlsebelum benar-benar memverifikasi url itu nyata karena operasi di atas mahal - mungkin hingga 200 milidetik tergantung pada ukuran file. Dalam beberapa kasus, url mungkin sebenarnya belum memiliki sumber daya di lokasinya yang tersedia (mis. Membuat url ke gambar yang belum diunggah). Selain itu Anda tidak menggunakan versi yang di-cache sehingga tidak seperti file_exists()itu akan men-cache stat pada file dan kembali hampir seketika. Solusi yang Anda berikan masih berguna. Mengapa tidak digunakan saja fopen($url, 'r')?
Yzmir Ramirez
Terima kasih, apa yang saya cari. Namun, saya membuat kesalahan saat mencoba menggunakannya. Fungsinya adalah "url_exist" bukan "url_exists" oops ;-)
PJ Brunet
9
Apakah ada risiko keamanan dalam mengakses langsung URL yang dimasukkan pengguna?
siliconpi
Anda ingin menambahkan tanda centang jika 404 ditemukan: <code> $ httpCode = curl_getinfo ($ c, CURLINFO_HTTP_CODE); // echo $ url. ''. $ httpCode. '<br>'; if ($ httpCode == 404) {echo $ url. ' 404 '; } </code>
Camaleo
Tidak aman sama sekali .. URL masukan apa pun akan diakses secara aktif.
dmmd
11

Sesuai John Gruber (Daring Fireball):

Ekspresi Reguler:

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

menggunakan di 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)

Berikut adalah pola regex yang diperpanjang (dengan komentar):

(?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
  )
)

Untuk detail lebih lanjut, silakan lihat: http://daringfireball.net/2010/07/improved_regex_for_matching_urls

abhiomkar
sumber
9

Saya tidak berpikir bahwa menggunakan ekspresi reguler adalah hal yang cerdas untuk dilakukan dalam kasus ini. Tidak mungkin untuk mencocokkan semua kemungkinan dan bahkan jika Anda melakukannya, masih ada kemungkinan url tidak ada.

Berikut adalah cara yang sangat sederhana untuk menguji apakah url benar-benar ada dan dapat dibaca:

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

(jika tidak ada preg_matchmaka ini juga akan memvalidasi semua nama file di server Anda)

promaty
sumber
7

Saya telah menggunakan yang ini dengan kesuksesan yang baik - saya tidak ingat dari mana saya mendapatkannya

$pattern = "/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i";
Peter Bailey
sumber
^ (http: // | https: //)? (([a-z0-9]? ([-a-z0-9] * [a-z0-9] +)?) {1,63} \ .) + [az] {2,6} (mungkin terlalu serakah, belum yakin, tapi lebih fleksibel pada protokol dan memimpin 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;
      }
    }
Vikash Kumar
sumber
Tidak berfungsi dengan tautan seperti: 'www.w3schools.com/home/3/?a=l'
pengguna3396065
5

Dan ada jawaban Anda =) Cobalah untuk memecahkannya, Anda tidak bisa !!!

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;
}
George Milonas
sumber
Ada lebih banyak domain tingkat atas .
Jeff Puckett
4

Edit:
Sebagai kejadian ditunjukkan oleh kode ini telah DIHENTIKAN dengan rilis PHP 5.3.0 (2009-06-30) dan harus digunakan sebagaimana mestinya.


Hanya dua sen saya tetapi saya telah mengembangkan fungsi ini dan telah menggunakannya untuk beberapa waktu dengan sukses. Ini didokumentasikan dengan baik dan dipisahkan sehingga Anda dapat dengan mudah mengubahnya.

// 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;
}
Frankie
sumber
1
Eregi akan dihapus di PHP 6.0.0. Dan domain dengan "öäåø" tidak akan divalidasi dengan fungsi Anda. Anda mungkin harus mengonversi URL ke punycode terlebih dahulu?
@incidence sangat setuju. Saya menulis ini pada bulan Maret dan PHP 5.3 hanya keluar akhir Juni pengaturan eregi sebagai TIDAK BERLAKU. Terima kasih. Akan mengedit dan memperbarui.
Frankie
Koreksi saya jika saya salah, tetapi dapatkah kami tetap berasumsi TLD akan memiliki minimal 2 karakter dan maksimal 6 karakter?
Yzmir Ramirez
2
@YzmirRamirez (Bertahun-tahun kemudian ...) Jika ada keraguan ketika Anda menulis komentar Anda pasti tidak sekarang, dengan TLD akhir-akhir ini seperti .photography
Nick Rice
@NickRice Anda benar ... berapa banyak web berubah dalam 5 tahun. Sekarang saya tidak bisa menunggu sampai seseorang membuat 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;
    }
jini
sumber
Hai, solusi ini bagus, dan saya meningkatkannya, tetapi tidak memperhitungkan port standar untuk https: - sarankan Anda mengganti 80 dengan '' di mana itu berhasil
pgee70
Saya akhirnya menerapkan variasi pada ini, karena domain saya peduli apakah URL benar-benar ada atau tidak :)
Raz0rwire
2

Terinspirasi dalam pertanyaan .NET StackOverflow ini dan dalam artikel yang direferensikan ini dari pertanyaan tersebut terdapat validator URI (URI berarti memvalidasi URL dan 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." );
}

Saya telah berhasil menguji unit fungsi ini di dalam ValueObject yang saya buat bernama Uridan diujiUriTest .

UriTest.php (Berisi kasus yang valid dan tidak valid untuk URL dan 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 (Objek Nilai)

<?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." );
        }
    }
}

Menjalankan UnitTests

Ada 65 pernyataan dalam 46 tes. Perhatian: ada 2 penyedia data untuk valid dan 2 lagi untuk ekspresi tidak valid. Satu untuk URL dan yang lainnya untuk URN. Jika Anda menggunakan versi PhpUnit v5.6 * atau yang lebih lama, Anda harus menggabungkan kedua penyedia data tersebut menjadi satu.

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)

Cakupan kode

Ada 100% cakupan kode dalam pemeriksa URI sampel ini.

Xavi Montero
sumber
2
"/(http(s?):\/\/)([a-z0-9\-]+\.)+[a-z]{2,4}(\.[a-z]{2,4})*(\/[^ ]+)*/i"
  1. (http (s?): //) berarti http: // atau https: //

  2. ([a-z0-9 -] +.) + => 2.0 [a-z0-9-] berarti karakter az atau tanda 0-9 atau (-))

                 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}) (/ [^] + ) / i "

                   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.

Catatan: Maaf untuk bahasa Inggris yang buruk. Negara saya tidak menggunakannya dengan baik.

Some_North_korea_kid
sumber
4
Apakah Anda memperhatikan berapa umur pertanyaan ini? Harap jelaskan regex Anda, pengguna yang belum mengetahuinya akan kesulitan memahaminya tanpa detail.
Nic3500
1

Oke, ini sedikit lebih rumit daripada regex sederhana, tetapi memungkinkan untuk jenis url yang berbeda.

Contoh:

Semua yang harus ditandai sebagai valid.

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;
}

Perhatikan bahwa ada pemeriksaan in_array untuk protokol yang ingin Anda izinkan (saat ini hanya http dan https yang ada di daftar itu).

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
Tim Groeneveld
sumber
Throws: ErrorException: Undefined index: skema jika protokol tidak ditentukan saya sarankan untuk memeriksa apakah sudah diatur sebelumnya.
pengguna3396065
@ user3396065, dapatkah Anda memberikan contoh masukan yang menunjukkan hal ini?
Tim Groeneveld
1

Regex URL terbaik yang berhasil untuk saya:

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);
}

Contoh:

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

Sumber: http://urlregex.com/

Fred Vanelli
sumber
0

Regex Peter terlihat tidak tepat bagi saya karena berbagai alasan. Ini memungkinkan semua jenis karakter khusus dalam nama domain dan tidak banyak menguji.

Fungsi Frankie terlihat bagus bagi saya dan Anda dapat membuat regex yang bagus dari komponen jika Anda tidak menginginkan fungsi, seperti:

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

Belum teruji tetapi saya pikir itu seharusnya berhasil.

Juga, jawaban Owen juga tidak terlihat 100%. Saya mengambil bagian domain dari regex dan mengujinya di alat penguji Regex http://erik.eae.net/playground/regexp/regexp.html

Saya meletakkan baris berikut:

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

di bagian "regexp" dan baris berikut:

-hello.com

di bawah bagian "teks contoh".

Hasilnya memungkinkan karakter minus masuk. Karena \ S berarti karakter non-spasi.

Perhatikan regex dari Frankie menangani minus karena memiliki bagian ini untuk karakter pertama:

[a-z0-9]

Yang tidak akan membiarkan minus atau karakter khusus lainnya.

joedevon
sumber
0

Inilah cara saya melakukannya. Tapi saya ingin mengatakan bahwa saya tidak terlalu paham tentang regex. Tapi itu harus berhasil :)

$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);

Dengan cara ini Anda tidak membutuhkan penanda eval pada pola Anda.

Semoga membantu :)

Thomas Venturini
sumber
0

Berikut adalah kelas sederhana untuk Validasi URL menggunakan RegEx dan kemudian mereferensikan silang domain terhadap server RBL (Daftar Lubang Hitam Waktu Nyata) yang populer:

Install:

require 'URLValidation.php';

Pemakaian:

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

Tambahkan URL sebagai parameter domain()metode dan periksa kembaliannya.

$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>';

}

Keluaran:

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

Seperti yang Anda lihat di atas, www.bokranzr.com terdaftar sebagai situs web berbahaya melalui RBL sehingga domainnya dikembalikan sebagai salah.

Kitson88
sumber
-1

Menurut saya, ini paling berguna untuk mencocokkan URL ..

^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$
Jeremy Moore
sumber
1
Akankah itu cocok dengan URL yang diawali dengan ftp:?
andrewsi
/^(https?:\/\/)?([\da-z\.-]+)\.([az\.]{2,6})([\/\w \ .-] *) * \ /? $ /
Shahbaz
-1

Ada fungsi asli PHP untuk itu:

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

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

Mengembalikan data yang difilter, atau FALSE jika filter gagal.

Lihat di sini

Fredmat
sumber
Jawaban ini menduplikasi salah satu jawaban dari tahun 2008!
tersangka