SEO-блог Гари

Заметки степного сеошника.

Регулярные выражения. Функции парсинга PHP.

, , , , , ,

Довольно-таки часто новичкам да и продвинутым сайтостроителям часто требуется что-то сграбить с другого сайта. Нужную информацию можно сграбить при помощи потокового RSS, но иногда такой способ бывает не совсем удобен, поэтому, программисты используют регулярные выражения в функциях PHP preg_match() и preg_match_all(), если требуется украсть (отпарсить, от агл. parse - "анализ, разбор") какую-либо информацию с какой-либо страницы сети Интернет. Например, можно каждый час грабать "дорожные пробки" поисковиков, "погоду" метеослужб, "курс валют" банков и прочую нужную информацию для своего сайта, если источники не предлагают свои информеры.

Чтобы найти нужный кусок текста и перетащить эту информацию на свой сайт, нужно задать символьную последовательность (маску поиска), по которой будет вестись весь перебор символов и, в случае нахождения, заданный набор символов (нужная сграбленная информация) будет присвоенна переменной, которую потом можно будет распечатать на экране монитора с помощью функции PHP "echo". Функцию PHP preg_match() парсит только до первого нахождения заданной символьной последовательности, функция preg_match_all() парсит все вхождения.

Символьнный поиск по маске

[ab] - это означает, что вы ищете либо "a", либо "b". [a-z] - все английские буквы от "a" до "z". [a-zA-Z] - любая английская буква, большая или маленькая. [a-fq-x] - любая маленькая английская буква в диапозоне от "a" до "f" и от "q" до "x". [0-9] - любая цифра от 0 до 9. [a-z][a-z][0-9][0-9] - символьная строка, состоящая из первых любых двух маленьких букв и двух любых цифр. [14a-cz] - символьная строка, состоящая из одного любого символа: 1, 4, буквы "a", "b", "c" или "z". Заметка: литералами могут быть не только буквы и цифры, а так же знаки препинания, математические знаки, например ',' (запятая), '!' (восклицательный знак), '+' (плюс), '-' (минус). Если вы поставите минус между a и z, то это будет интервал, но если вы поставите минус сразу же после открытой квадратной скобки, то это будет минус, например: [-,a-z] - символьная строка, состоящая из симоволов: "минус", "запятая" и одна любая маленькая английская буква. Квантификаторы Квантификаторы призванные на сокращение повторений записи (в фигурных скобках): [a-z]{2}[0-9]{3} - символьная строка, состоящая из первых любых двух маленьких букв и трех любых цифр. [a-z]{1,3} - символьная строка, состоящая из одной, двух или трех маленьких английских букв. [a-z]{2,} - символьная строка, состоящая из двух и более маленьких английских букв. [a-z]* - символьная строка, состоящая из любого количества маленьких английских букв или ни одной. Идентично [a-z]{0,}. [a-z]+ - символьная строка, состоящая из любого количества маленьких английских букв, но минимум одной. Идентично [a-z]{1,}. [a-z]? - символьная строка, состоящая из не более, чем одной любой маленькой английской буквы, которая может и отсутствовать. Идентично [a-z]{0,1}. [^abc] - символьная строка, состоящая из любого символа, кроме маленьких букв латинского алфавита "a", "b" и "c". Инструкции ([a-z]{5})([1-8]{3}) - символьная строка, состоящая из пяти маленьких английских букв и трех цифер от 1 до 8. При этом, переменная (в Perl) $0 будет содержать всю строку; $1 - только первую часть, т.е. пять любых маленьких английских букв; $2 - только вторую часть, т.е. три любых цифры от 1 до 8. Символьная строка имеет начало и конец: вначале каждой строки и в конце каждой строки стоит невидимый символ. Для того, чтобы найти совпадающее символьное выражение в нашей строке, существуют спец. символы: ^ ("крышка", "птичка", циркумфлекс)- символ начала строки, ставится в начале строки. $ (знак доллара) - символ конца строки, ставится в конце строки. Запись будет выглядеть так: ^[a-z]{2}[1-5]{3}$ - найти символьное совпадение в строке, которая начинается на первые две любые маленькие английские буквы и заканчивается на три любые цифры от 1 до 5. В программах для того, чтобы показать, где начинается условие поиска (регулярное выражение), используют разделители, например, "слеши" (наклонная черта) или "тильды" (волнистое тире - "~"): preg_match("/^[a-z0-9]/",$string,$mathces); Символы \s - соответствует литералу 'пробел', либо литералу 'перевод строки', либо литералу 'табулятор'. \S - любой видимый символ, не совпадающий с \s, т.е. [^\s]. \w - любой буквенный символ из [a-zA-Z_]. \W - любой символ, не входящий в определение \w, т.е. [^a-zA-Z_]. \d - любой символ из [0-9]. \D - любой символ, не являющийся цифрой. \f - подача листа. \b - "забой" или "граница слова" в зависимости от ситуации. . ("точка") - абсолютно любой символ из видимых и невидимых. \ ("слеш") - позволяет любой спецсимвол описать обычным литералом (простым символом). Например: \. - даст "точку". \\ - даст "слеш". \\\ - даст два обратных "слеша", т.е. "\\". \\\\? - даст "\" или "\\". \< и \> - позиция в начале и в конце слова, т.е. \<cat даст "category", но не "mycat", противоположно действует cat\>, которая даст "mycat" ("notmycat" и др.). Примеры: Запись [a-z\s] будет выглядеть понятней и читабельней, чем [a-z ]. Условия (?<=символы) - символы спереди, которые обязательно должны совпасть в искомой строке. (?=символы) - символы сзади, которые обязательно должны совпасть в искомой строке. (?<!символы) - символы сзади, которые обязательно должны отсутствовать в искомой строке. (?!символы) - символы спереди, которые обязательно должны совпасть в искомой строке. (?# comment #) - комментарий для себя. ?: - позволяет не запоминать (не "есть память" сервера), например: (?:be)|(?:not\sto\sbe) - не будут запоминаться в переменные \1, \2 (в Perl - $1, $2). Например:
preg_match_all("/(?<!<TD>)(?<=>)\d*\.\d*(?!<\/B>)(?=<\/A>)/",$string,$matches);
print_r($matches);
(be)|(not\sto\sbe) - найти в строке символьное совпадение первой группы литералов (символов) "be" или "not to be". Пример: preg_match("/^(be)|(not\sto\sbe)$/",$alternate,$answer); Регулярное выражение совпадет в случае если $alternate = "be" или $alternate = "not to be". s(o|u)n - идентично (son)|(sun) и совпадет с "son" и с "sun". s[o|u]n - совпадет только с "so|un". [(July|Jul)] = [July?] = либо "July", либо "Jul". -------------------------- В PHP поддерживается два стандарта регулярных выражений - POSIX и PCRE (Perl Compatible Regular Expressions). Первый устаревший и медленный, примеров почти нет, документация на английском; второй (функции preg_*) - современный, документация полная. Подробнее об этих стандартах написано в Вики: Regular expression. Вот все функции PHP: preg_filter — Perform a regular expression search and replace preg_grep — Return array entries that match the pattern preg_last_error — Returns the error code of the last PCRE regex execution preg_match_all — Perform a global regular expression match preg_match — Perform a regular expression match preg_quote — Quote regular expression characters preg_replace_callback — Perform a regular expression search and replace using a callback preg_replace — Perform a regular expression search and replace preg_split — Split string by a regular expression Синтаксис регулярных выражений. --------------------------

Примеры парсинга

Ищем все Jpeg-картинки: "\.jpg$". Ищем все ссылки на странице: ^http:// Ищем картинки только в полном пути, а не в бэкграундах и т.д.: ^http://.*\.jpg$ Ищем любую последовательность из символа "А": "A*" - это даст "А", либо "ААА", либо "ААААА". Ищем документ в сети (главную страницу): "index\.(asp|htm|cfm|php|html)". Ищем один слеш или больше: "\\\\+" (первый слеш экранирующий, второй слеш - это сам слеш, затем идет любое количество слешей). Ищем код, например, 12B3C2F0-9D8E-9A99-7A1181C5F546F938: [A-F0-9]{8,8}-[A-F0-9]{4,4}-[A-F0-9]{4,4}-[A-F0-9]{16,16} Найдем страницы от 0 до 9: "page[0-9]\.html" = "page[0-9]+\.html" = "page[0-9]{1,1}\.html" = "page[123456789]\.html". Можно записать приближенно: "page.\.html". Примеры выше взял отсюда: http://stedee.id.au/So_You_Want_to_Learn_Regular_Expressions.
<?php
//Получаем всю html-страницу нужного документа сети и 
    присваиваем содержимое страницы переменной $html.
$html = file_get_contents($site);
//Парсим заголовок (титул) самой html-страницы.
preg_match('|<title>(.*)</title>|mi',$html,$result1);
//Парсим все заголовки html-страницы H1.
preg_match_all('|<h1>(.*)</h1>|mi',$html,$result2);
//Выводим на экран все данные html-страницы
echo '
Титул: '.$result1[1].'<br />
Н1   : '.$result2[1];
?>
Найдем айпи (ip), оно может быть одного из трех форматов: х.х.х.х хх.хх.хх.хх ххх.ххх.ххх.ххх где (х|xx|xxx) = 0...255. preg_match("^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$",$alternate,$answer); Эта маска позволит получить такую последовательность: 999.999.999.999 000.000.000.000 А далее ее уже нужно обрабатывать, чтоб получить правильный айпи-адресс нужного диапазона без ошибок, проверять на совпадение. Если на сайте нет RSS (его парсить гораздо проще), то парсить html-страницу можно так:
<?php
// Получаем HTML-код страницы с помощью функции PHP file_get_contents.
$content = file_get_contents('http://news.google.ru/news?ned=tru_ru&rec=0');
// Определяем позицию строки, с которой мы будем копировать код. Функция strpos.
$pos = strpos($content,'<table border=0 align=right cellspacing=0 cellpadding=0>');
// Присваиваем переменной $content скопированный с помощью substr код, начиная с позиции $pos.
$content = substr($content,$pos);
// Находим позицию второй строки.
$pos = strpos($content,'<br><br><br clear=all>');
// Отрезаем нужное количество символов от нулевого.
$content = substr($content,0,$pos);
// Чтобы не подгружать изображения, удаляем теги [html:img с помощью str_replace (заменяем на пустоту).
$content = str_replace('<img src=/images/cleardot.gif width=1 height=2]','',$content);
// выводим полученный код.
echo $content;
?>
Нашел здесь. -------------------------- Регулярные выражения в сети: http://phpclub.ru/detail/article/regexp_1 http://phpclub.ru/detail/article/regexp_2 P.S. Нужно стараться делать парсеры не чистого html-файла, а XML-файла, потому как он при парсинге не загружается полностью в память, а читается последовательно и вызывается соответсвующее событие. Но у себя я решил пока начать с простого и наклепал при помощи регулярок простой чекер, который показывает в каких каталогах находится ваш сайт, также ТИЦ, ПР, Алексу (популярность сайта по посещаемости в сети), индексацию сайта (количество проиндексированных страниц поисковиками) и беклинки (обратные ссылки на ваш сайт).Со временем постараюсь его доработать, посмотрим, что из этого выйдет. Нашел немного интересных ссылок про регулярные выражения на английском на каком-то странном сайте deitel.com. К сожалению, со всех сайтов вытягивать информацию, не заходя на них (парсить, в общем), не получается, если они находятся на серверах, которые выдают эти самые сайты в различных кодировках, например, мой блог сервер выдает в кодировке charset=UTF-8, поэтому, я не могу проверить регулярками, например, Веб-архив (archive.org), который выдается в кодировке charset=iso-8859-1. Вот такая жопа. И нигде не могу найти в сети пример конвертера, сам тоже не знаю, как конвертер написать. Капец. Зато нашел в сети конвертер в charset=UTF-8 из charset=windows-1251:
<?php
function utf8win1251($s){
  $out="";$c1="";$byte2=false;
  for ($c=0;$c<strlen($s);$c++) {
	$i=ord($s[$c]);
	if ($i<=127) $out.=$s[$c];
	if ($byte2) {
	  $new_c2=($c1&3)*64+($i&63);
	  $new_c1=($c1>>2)&5;
	  $new_i=$new_c1*256+$new_c2;
	  if ($new_i==1025) $out_i=168; else
	  if ($new_i==1105) $out_i=184; else $out_i=$new_i-848;
	  $out.=chr($out_i);
	  $byte2=false;
	} if (($i>>5)==6) {$c1=$i; $byte2=true;}
  } return $out;
}
?>
Применить его к регуляркам не сложно, следует прописать, например, так (кол-во бэклинков в Яндексе):
<?php
function backs_blogs_yandex($link) {
  //Показаны сообщения <b>1</b> — <b>10</b> из <b>414</b> найденных.
  $url = 'http://blogs.yandex.ru/search.xml?text=&holdres=mark&link='.$link;
  $buf = utf8win1251(file_get_contents($url));
  preg_match('|из\s<b>(\d*)</b>|smi',$buf,$r);
  return $r[1] ? $r[1] : '?';
}
?>
Кто знает, как вытянуть информацию о нахождении сайта в Веб-архиве, прокомментируйте, пожалуйста.
http://web.archive.org/web/*/isle-blog.ru
Те, кто часто встречал набор символов, типа \n\t\s\r и подобные и не знает, что это такое и откуда, то загляните в Вики: Управляющие символы. Заметка: Функция PHP file() при получении содержимого страницы с удаленного хоста отправляет среди прочих заголовок X-Powered-By: PHP/5.3.0. Некоторые сайты отслеживают наличие такого заголовка (USER_AGENT) и не отдают по такому запросу контент, выдавая ошибку типа 503 (сервер понял комманду, но решил ее не выполнять по какой-либо причине; 404 - запрещенный вызов и т.д.). Чтобы избежать подобного рода ошибок и всё же вытащить контент, можно воспользоваться CURL и формировать заголовки (типа USER_AGENT и т.п.), маскируясь под браузер, тогда нельзя будет распознать, что это: скрипт (бот) или браузер. Например (стырил с форума forum.php.su):
<?
@set_time_limit(0);
@ini_set("display_errors","1");
$responce = "";
  $fsock    = fsockopen("www.site.ru",80,$errnum,$errstr,2);
  $headers  = "GET http://www.site.ru/ HTTP/1.1\n";
  $headers .= "Host: www.monet.com\n";
  $headers .= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.0.2) Gecko/20060308 Firefox/1.5.0.2\n";
  $headers .= "Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\n";
  $headers .= "Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3\n";
  $headers .= "Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7\n";
  $headers .= "Keep-Alive: 500\n";
  $headers .= "Connection: close\n";
  $headers .= "Content-Type: application/x-www-form-urlencoded\r\n\r\n";
  fwrite ($fsock,$headers);
  while  (!feof($fsock)) $responce .= fread($fsock,1024);
  fclose ($fsock);
echo $responce;
?>
Получить юзер-агент у себя на сайте любой ОС и любого браузера можно коммандой:
<?php echo $_SERVER['HTTP_USER_AGENT']; ?>
Именно из юзер-агента можно вытащить информацию через функцию PHP preg_match(), почти все счетчики-чекеры, определяющие параметры браузера, ОС (операционная система) и языка клепают именно так. smile Если вы писали сами или знаете, где есть интересные статьи на эту тему, поделитесь, пожалуйста, ссылками. Кто не в курсе что это и зачем, просьба не спамить в данном топике - все "левые" комментарии отсюда будут удаляться. Кому интересны заметки, подписывайтесь на блог "Заметки степного сеошника", чтоб не пропустить все самое интересное. wink

Праздник: Всемирный день мужчинjavascript:window.print

Comments

Романrspost Saturday, November 28, 2009 1:18:30 PM

Эка.
С позволения, сграбастаю себе в оффлайн для разбора. Как раз искал нечто похожее почитать, да вот: нашел компактно.
Спасибо.

Зайва Игорь Леонидовичisle0 Sunday, November 29, 2009 8:41:43 AM

Да ничё, грабь, всё, что есть... Все думал, сделаю для себя пару заметок, а они в блог вылились, для себя клепал, ну и рад, что еще кому-то пригодилось smile Здесь только самая скромная информация, сижу, собираю по крупицам. Сам уже вполне разобрался, поэтому, если чего, дополню топик, если нужно, примеры приведу, которые сам смастерил... Как всё до кучи в чекер соберу, так можно будет и весь файл в паблик скинуть... Любой чекер любой сложности можно за неделю наклепать. Хотел купить за 10$ для себя, но самый дешевый, какой предложили - 100-2000, что мне кажется за такую ерундовину слишком круто, вот и решил сам за неделю разобраться... smile

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

Романrspost Sunday, November 29, 2009 2:00:30 PM

Как только разберусь, обязательно worried Только это нескоро будет, мы пока с почтой под опенсорс корпоративной колдуем.
Но всё что найду и всё, до чего дойду, выложу.

Anonymous Monday, February 22, 2010 11:41:53 PM

Ðноним writes: спасибо за статью очень полезная вопрос такой есть контент $content ='vasea vasea vasea vasea'; preg_match_all('/\bvasea vasea\b/U',$content, $result); в результате только 2 совпадения, а действительности если почитать то 3 как правильно это сделать ? спасибо

Зайва Игорь Леонидовичisle0 Tuesday, March 2, 2010 7:37:09 PM

Я не использую "границы слова", также предпочитаю использовать жадный оператор - знак вопроса вместо "U". Поскольку приведенный пример мне не понятен, то, предполагая, что нужно найти все "vasea" из приведенного контента ($content), я бы написал регулярку так:

preg_match_all('|\svasea\s|si',$content,$result);

Далее циклом:

echo $result[0][n];

Anonymous Wednesday, March 3, 2010 9:17:42 PM

ÐиÑалий writes: Привет. Откопал у себя в закладках твой блог. Спасибо большое. Частенько захожу - всё-таки регулярные выражения - это не "мама мыла раму" выучить (чтобы там ни говорили гуру, что это как 2 байта отправить) Если знаешь, подскажи, пжста, почему не находит вот такую конструкцию '\\\"', т.е. в исходном тексте есть '\"весло\"', хотелось бы его заменить на '"весло"' Мож, заодно подскажешь, почему из формы через POST вместо 'девушка с "веслом"' получаю 'девушка с \"веслом\"'? Копал в сторону htmlentitites(), но так и не победил...

Anonymous Wednesday, March 3, 2010 9:47:25 PM

ÐиÑалий writes: И ещё вопрос вдогонку: что это за выражение "/[^\w\x7F-\xFF\s]/" ? Нарыл где-то в сети. Я понимаю, что ищет какой-то диапазон символов, а "сказать" не могу. И где в этом диапазоне '\' и '"'? C помощью этого выражения меняю '\"' на, к примеру, 't'. Получаю 'ttвеслоtt', а потом уже вырезаю лишние 'tt'. Но, боюсь, что в исходном тексте может встретиться что-нить из указанного диапазона, и поменяет лишнее...

Зайва Игорь Леонидовичisle0 Friday, March 5, 2010 4:04:02 PM

Привет smile

Originally posted by anonymous:

Копал в сторону htmlentitites()


Нужно копать в сторону "экранированных кавычек" - дело в них... Для того, чтобы в php вывести текст с кавычками, их нужно заэкранировать или использовать спец.символы юникода, например:

&lt; b &gt; bold &lt; /b &gt;

вместо
<b>bold</b>

Тогда, если выводить переменную как html, то будет результат "жирным" на мониторе, а чтобы переменную вывести как текст, то я использую функцию htmlspecialchars() (аналог htmlentitites()). Это удобно, когда нужно отпарсить страницу html и вывести ее теги (пример выше).

Экранирование кавычек для их вывода в php:

$myparam = "Это \"мой\" текст.";
echo $myparam;

Вывод будет:

Это "мой " текст.

Чтобы кавычки не экранировать, можно использовать одинарные и двойные кавычки, например, так:

$myparam = 'Это "мой" текст.';


Зайва Игорь Леонидовичisle0 Friday, March 5, 2010 4:15:59 PM

Originally posted by anonymous:

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


Раз слово в тексте есть, значит, находит smile

Конструкция '\\\"' означает, что нужно вывести один слеш и одну двойную кавычку, т.е.: \" - это и выводится в тексте. Если нужно вывести вместо '\"весло\"' просто '"весло"', то написать нужно так: '\"' вместо '\\\"' - тогда будет выведена только двойная кавычка без слеша, т.е. получим: просто '"весло"' wink

Все спецсимволы в регулярках должны быть экранированы - это двойные кавычки и слеши, как правило, а также спец.символы управления в регулярках, т.е.: \s - пробелы, \w - символы буквенные (латинские), \d - цифры и т.д.

Зайва Игорь Леонидовичisle0 Friday, March 5, 2010 4:28:29 PM

Originally posted by anonymous:

что это за выражение "/[^\w\x7F-\xFF\s]/" ?


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

echo iconv('windows-1251','utf-8','слово');

А можно просто редактировать php-файл в редакторе, который сохраняет utf-8 кодировку, т.е. просто написать:

echo 'ñëîâî';

Если php-документ в соответствующей кодировке.
Я иногда пользуюсь Штирлицем - помогает wink

Anonymous Thursday, July 22, 2010 11:14:44 AM

Anonymous writes: Добрый день. Вот я смотрю на Ваш пример нахождения ip - preg_match("^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$",$alternate,$answer); И делаю вое регулярное выражение для preg_match в php - preg_match("^[0-9]{8-8}-[0-9]{8-8}-[0-9]-[0-9]-[0-9]$", $html, $tic);print_r($tic); Для нахождения в html коде полученном сurlom, значений типо 27368785-15261606-3-11-0 и не получается, выдается ошибка :Warning: preg_match() [function.preg-match]: Unknown modifier '$' in C:\webserver\apache\www.test1.ru\www\tit.php on line 112

Anonymous Thursday, July 22, 2010 11:34:57 AM

Anonymous writes: сам уже разобрался нужно немного не так как у Вас написано,а так preg_match('/[0-9]{1,9}-[0-9]{1,9}-[0-9]{1,9}-[0-9]{1,9}-[0-9]{1,9}/i',

Зайва Игорь Леонидовичisle0 Tuesday, July 27, 2010 3:19:06 AM

Аноним, всё верно smile Если вы вытаскиваете длинную переменную (строку), например, функцией PHP file_get_contents, в которой содержится где-то в середине ваш айпи, то применять в этой строке "начало" и "конец" в регулярках будет неверно! Если же хотите уточнить, что ваш айпи это и есть целая строка, то можно указать, но это не обязательно и если в айпи (переменной-строке) будет что-то лишнее, то регулярка не сработает.

Приведенный вами пример неправильный:

"[0-9]{1,9}-..." - может быть "1", "11", "111", ... "111111111" - это первая часть айпи, а части не могут иметь более трех цифр и не могут быть более 255.

Нужно именно так:

"[0-9]{1,3}-..." - тогда получим варианты, типа "1", "11" или "111", т.е. 1-3 цифры.

Татьянаtaranna Sunday, September 19, 2010 6:34:40 AM

Только начала интересоваться парсингом, думаю новичкам пригодится и [эта статья]

Зайва Игорь Леонидовичisle0 Sunday, September 19, 2010 9:39:45 AM

Удалил ссылку, потому как ворованная статья написана скорее для хакера и на хакерском ресурсе, тем более устаревшая (не актуальная) и без какого-либо оформления.

Я интересуюсь парсингом как способом передачи информации с одного сайта на другой, а не как способом загаживания сети и чужих ресурсов спамом. Если действительно интересуетесь парсингом, можете задать свои вопросы в личку, могу для вас статейку написать, если оно действительно нужно, но вроде вы и сами в php разбираетесь, раз статьи соответствующие публикуете. smile

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies

February 2012
M T W T F S S
January 2012March 2012
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29