HTML bağlantıları ile metin içinde URL'leri değiştirin

10 Cevap php

Burada bir tasarım olsa: Örneğin ben gibi bir bağlantı koymak

http://example.com

in textarea. Nasıl ben bir http:// link algılayabilir ve sonra olarak yazdırmak PHP alabilirim

print "<a href='htttp://example.com'>http://example.com</a>";

I remember doing something like this before however, it was not fool proof it kept breaking for complex links.

Eğer gibi bir bağlantı varsa başka iyi bir fikir olacaktır

http://example.com/test.php?val1=bla&val2blablabla%20bla%20bla.bl

bu yüzden yapar bunu düzeltmek

print "<a href='http://example.com/test.php?val1=bla&val2=bla%20bla%20bla.bla'>";
print "http://example.com/test.php";
print "</a>";

D: Bu bir sadece bir düşünce sonra .. stackoverflow de muhtemelen de bu kullanabilirsiniz edilir

Herhangi Fikirler

10 Cevap

Kullanıcının ihtiyaçlarına bakalım. Eğer köprü URL'leri ile görüntülemek istediğiniz bazı kullanıcı tarafından sağlanan düz metin var.

  1. "Http://" protokol öneki isteğe olmalıdır.
  2. Her iki etki ve IP adresleri kabul edilmelidir.
  3. Herhangi geçerli bir üst düzey alan, kabul edilmelidir, örneğin . Aero ve xn -. Jxalpdlp.
  4. Port numaraları izin verilmelidir.
  5. URL'ler normal bir cümle bağlamlarda izin verilmelidir. Sözgelimi, "stackoverflow.com ziyaret edin.", Son dönem URL parçası değildir.
  6. Muhtemelen de "https://" URL'leri izin vermek istiyorum, ve belki diğerleri de.
  7. HTML kullanıcı sağlanan metni görüntülerken her zaman olduğu gibi, cross-site scripting (XSS) engellemek istiyorum. Ayrıca, URL'leri imi correctly escaped & gibi olmak isteyeceksiniz.
  8. Muhtemelen IPv6 adresleri için destek gerekmez.
  9. Edit: açıklamalarda belirtildiği gibi, e-posta adresleri için destek kesinlikle bir artı.
  10. Edit: Sadece düz metin girişi destek olmaktır - giriş HTML etiketleri onur edilmemelidir. (Bitbucket sürümü HTML girişini destekler.)

Edit: e-posta adresleri, doğrulanmış URL'ler, tırnak ve parantez içinde URL'ler, HTML girdi, yanı sıra güncellenmiş TLD listesinde desteği ile, son sürümü için Bitbucket göz atın.

Please report bugs and enhancement requests using the Bitbucket issue tracker. Onlar bu şekilde takip etmek (ve açıklama alanı karmaşasını yok) daha kolaydır.

İşte benim almak bulunuyor:

<?php
$text = <<<EOD
Here are some URLs:
stackoverflow.com/questions/1188129/pregreplace-to-detect-html-php
Here's the answer: http://www.google.com/search?rls=en&q=42&ie=utf-8&oe=utf-8&hl=en. What was the question?
A quick look at http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax is helpful.
There is no place like 127.0.0.1! Except maybe http://news.bbc.co.uk/1/hi/england/surrey/8168892.stm?
Ports: 192.168.0.1:8080, https://example.net:1234/.
Beware of Greeks bringing internationalized top-level domains: xn--hxajbheg2az3al.xn--jxalpdlp.
And remember.Nobody is perfect.

<script>alert('Remember kids: Say no to XSS-attacks! Always HTML escape untrusted input!');</script>
EOD;

$rexProtocol = '(https?://)?';
$rexDomain   = '((?:[-a-zA-Z0-9]{1,63}\.)+[-a-zA-Z0-9]{2,63}|(?:[0-9]{1,3}\.){3}[0-9]{1,3})';
$rexPort     = '(:[0-9]{1,5})?';
$rexPath     = '(/[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]*?)?';
$rexQuery    = '(\?[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?';
$rexFragment = '(#[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?';

// Solution 1:

function callback($match)
{
    // Prepend http:// if no protocol specified
    $completeUrl = $match[1] ? $match[0] : "http://{$match[0]}";

    return '<a href="' . $completeUrl . '">'
        . $match[2] . $match[3] . $match[4] . '</a>';
}

print "<pre>";
print preg_replace_callback("&\\b$rexProtocol$rexDomain$rexPort$rexPath$rexQuery$rexFragment(?=[?.!,;:\"]?(\s|$))&",
    'callback', htmlspecialchars($text));
print "</pre>";
  • Düzgün kaçmak için < ve & karakterleri, ben işlemeden önce htmlspecialchars'dan tüm metin atmak. Html öncelemeli URL sınırların yanlış algılanması neden olabilir, bu durum ideal değildir.
  • Gösterdiği gibi, "Ve remember.Nobody mükemmel." daha geçerli bir üst düzey etki alanları üzerinde kontrol hattı (hangi remember.Nobody çünkü eksik alan bir URL olarak kabul edilir), sırayla olabilir.

Edit: Aşağıdaki kodu yukarıdaki iki sorunu giderir, ama ben daha çok ya da daha az preg_replace_callback ile preg_match yeniden uygulanması değilim çünkü biraz daha ayrıntılı olmalıdır.

// Solution 2:

$validTlds = array_fill_keys(explode(" ", ".aero .asia .biz .cat .com .coop .edu .gov .info .int .jobs .mil .mobi .museum .name .net .org .pro .tel .travel .ac .ad .ae .af .ag .ai .al .am .an .ao .aq .ar .as .at .au .aw .ax .az .ba .bb .bd .be .bf .bg .bh .bi .bj .bm .bn .bo .br .bs .bt .bv .bw .by .bz .ca .cc .cd .cf .cg .ch .ci .ck .cl .cm .cn .co .cr .cu .cv .cx .cy .cz .de .dj .dk .dm .do .dz .ec .ee .eg .er .es .et .eu .fi .fj .fk .fm .fo .fr .ga .gb .gd .ge .gf .gg .gh .gi .gl .gm .gn .gp .gq .gr .gs .gt .gu .gw .gy .hk .hm .hn .hr .ht .hu .id .ie .il .im .in .io .iq .ir .is .it .je .jm .jo .jp .ke .kg .kh .ki .km .kn .kp .kr .kw .ky .kz .la .lb .lc .li .lk .lr .ls .lt .lu .lv .ly .ma .mc .md .me .mg .mh .mk .ml .mm .mn .mo .mp .mq .mr .ms .mt .mu .mv .mw .mx .my .mz .na .nc .ne .nf .ng .ni .nl .no .np .nr .nu .nz .om .pa .pe .pf .pg .ph .pk .pl .pm .pn .pr .ps .pt .pw .py .qa .re .ro .rs .ru .rw .sa .sb .sc .sd .se .sg .sh .si .sj .sk .sl .sm .sn .so .sr .st .su .sv .sy .sz .tc .td .tf .tg .th .tj .tk .tl .tm .tn .to .tp .tr .tt .tv .tw .tz .ua .ug .uk .us .uy .uz .va .vc .ve .vg .vi .vn .vu .wf .ws .ye .yt .yu .za .zm .zw .xn--0zwm56d .xn--11b5bs3a9aj6g .xn--80akhbyknj4f .xn--9t4b11yi5a .xn--deba0ad .xn--g6w251d .xn--hgbk6aj7f53bba .xn--hlcj6aya9esc7a .xn--jxalpdlp .xn--kgbechtv .xn--zckzah .arpa"), true);

$position = 0;
while (preg_match("{\\b$rexProtocol$rexDomain$rexPort$rexPath$rexQuery$rexFragment(?=[?.!,;:\"]?(\s|$))}", $text, &$match, PREG_OFFSET_CAPTURE, $position))
{
    list($url, $urlPosition) = $match[0];

    // Print the text leading up to the URL.
    print(htmlspecialchars(substr($text, $position, $urlPosition - $position)));

    $domain = $match[2][0];
    $port   = $match[3][0];
    $path   = $match[4][0];

    // Check if the TLD is valid - or that $domain is an IP address.
    $tld = strtolower(strrchr($domain, '.'));
    if (preg_match('{\.[0-9]{1,3}}', $tld) || isset($validTlds[$tld]))
    {
        // Prepend http:// if no protocol specified
        $completeUrl = $match[1][0] ? $url : "http://$url";

        // Print the hyperlink.
        printf('<a href="%s">%s</a>', htmlspecialchars($completeUrl), htmlspecialchars("$domain$port$path"));
    }
    else
    {
        // Not a valid URL.
        print(htmlspecialchars($url));
    }

    // Continue text parsing from after the URL.
    $position = $urlPosition + strlen($url);
}

// Print the remainder of the text.
print(htmlspecialchars(substr($text, $position)));

İşte ben bu denenmiş ve test edilmiş bulundu şeydir

function make_links_blank($text)
{
  return  preg_replace(
     array(
       '/(?(?=<a[^>]*>.+<\/a>)
             (?:<a[^>]*>.+<\/a>)
             |
             ([^="\']?)((?:https?|ftp|bf2|):\/\/[^<> \n\r]+)
         )/iex',
       '/<a([^>]*)target="?[^"\']+"?/i',
       '/<a([^>]+)>/i',
       '/(^|\s)(www.[^<> \n\r]+)/iex',
       '/(([_A-Za-z0-9-]+)(\\.[_A-Za-z0-9-]+)*@([A-Za-z0-9-]+)
       (\\.[A-Za-z0-9-]+)*)/iex'
       ),
     array(
       "stripslashes((strlen('\\2')>0?'\\1<a href=\"\\2\">\\2</a>\\3':'\\0'))",
       '<a\\1',
       '<a\\1 target="_blank">',
       "stripslashes((strlen('\\2')>0?'\\1<a href=\"http://\\2\">\\2</a>\\3':'\\0'))",
       "stripslashes((strlen('\\2')>0?'<a href=\"mailto:\\0\">\\0</a>':'\\0'))"
       ),
       $text
   );
}

Bu benim için çalışıyor. Ve bu e-posta ve URL, benim kendi soruyu yanıtlamak için üzgünüm için çalışıyor. (

Ama bu çalışır sadece

http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_21878567.html: İşte ben buldum link

Sry önceden bir uzman değişimi olduğu için.

Bu RegEx bu yeni 3 + karakteri toplevel etki haricinde herhangi bir bağlantı eşleşmesi gerekir ...

{
  \\b
  # Match the leading part (proto://hostname, or just hostname)
  (
    # http://, or https:// leading part
    (https?)://[-\\w]+(\\.\\w[-\\w]*)+
  |
    # or, try to find a hostname with more specific sub-expression
    (?i: [a-z0-9] (?:[-a-z0-9]*[a-z0-9])? \\. )+ # sub domains
    # Now ending .com, etc. For these, require lowercase
    (?-i: com\\b
        | edu\\b
        | biz\\b
        | gov\\b
        | in(?:t|fo)\\b # .int or .info
        | mil\\b
        | net\\b
        | org\\b
        | [a-z][a-z]\\.[a-z][a-z]\\b # two-letter country code
    )
  )

  # Allow an optional port number
  ( : \\d+ )?

  # The rest of the URL is optional, and begins with /
  (
    /
    # The rest are heuristics for what seems to work well
    [^.!,?;"\\'()\[\]\{\}\s\x7F-\\xFF]*
    (
      [.!,?]+ [^.!,?;"\\'()\\[\\]\{\\}\s\\x7F-\\xFF]+
    )*
  )?
}ix

Bana tarafından yazılmış değil, ben hiçbir kredi verebilir ki üzgünüm, ben onu nerede var oldukça emin değilim ...

Bu size e-posta adreslerini almak gerekir:

$string = "bah bah steve@gmail.com foo";
$match = preg_match('/[^\x00-\x20()<>@,;:\\".[\]\x7f-\xff]+(?:\.[^\x00-\x20()<>@,;:\\".[\]\x7f-\xff]+)*\@[^\x00-\x20()<>@,;:\\".[\]\x7f-\xff]+(?:\.[^\x00-\x20()<>@,;:\\".[\]\x7f-\xff]+)+/', $string, $array);
print_r($array);

// outputs:
Array
(
    [0] => steve@gmail.com
)

Çizgisinde bir şey:

<?php
if(preg_match('@^http://(.*)\s|$@g', $textarea_url, $matches)) {
    echo '<a href=http://", $matches[1], '">', $matches[1], '</a>';
}
?>

Bu cevap bu soru oldukça eski olduğu kabul edilmiş ve biliyorum, ancak diğer uygulamaları arayan diğer insanlar için yararlı olabilir.

Temmuz 27,09 üzerinde Angel.King.47: Bu tarafından yayınlanmıştır kodun değiştirilmiş versiyonu:

$text = preg_replace(
 array(
   '/(^|\s|>)(www.[^<> \n\r]+)/iex',
   '/(^|\s|>)([_A-Za-z0-9-]+(\\.[A-Za-z]{2,3})?\\.[A-Za-z]{2,4}\\/[^<> \n\r]+)/iex',
   '/(?(?=<a[^>]*>.+<\/a>)(?:<a[^>]*>.+<\/a>)|([^="\']?)((?:https?):\/\/([^<> \n\r]+)))/iex'
 ),  
 array(
   "stripslashes((strlen('\\2')>0?'\\1<a href=\"http://\\2\" target=\"_blank\">\\2</a>&nbsp;\\3':'\\0'))",
   "stripslashes((strlen('\\2')>0?'\\1<a href=\"http://\\2\" target=\"_blank\">\\2</a>&nbsp;\\4':'\\0'))",
   "stripslashes((strlen('\\2')>0?'\\1<a href=\"\\2\" target=\"_blank\">\\3</a>&nbsp;':'\\0'))",
 ),  
 $text
);

Değişiklikler:

  • (Ben durumlar kullanışlı olduğu emin değilim) kurallarını # 2 ve # 3 kaldırıldı.
  • Ben gerçekten gerek yok gibi e-posta ayrıştırma kaldırıldı.
  • I added one more rule which allows the recognition of URLs in the form: [domain]/* (without www). For example: "example.com/faq/" (Multiple tld: domain.{2-3}.{2-4}/)
  • "Http://" ile başlayan dizeleri ayrıştırma, bu bağlantı etiket kaldırır.
  • Tüm linkler için "target = '_blank'" eklendi.
  • URL'ler sadece herhangi bir (?) Etiketinden sonra belirtilebilir. Örneğin: www.example.com

"Soren Løvborg" belirttiği gibi, bu işlev URL'leri kaçış yok. Ben onun / sınıfını denedim ama ben (güveniniz yoksa, o zaman ilk onun / kod denemek) beklendiği gibi sadece işe yaramadı.

This class metne adresler değiştirir ve ev url tutarken olduğu gibi. Ben bu yardım ve you.Enjoy için zaman kazandıracak umuyoruz.

class RegClass 
{ 

     function preg_callback_url($matches) 
     { 
        //var_dump($matches); 
        //Get the matched URL  text <a>text</a>
        $text = $matches[2];
        //Get the matched URL link <a href ="http://www.test.com">text</a>
        $url = $matches[1];

        if($url=='href ="http://www.test.com"'){
         //replace all a tag as it is
         return '<a href='.$url.' rel="nofollow"> '.$text.' </a>'; 

         }else{
         //replace all a tag to text
         return " $text " ;
         }
} 
function ParseText($text){ 

    $text = preg_replace( "/www\./", "http://www.", $text );
        $regex ="/http:\/\/http:\/\/www\./"
    $text = preg_replace( $regex, "http://www.", $text );
        $regex2 = "/https:\/\/http:\/\/www\./";
    $text = preg_replace( $regex2, "https://www.", $text );

        return preg_replace_callback('/<a\s(.+?)>(.+?)<\/a>/is',
                array( &$this,        'preg_callback_url'), $text); 
      } 

} 
$regexp = new RegClass();
echo $regexp->ParseText($text);

Eğer IANA'da güvenmek isterseniz orada gibi kullanımda offcially desteklenen TLD'lerin geçerli listesini alabilirsiniz:

  $validTLDs = 
explode("\n", file_get_contents('http://data.iana.org/TLD/tlds-alpha-by-domain.txt')); //get the official list of valid tlds
  array_shift($validTLDs); //throw away first line containing meta data
  array_pop($validTLDs); //throw away last element which is empty

Søren Løvborg çözümü 2. biraz daha ayrıntılı yapar ve listeyi güncelleme güçlük yedek, bugünlerde yeni TLD'leri ;) dikkatsizce dışarı atılır

Here is the code using Regular Expressions in function

<?php
//Function definations
function MakeUrls($str)
{
$find=array('`((?:https?|ftp)://\S+[[:alnum:]]/?)`si','`((?<!//)(www\.\S+[[:alnum:]]/?))`si');

$replace=array('a href="$1" target="_blank">$1</a>','<a href="http://$1"    target="_blank">$1</a>');

return preg_replace($find,$replace,$str);
}
//Function testing
$str="www.cloudlibz.com";
$str=MakeUrls($str);
echo $str;
?>

Tam url spec eşleşen zor olsa da, burada genellikle iyi bir iş yapan bir düzenli ifade var:

([\w-]+(\.[\w-]+)*@([a-z0-9-]+(\.[a-z0-9-]+)*?\.[a-z]{2,6}|(\d{1,3}\.){3}\d{1,3})(:\d{4})?)

Preg_replace bu kullanmak için, ancak, bunu kaçmak gerekir. Şekilde:

$pattern = "/([\\w-]+(\\.[\\w-]+)*@([a-z0-9-]+(\\.[a-z0-9-]+)*?\\.[a-z]{2,6}|(\\d{1,3}\\.){3}\\d{1,3})(:\\d{4})?)/";
$replaced_texttext = preg_replace($pattern, '<a href="$0" title="$0">$0</a>', $text);