Wikipedia Style Include - обнаружение цикла PHP - PullRequest
2 голосов
/ 15 декабря 2011

У меня есть несколько интересный запрос.

Возможно, я упростил пример, но постараюсь описать мою проблему.

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

Поле «Содержимое» является прямым, оно хранит ссылки «Содержимое страницы» или «Википарт», т. е. [[n]] для ссылки на другую часть и включаетссылки оформлены как [[n]] и включают {{n}}.

+---------------------------+
| id    |  Content          |
+---------------------------+
|  1    | see {{2}} here    | 
+---------------------------+
|  2    | {{1}} here [[4]]  | 
+---------------------------+
|  4    | {{1}}             | 
+---------------------------+



$html_for_screen = readData($this->Content);

function readData($wikipage) {

    $str = "";

    //Convert any wiki links to HTML Links
    $wikipage = Converter::convertWikink($wikipage);

    //Get ALL Include Link matches into array
    $wiki_inc = RegEx::getMatches(wikipage); 

    //Iterate through the Matches
    foreach($wiki_inc as $wiki) {
         //traverse through each match. 
         //but I assume here is where I would eventually have the trouble
         //With infinant loops
         $str .= readData($wiki);
    }

    return $str;

}

Вопрос: Как бы я мог запретить бесконечные части Wiki, включая друг друга?то есть WikiPart 1 включает WikiPart2 .. но WikiPart 2 включает WikiPart1

Функция parse или readData () просто продолжит цикл.

относительно

Ответы [ 2 ]

3 голосов
/ 15 декабря 2011

Вы можете отслеживать свое включение с помощью стека (или набора).Если вы обнаружите, что страница, которую вы собираетесь включить, где-то в стеке, который вы остановите.

Вы также можете просто установить предел рекурсии, например 30 или что-то в этом роде, это не очень чисто, но работает.

2 голосов
/ 15 декабря 2011

На самом деле, если вы столкнулись с циклом, вы больше не можете разрешить.Пример:

1: {{2}}
2: {{1}}

Это создаст бесконечный цикл:

1 -> 2 -> 1 -> 2 -> ...

Поскольку ресурсы любого компьютера ограничены, бесконечные циклы приведут к сбою.

Так чтоты можешь сделать?Вы можете обнаружить это, а затем выдать ошибку с помощью стека:

function readData($wikipage)
{
    static $stack = array();
    if (in_array($wikipage, $stack))
    {
        throw new Exception(sprintf('Circular reference detected: %s -> %s', implode(' -> ', $stack), $wikipage));
    }
    $stack[] = $wikipage;

    ... (your existing code)

    array_pop($stack);
}

Кроме того, вы можете контролировать предел рекурсии, используя count($stack) для определения уровня вложенности.

На самом деле может вызвать исключениеНе будет правильной реакции на циклический эталон, но он показывает, как работает детекция.Вы можете сами решить, как бы вы хотели поступить с делом, например, вернуть FALSE или больше не разрешать поле и т. Д.

Редактировать: Проявите творческий подход здесь:

Если вывод HTML, вы также можете разрешить пользователю проблему.Если такая циклическая ссылка обнаружена, может быть вставлен некоторый маркер AJAX, который запрашивает в браузере наложение в той или иной форме тот фрагмент кода, который не удалось получить на стороне сервера.Такое наложение затем будет снова содержать циклическую ссылку (возможность повторного наложения), чтобы пользователь мог видеть циклическую ссылку в интерактивном режиме.

...