Как заменить каждый URL в строке другим уникальным URL? - PullRequest
2 голосов
/ 18 апреля 2009

У меня есть следующее:

$reg[0] = '`<a(\s[^>]*)href="([^"]*)"([^>]*)>`si';
$reg[1] = '`<a(\s[^>]*)href="([^"]*)"([^>]*)>`si';
$replace[0] = '<a$1href="http://www.yahoo.com"$3>';
$replace[1] = '<a$1href="http://www.live.com"$3>';
$string = 'Test <a href="http://www.google.com">Google!!</a>Test <a href="http://www.google.com">Google!!2</a>Test';
echo preg_replace($reg, $replace, $string);

Что приводит к:

Test <a href="http://www.live.com">Google!!</a>Test <a href="http://www.live.com">Google!!2</a>Test

Я хочу закончить с (разница в первой ссылке):

Test <a href="http://www.yahoo.com">Google!!</a>Test <a href="http://www.live.com">Google!!2</a>Test

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

Ответы [ 4 ]

2 голосов
/ 18 апреля 2009

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

Если вы не можете каким-то образом отличить «модифицированные» ссылки от исходных, чтобы они не были захвачены другим выражением (возможно, путем добавления дополнительного свойства HTML?), Я не думаю, что вы действительно сможете решить эту проблему один preg_replace() звонок. Одно возможное решение (помимо дифференцирования в регулярном выражении), которое приходит на ум, состоит в использовании preg_match_all(), поскольку оно даст вам массив совпадений для работы. Вы, вероятно, могли бы затем кодировать совпадающие URL-адреса с помощью URL-адреса отслеживания, перебирая массив и выполняя str_replace() для каждого сопоставленного URL-адреса.

1 голос
/ 19 апреля 2009

Не знаю, правильно ли я понял. Но я написал следующий фрагмент: Регулярное выражение соответствует некоторым гиперссылкам. Тогда это зацикливается через результат и сравнивает текстовые узлы с гиперссылками. Когда в ссылке на гиперссылку обнаружен текстовый узел, он расширяет совпадения, вставляя образец ссылки обратной ссылки с уникальным ключом.

UPDATE Фрагменты находят все гиперссылки:

  1. найти ссылки
  2. build track обратная ссылка
  3. найти позицию каждой найденной ссылки (соответствует [3]) и установить тег шаблона
  4. заменить теги-шаблоны ссылками на трекбек Каждая позиция ссылки уникальна.

$ string = '

Название информационного бюллетеня

Lorem Ipsum Dolor Sit Amet, Concetetur Adipiscing Elit. Donec lobortis, ligula sed sollicitudin dignissim, lacus dolor suscipit sapien, bar.com ipsum ligula не мучитель. Quisque sagittis sodales elit. Mauris dictum blandit lacus. Последовательность Мауриса Лаорет Лакус .

Название бюллетеня

Lorem Ipsum Dolor Sit Amet, Concetetur Adipiscing Elit. Donec lobortis, ligula sed sollicitudin dignissim, lacus dolor suscipit sapien, bar.com ipsum ligula не мучитель. Quisque sagittis sodales elit. Mauris dictum blandit lacus. Последовательность Мауриса Лаорет Лакус .

Название бюллетеня

Lorem Ipsum Dolor Sit Amet, Concetetur Adipiscing Elit Donec lobortis, ligula sed sollicitudin dignissim, lacus dolor suscipit sapien, bar.com ipsum ligula не мучитель. Quisque sagittis sodales elit. Mauris dictum blandit lacus. Последовательность Мауриса Лаорет Лакус .

«;
$regex = '<[^>]+>(.*)<\/[^>]+>';
preg_match_all("'<a\s+href=\"(.*)\"\s*>(.*)<\/[^>]+>'U",$string,$matches);


$uniqueURL = 'http://www.yourdomain.com/trackback.php?id=';

foreach($matches[2] as $k2 => $m2){
    foreach($matches[1] as $k1 => $m1){
        if(stristr($m1, $m2)){
                $uniq = $uniqueURL.md5($matches[0][$k2])."_".rand(1000,9999);
                $matches[3][$k1] = $uniq."&refLink=".$m1;
        }
    }
}


foreach($matches[3] as $key => $val) {

    $startAt = strpos($string, $matches[1][$key]);
    $endAt= $startAt + strlen($matches[1][$key]);

    $strBefore = substr($string,0, $startAt);
    $strAfter = substr($string,$endAt);

    $string = $strBefore . "@@@$key@@@" .$strAfter;

}
foreach($matches[3] as $key => $val) {
        $string = str_replace("@@@$key@@@",$matches[3][$key] ,$string);
}
print "<pre>";
echo $string;
1 голос
/ 18 апреля 2009

Я не очень хорошо разбираюсь в регулярных выражениях, но если вы просто заменяете внешние URL-адреса (т. Е. Не являетесь частью вашего сайта / приложения) внутренним URL-адресом, который будет отслеживать клики и перенаправлять пользователя, тогда должно быть легко создать регулярное выражение, которое будет соответствовать только внешним URL-адресам.

Итак, скажем, ваш домен foo.com, тогда вам просто нужно создать регулярное выражение, которое будет соответствовать только гиперссылке, которая не содержит URL, начинающийся с <a href="http://foo.com" rel="nofollow noreferrer">http://foo.com</a>. Теперь, как я уже сказал, я довольно плохо с регулярными выражениями, но вот мой лучший удар в этом:

$reg[0] = '`<a(\s[^>]*)href="(?!http://foo.com)([^"]*)"([^>]*)>`si';

Edit: Если вы хотите также отслеживать переходы по внутренним URL-адресам, просто замените <a href="http://foo.com" rel="nofollow noreferrer">http://foo.com</a> URL-адресом страницы перенаправления / отслеживания, например, <a href="http://foo.com/out.php" rel="nofollow noreferrer">http://foo.com/out.php</a>.

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

<h1>Newsletter Name</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis,
ligula <a href="http://bar.com">sed sollicitudin</a> dignissim, lacus dolor
suscipit sapien, <a href="http://foo.com">eget auctor</a> ipsum ligula
non tortor. Quisque sagittis sodales elit. Mauris dictum blandit lacus.
Mauris consequat <a href="http://last.fm">laoreet lacus</a>.</p>

Для целей этого упражнения шаблон поиска будет:

// Only match links that don't begin with: http://foo.com/out.php
`<a(\s[^>]*)href="(?!http://foo.com/out\.php)([^"]*)"([^>]*)>`si

Это регулярное выражение можно разбить на 3 части:

  1. <a(\s[^>]*)href="
  2. (?!http://foo.com/out\.php)([^"]*)
  3. "([^>]*)>

При первом проходе поиска скрипт проверит:

<a href="http://bar.com">

Эта ссылка удовлетворяет всем 3 компонентам регулярного выражения, поэтому URL хранится в базе данных и заменяется на <a href="http://foo.com/out.php?id=1" rel="nofollow noreferrer">http://foo.com/out.php?id=1</a>.

На втором проходе поиска скрипт проверит:

<a href="http://foo.com/out.php?id=1">

Эта ссылка соответствует 1 и 3, но не 2. Таким образом, поиск переходит к следующей ссылке:

<a href="http://foo.com">

Эта ссылка удовлетворяет всем 3 компонентам регулярного выражения, поэтому URL хранится в базе данных и заменяется на <a href="http://foo.com/out.php?id=2" rel="nofollow noreferrer">http://foo.com/out.php?id=2</a>.

На 3-м проходе поиска сценарий проверит первые 2 (уже замененные) ссылки, пропустит их, а затем найдет совпадение с последней ссылкой в ​​бюллетене.

0 голосов
/ 20 апреля 2009

До PHP 5.3, где вы можете просто создать функцию на месте, вы должны использовать либо create_function (которую я ненавижу), либо вспомогательный класс.

/**
 * For retrieving a new string from a list.
 */
class StringRotation {
    var $i = -1;
    var $strings = array();

    function addString($string) {
        $this->strings[] = $string;
    }

    /**
     * Use sprintf to produce result string
     * Rotates forward
     * @param array $params the string params to insert
     * @return string
     * @uses StringRotation::getNext()
     */
    function parseString($params) {
        $string = $this->getNext();
        array_unshift($params, $string);
        return call_user_func_array('sprintf', $params);
    }

    function getNext() {
        $this->i++;
        $t = count($this->strings);
        if ($this->i > $t) {
            $this->i = 0;
        }
        return $this->strings[$this->i];
    }

    function resetPointer() {
        $this->i = -1;
    }
}

$reg = '`<a(\s[^>]*)href="([^"]*)"([^>]*)>`si';
$replaceLinks[0] = '<a%2$shref="http://www.yahoo.com"%4$s>';
$replaceLinks[1] = '<a%2$shref="http://www.live.com"%4$s>';

$string = 'Test <a href="http://www.google.com">Google!!</a>Test <a href="http://www.google.com">Google!!2</a>Test';

$linkReplace = new StringRotation();
foreach ($replaceLinks as $replaceLink) {
    $linkReplace->addString($replaceLink);
}

echo preg_replace_callback($reg, array($linkReplace, 'parseString'), $string);
...