21 April 2021
Как использовать все это добро, много всего написано в Сети, поэтому остановлюсь на практических моментах "эксплуатации" (статья написана специально для dkws.org.ua)
Представим, что у нас есть сайт, на который нужно из XML выдрать некоторую информацию (допустим из новостной ленты или еще из чего-либо). Пусть есть путь самого RSS/XML:
$patha = "https://www.vcerecepti.ru/i/%D1%81%D0%B0%D0%BB%D0%B0%D1%82.html?rss=1"
Код будет примено таким:
// для нормальной работы с UTF-8 mb_Internal_Encoding ( 'UTF-8' ); // Создаем новый документ $xmlDoc = new DOMDocument(); // Загружаем в него ссылку (написано для dkws.org.ua) $xmlDoc->load($patha); // получаем элементы из "channel" $channel=$xmlDoc->getElementsByTagName('channel')->item(0); $channel_title = $channel->getElementsByTagName('title') ->item(0)->childNodes->item(0)->nodeValue; $channel_link = $channel->getElementsByTagName('link') ->item(0)->childNodes->item(0)->nodeValue; $channel_desc = $channel->getElementsByTagName('description') ->item(0)->childNodes->item(0)->nodeValue; // выводим элементы из "channel" // В общем, последующий разбор мало интересен, так как об этом и так написано в сети
Все работает превосходно, пока не появляется подлый амперсанд в URL, например:
$patha = "https://www.vcerecepti.ru/i/%D1%81%D0%B0%D0%BB%D0%B0%D1%82.html?rss=1&p=2";
Появится ошибка EntityRef: expecting ';' in имя_RSS
Если вам повезет то & можно просто заменить на &
Но может быть вариант похуже, когда амерсанды есть в самом XML-коде. В этом случае их тоже нужно заменить на &. Есть два способа. Первый - это получить XML-код с помощью file_get_contents() или любым другим способом, например, с помощью curl закачав на сервере, а потом прочитав его в переменную. После того функцией str_replace меняем & на & и полученный XML-код передаем в класс методом loadXML():
$xmlDoc->loadXML($xml);
Но тут возникают проблемы производительности. DOMDocument и так не очень быстрый, а если еще и проводить все эти манипуляции с курлом и заменой амперсандов, то нетерпеливые пользователи могут вовсе не дождаться вывода страницы. Поэтому возникла мысль кэширования. Создается отдельный сценарий, который запускается, скажем, раз в сутки кроном и проходится по всем страницам RSS, то есть:
https://www.vcerecepti.ru/i/%D1%81%D0%B0%D0%BB%D0%B0%D1%82.html?rss=1
https://www.vcerecepti.ru/i/%D1%81%D0%B0%D0%BB%D0%B0%D1%82.html?rss=1&p=2
https://www.vcerecepti.ru/i/%D1%81%D0%B0%D0%BB%D0%B0%D1%82.html?rss=1&p=3
https://www.vcerecepti.ru/i/%D1%81%D0%B0%D0%BB%D0%B0%D1%82.html?rss=1&p=4
и т.д.
Каждую страницу он сохраняет в файл, например, rep1.xml, rep2.xml, rep3.xml и т.д. В этих файлах он заменяет амперсанды на нужную последовательность символов. А наш основной сценарий (Денис Колнисниченко, dkws. org. ua) работает не с удаленным RSS/XML, а загружает методом load() созданные ранее "правильные" XML-файлы: rep1.xml, rep2.xml и т.д. - в зависимости от переданной ему переменной $p.
Во-первых, мы существенно ускоряем сценарий, потому что не нужно загружать XML с удаленного сервера, а мы будем загружать его с локального диска.
Во-вторых, мы избавляемся от ситуации, когда удаленный сервер "завис", с ним нет связи или призошла еще какая-то оказия. В этом случае наш основной сценарий просто бы не открылся, потому что не смог бы получить XML. А так XML под боком. Даже если с удаленным сервером что-то и произойдет, сценарий просто будет использовать старый вариант, созданный сутки назад.
Есть и недостаток. Если страниц много и они большие можно превысить максимальное время выполнения. В этом случае нужно разбить сценарий на 3-4, каждый из которых будет получать свою порцию XML. Например, первый обрабатывает первые 15 страниц, второй - следующие 15 страниц и т.д. Все эти сценарии, чтобы не было лишней нагрузки на сервер нужно запускать с интервалом в 5 - 10 минут. Также нужно учитывать обычное время обновления ресурса, из которого сдирается XML (создано для dkws.org.ua): если он обновляется в 7 утра, то запускать наши сценарии нужно, начиная с 7:20, чтобы они получили не вчерашний XML, а свежий.
Примерный код получения и привода в чувства XML-кода для одной страницы:
// Путь к XML $ch = curl_init($patha); // Открываем файл rep2.xml $fp = fopen("rep2.xml", "w"); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_HEADER, 0); // получаем и сохраняем файл curl_exec($ch); curl_close($ch); fclose($fp); // замена в файле $file = fopen('rep.xml', 'r'); $text = fread($file, filesize('rep2.xml')); fclose($file); $file = fopen('rep.xml', 'w'); fwrite($file, str_replace('&p', '&p', $text)); fclose($file);
На этом все. Успехов!