Отправляет email-рассылки с помощью сервиса Sendsay

Все о PHP и даже больше

  Все выпуски  

Все о PHP и даже больше #15


Информационный Канал Subscribe.Ru

Все о PHP и даже больше...

.:: Путь от начинающего до эксперта ::.

# 15
11/2003

7 июля 2003г.

Проект сайта GreatWeb.RU

Ведущий рассылки: Бабушкин Евгений


    В этом выпуске:

  • Наши проекты
  • Модульное программирование на PHP или как написать маленький портал
  • Строки и регулярные выражения. Часть 1
  •   Полезные ссылки:

  • Лучший хостинг
  • Раскрутка
  • Советы Web-мастеру
  • Книги по программировании
  • WEB-браузеры
  • Миры PhotoShop
  • Скрипты
  • Лучшие Рассылки
  • Партнерская программа
  • Взлом и Защита

  • Привет программер!

    :.:: Наши проекты:

     

    GreatWeb.RU - Портал продвинутых юзеров. Только здесь все о веб-дизайне, раскрутке, выбору хостинга и не только...
    Читайте здесь последние новости интернета!

    Форум продвинутых юзеров. Отличный форум! Задавайте абсолютно любые вопросы, вам обязательно ответят и помогут решить Ваши проблемы.
    Самым активным пользователям будет выделен красивый почтовый ящик на 5 mb. Ваше_имя@greatweb.ru


    :.:: Новости GreatWeb.Ru:


    Я поставил новую версию (2.3.0) форума Vbulletin – я решил его оставить, так решило голосование и я в том числе :)
    А так же установлено множество хаков… самые активные пользователи могут их получить… открылось множество новых форумов, вот список всех форумов: Флейм; Играем; Юмор; E-books и не только ...; О форуме; HiTech; Железо; Mobiles; Modding; Операционные системы; Инет Пагеры; Русификаторы; CGI, Perl, PHP, ASP; HTML, CSS, XML, JavaScript; Apache и SSI; Помощь в отладке и установке скриптов; Зацените-ка!; Графика; Плагиат Сети; В помощь вебмастеру; Интересные места паутины; Платный Хостинг; Бесплатный Хостинг. Вот их сколько у нас ;) Заходите, Вам понравится!
    Если Вы еще не зарегистрированы, можете сделать это здесь.

    Добавлено несколько новых статей в раздел Советы Веб-мастеру.

    1. Сезон навигации открыт! - Гипертекстовые ссылки — неотъемлемый элемент любой web-страницы и основа основ идеологии Всемирной Паутины...

    2. Создание веб-страниц для разных разрешений монитора - При создании дизайна веб-страницы Вы должны принимать во внимание несколько вещей. Главными из них являются размер монитора и разрешение экрана посетителей Вашего сайта...

    3. Постройте ваших уток в ряд - Макет страницы и управление содержанием - Одно дело построить уток в ряд, и совсем другое - сделать то же самое, когда они отображаются на HTML-странице....


    Если Вы хотите опубликовать свою рекламу в этой рассылке, пишите на admin@greatweb.ru с
    темой: "Реклама в рассылке Все о PHP и даже больше".


    .:: Модульное программирование на PHP или как написать маленький портал

     


    Я попытаюсь тут разъяснить то, как я подхожу к написанию сайтов, где могут применять подключаемые модули. Пример тому известный скрипт PHPNuke. Как бы не ругали его, подход, примененный в нем, к модульному программированию очень удобен. Но из-за корявости общего кода применять такой скрипт на серьезных сайтах, точнее скажем порталах, с большим количеством посетителей, не рекомендуется. Почему? Скрипт работает медленно, очень большая нагрузка на базу данных. Можно еще очень много чего описать, но это уже материал для другой статьи. Если кому интересно , то в интернете полно описаний этого движка. В «неудобоваримости» PHPNuke я убедился сам. Мой основной проект NVIDIA BIOS Collection в начала базировался на PHPNuke, но постоянные проблемы с хостингом заставили меня начать разработку своей система портала с нуля. Из PHPNuke я взять только суть модулей, все остальное же делал сам. И так для начала. Прежде всего, надо продумать систему каталогов, что и где будет лежать. Вот примерный вариант.

    /
    /mods/ - каталог для хранения модулей
    /img/ - картинки
    /inc/ - каталог вспомогательных файлов
    это что нам сейчас пока надо. Применять блоки и скины мы пока не будем. В моем портале также были другие каталоги
    /blocks/ - Тоже своего рода модули, но не выводящие сами информацию, а возвращающие заполненную переменную.
    /js/ - каталог для Java скриптов
    /theme/ - каталог выбора тем или, грубо говоря, набор скинов для сайта.
    /files/ - файлы для скачивания
    ну и другие каталоги.

    В корневом каталоге храниться всего один файл index.php и вся работа идет через него. Теперь надо решить как будет выглядеть сам сайт. Для нашего примера подойдет наипростейший вариант дизайна , верх сайта , низ сайта, а в середине наша информация из модулей. Для этого в каталоге include создадим два файла top.php и bottom.php, что соответственно будет верхней частью дизайна и нижней частью дизайна.

    top.php
    <?php
    echo "<html>
    <head>
    <meta http-equiv='Content-Type' content='text/html; charset=windows-1251'>
    <title>$PAGE_TITLE</title>
    </head>
    <body>
    <table border='0' cellpadding='0' cellspacing='0' style='border-collapse: collapse' bordercolor='#111111' width='100%' id='AutoNumber1'>
    <tr>
    <td width='100%' colspan='2' bgcolor='#DDFFFF'>
    <p align='center'>здесь выводится шапка</td>
    </tr>
    <tr>
    <td width='17%' align='left' valign='top' bgcolor='#FFDFFF'><b>Меню сайта</b><p>
    <b>- </b><a href='index.php?mod=mod1'>Модуль1</a><br>
    - <a href='index.php?mod=mod2'>Модуль2</a></td>
    <td width='83%' align='left' valign='top'>";
    ?>

    Предвижу комментарии, где скажут, почему я не вывожу HTML код отдельно, а php отдельно. Я приучил себя к написанию 100% PHP кода, с одной стороны не очень и красиво может выглядеть, но мне так удобнее. Если кто-то хочет писать по-другому, то тут я не советчик. Заметьте переменную $PAGE_TITLE в top.php. В моей реализации вся информация о модулях храниться в базе данных, где помимо имени файла модуля храниться также и его название, которое потом и кладется в $PAGE_TITLE, для вывода его в головок браузера.

    bottom.php
    <?php
    echo "</td>
    </tr>
    <tr>
    <td width='100%' align='left' valign='top' colspan='2' bgcolor='#DDFFFF'>&nbsp;</td>
    </tr>
    </table>
    </body>
    </html>";
    ?>

    Также создадим файл конфигурации config.php и положим его в каталог include.

    config.php
    <?php
    #Модуль по умолчанию
    $sys_def_mod="mod1";
    ?>


    Вот примерная схема работы index.php
    <?php
    include("inc/config.php");
    if (!isset($mod) || ($mod=="") || (!file_exists ("mods/$mod.php"))) {
    $mod=$sys_def_mod;
    #Проверка на существование переменной $mod, и существования такого модуля
    # если неверное условие то присваиваем ему значением модуля по умолчанию
    }
    $PAGE_TITLE="Модуль $mod";
    include("inc/top.php");
    include("mods/$mod.php");
    include("inc/bottom.php");
    ?>

    Теперь создадим два файла mod1.php и mod2.php и положим их в каталог mods.


    mod1.php
    <?php
    if (!eregi("index.php", $PHP_SELF)) { die ("Access denied"); }
    echo "Это модуль номер 1!<br>";
    echo "А <a href='index.php?mod=mod2'>здесь</a> можно посмотреть на модуль номер 2";
    ?>

    mod2.php


    <?php
    if (!eregi("index.php", $PHP_SELF)) { die ("Access denied"); }
    echo "Это модуль номер 2!<br>";
    echo "А <a href='index.php?mod=mod1'>здесь</a> можно посмотреть на модуль номер 1";
    ?>

    Поясню немного вот эту строку

    if (!eregi("index.php", $PHP_SELF)) { die ("Access denied"); }

    В каждый модуль желательно включать такую проверку во избежании вызова файла модуля вне самого index.php. На примере моего портала до вызова модуля у меня идет подключение в базе данных, считывание некоторых глобальных переменных и без них, ни один модуль сам по себе работать не сможет. Так что лучше всего просто запретить вызов модуля напрямую. Вызов модулей в данном случае производится через строку в виде index.php?mod=имя модуля, но тут можно применить и систему ЧПУ. Тогда URL примет вид index.php/имя модуля/

    Вот в принципе очень грубая схема реализации модулей. Можно добавить любой модуль, просто положив его в каталог mods/ и придерживаясь общей концепции работы, построить очень сложный сайт. В чем удобства работы? По сути вы отодвигаете от себя основную заботу по натягиванию кода на дизайн. Это делает один раз в index.php. Сам же модуль должен только работать и приносить пользу. Централизация сбора основной информации из базы или конфигурационного файла, глобальные переменные сайта, информация о пользователе и т.д. С другой стороны есть недостатки (хотя при определенном взгляде они не кажутся недостатками), скажем надо четко следить за тем какие имена переменных используются до модуля, чтобы не перезаписать, случайно, их внутри модуля. Один раз у меня такое случилось. После такого случая, я взял для себя за правило называть системные переменные в таком виде $sys_имя переменной. Другой очевидный недостаток это трудность реализации разных вариантов дизайна для разных модулей. Но! Тут есть выход тоже.

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

    К примеру, наши простые модули можно модифицировать в таком варианте.

    <?php
    if (!eregi("index.php", $PHP_SELF)) { die ("Access denied"); }
    $PAGE_TITLE="Это Я, модуль номер 1!!!";
    include("inc/top.php");
    echo "Это модуль номер 1!<br>";
    echo "А <a href='index.php?mod=mod2'>здесь</a> можно посмотреть на модуль номер 2";
    include("inc/bottom.php");
    ?>

    Как делать в данном и конкретном случае решать Вам. Я же просто попытался направить тех, кто начинает писать на php, а может и тех, кто уже пишет, на определенный вариант или стиль программирования.

    Источник: Web-script.ru


     
    .:: Строки и регулярные выражения. Часть 1

     

    Возможности эффективной организации, поиска и распространения информации давно представляли интерес для специалистов в области компьютерных технологий. Поскольку информация в основном представляет собой текст, состоящий из алфавитно-цифровых символов, разработка средств поиска и обработки информации по шаблонам, описывающим текст, стала предметом серьезных теоретических исследований.
    Поиск по шаблону позволяет не только находить определенные фрагменты текста, но и заменять их другими фрагментами. Одним из стандартных примеров поиска по шаблону являются команды поиска/замены в текстовых редакторах — например, в MS Word, Emacs и в моем любимом редакторе vi. Всем пользователям UNIX хорошо известны такие программы, как sed, awk и grep; богатство возможностей этих программ в значительной степени обусловлено средствами поиска по шаблону. Механизмы поиска по шаблону решают четыре основные задачи:

  • Поиск строк, в точности совпадающих с заданным шаблоном;
  • Поиск фрагментов строк, совпадающих с заданным шаблоном;
  • Замену строк и подстрок по шаблону;
  • Поиск строк, с которыми заданный шаблон не совпадает.
  • Появление Web породило необходимость в более быстрых и эффективных средствах поиска данных, которые бы позволяли пользователям со всего мира находить нужную информацию среди миллиардов web-страниц. Поисковые системы, он-лайновые финансовые службы и сайты электронной коммерции — все это стало бы абсолютно бесполезным без средств анализа гигантских объемов данных в этих секторах. Действительно, средства обработки строковой информации являются жизненно важной составляющей практически любого сектора, так или иначе связанного с современными информационными технологиями,
    В этой главе основное внимание посвящено средствам обработки строк в РНР. Мы рассмотрим некоторые стандартные строковые функции (в языке их больше 60!), а из приведенных определений и примеров вы получите сведения, необходимые для создания web-приложений. Но прежде чем переходить к специфике РНР, я хочу познакомить вас с базовым механизмом, благодаря которому становится возможным поиск по шаблону. Речь идет о регулярных выражениях.

    Регулярные выражения
    Регулярные выражения лежат в основе всех современных технологий поиска по шаблону. Регулярное выражение представляет собой последовательность простых и служебных символов, описывающих искомый текст. Иногда регулярные выражения бывают простыми и понятными (например, слово dog), но часто в них присутствуют служебные символы, обладающие особым смыслом в синтаксисе регулярных выражений, — например, <(?)>.*<\/.?>.
    В РНР существуют два семейства функций, каждое из которых относится к определенному типу регулярных выражений: в стиле POSIX или в стиле Peri. Каждый тип регулярных выражений обладает собственным синтаксисом и рассматривается в соответствующей части главы. На эту тему были написаны многочисленные учебники, которые можно найти как в Web, так и в книжных магазинах. Поэтому я приведу лишь основные сведения о каждом типе, а дальнейшую информацию при желании вы сможете найти самостоятельно.
    Если вы еще не знакомы с принципами работы регулярных выражений, обязательно прочитайте краткий вводный курс, занимающий всю оставшуюся часть этого раздела. А если вы хорошо разбираетесь в этой области, смело переходите к следующему разделу.

    Синтаксис регулярных выражений (POSIX)
    Структура регулярных выражений POSIX чем-то напоминает структуру типичных математических выражений — различные элементы (операторы) объединяются друг с другом и образуют более сложные выражения. Однако именно смысл объединения элементов делает регулярные выражения таким мощным и выразительным средством. Возможности не ограничиваются поиском литерального текста (например, конкретного слова или числа); вы можете провести поиск строк с разной семантикой, но похожим синтаксисом — например, всех тегов HTML в файле.
    Простейшее регулярное выражение совпадает с одним литеральным символом — например, выражение g совпадает в таких строках, как g, haggle и bag. Выражение, полученное при объединении нескольких литеральных символов, совпадает по тем же правилам — например, последовательность gang совпадает в любой строке, содержащей эти символы (например, gang, organize или Reagan).
    Оператор | (вертикальная черта) проверяет совпадение одной из нескольких альтернатив. Например, регулярное выражение php|zend проверяет строку на наличие рhр или zend.

    Квадратные скобки
    Квадратные скобки ([ ]) имеют особый смысл в контексте регулярных выражений — они означают «любой символ из перечисленных в скобках». В отличие от регулярного выражения php, которое совпадает во всех строках, содержащих литеральный текст php, выражение [php] совпадает в любой строке, содержащей символы p или п. Квадратные скобки играют важную роль при работе с регулярными выражениями, поскольку в процессе поиска часто возникает задача поиска символов из заданного интервала. Ниже перечислены некоторые часто используемые интервалы:

  • [0-9] — совпадает с любой десятичной цифрой от 0 до 9;
  • [a-z] — совпадает с любым символом нижнего регистра от а до z;
  • [A-Z] — совпадает с любым символом верхнего регистра от А до Z;
  • [a-Z] — совпадает с любым символом нижнего или верхнего регистра от а до Z.


  • Конечно, перечисленные выше интервалы всего лишь демонстрируют общий принцип. Например, вы можете воспользоваться интервалом [0-3] для обозначения любой десятичной цифры от 0 до 3 или интервалом [b-v] для обозначения любого символа нижнего регистра от b до v. Короче говоря, интервалы определяются совершенно произвольно.

    Квантификаторы
    Существует особый класс служебных символов, обозначающих количество повторении отдельного символа или конструкции, заключенной в квадратные скобки. Эти служебные символы (+, * и {...}) называются квантификаторами. Принцип их действия проще всего пояснить на примерах:

  • р+ означает один или несколько символов р, стоящих подряд;
  • р* означает ноль и более символов р, стоящих подряд;
  • р? означает ноль или один символ р;
  • р{2} означает два символа р, стоящих подряд;
  • р{2.3} означает от двух до трех символов р, стоящих подряд;
  • р{2,} означает два и более символов р, стоящих подряд.


  • Прочие служебные символы
    Служебные символы $ и " совпадают не с символами, а с определенными позициями в строке. Например, выражение р$ означает строку, которая завершается символом р, а выражение ^p — строку, начинающуюся с символа р.

  • Конструкция [^a-zA-Z] совпадает с любым символом, не входящим в указанные интервалы (a-z и A-Z).
  • Служебный символ . (точка) означает «любой символ». Например, выражение р. р совпадает с символом р, за которым следует произвольный символ, после чего опять следует символ р.

  • Объединение служебных символов приводит к появлению более сложных выражений. Рассмотрим несколько примеров:

  • ^.{2}$ — любая строка, содержащая ровно два символа;
  • <b>(.*)</b> — произвольная последовательность символов, заключенная между <Ь> и </Ь> (вероятно, тегами HTML для вывода жирного текста);
  • p(hp)* — символ р, за которым следует ноль и более экземпляров последовательности hp (например, phphphp).

  • Иногда требуется найти служебные символы в строках вместо того, чтобы использовать их в описанном специальном контексте. Для этого служебные символы экранируются обратной косой чертой (\). Например, для поиска денежной суммы в долларах можно воспользоваться выражением \$[0-9]+, то есть «знак доллара, за которым следует одна или несколько десятичных цифр». Обратите внимание на обратную косую черту перед $. Возможными совпадениями для этого регулярного выражения являются $42, $560 и $3.

    Стандартные интервальные выражения (символьные классы)
    Для удобства программирования в стандарте POSIX были определены некоторые стандартные интервальные выражения, также называемые символьными классами (character classes). Символьный класс определяет один символ из заданного интервала — например, букву алфавита или цифру:

  • [[:a1pha:]] — алфавитный символ (aA-zZ);
  • [[: digit:]] - цифра (0-9);
  • [[:a1num:]] — алфавитный символ (aA-zZ) или цифра (0-9);
  • [[: space:]] — пропуски (символы новой строки, табуляции и т. д.).
  • Функции РНР для работы с регулярными выражениями (POSIX-совместимые)
    В настоящее время PHP поддерживает семь функций поиска с использованием регулярных выражений в стиле POSIX:

  • еreg();
  • еreg_гер1асе();
  • еreg();
  • еregi_гер1асе();
  • sp1it();
  • spliti();
  • sq1_regcase().
    Описания этих функций приведены в следующих разделах.
    ereg()
    Функция еreg() ищет в заданной строке совпадение для шаблона. Если совпадение найдено, возвращается TRUE, в противном случае возвращается FALSE.

    Синтаксис функции еreg():

    int егед (.string шаблон, string строка [, array совпадения])

    Поиск производится с учетом регистра алфавитных символов. Пример использования еreg() для поиска в строках доменов .corn:


    $is_com = ereg("(\.)(com$)", $еmail);
    // Функция возвращает TRUE, если $еmаil завершается символами ".corn"
    // В частности, поиск будет успешным для строк
    // "www.wjgnmore.com" и "someemail@apress.com"


    Обратите внимание: из-за присутствия служебного символа $ регулярное выражение совпадает только в том случае, если строка завершается символами .corn. Например, оно совпадет в строке "www.apr-ess.com", но не совпадет в строке
    "www.apress.com/catalog".

    Необязательный параметр совпадения содержит массив совпадений для всех подвыражений, заключенных в регулярном выражении в круглые скобки. Далее показано, как при помощи этого массива разделить URL нa несколько сегментов.

    <?
    $ur1 = "http://www.apress.com";
    // Разделить $ur1 на три компонента: "http://www". "apress" и "corn" $www_ur1 = ereg("^(http://www)\.([[:alnum:]]+)\.([[:alnum:]]+)". $ur1. $regs);
    if ($www_ur1) : // Если переменная $www_ur1 содержит URL
    echo $regs[0]: // Вся строка "http://www.apress.com"
    print "<br>";
    echo $regs[l]: // "http://www"
    print "<br>";
    echo $regs[2]: // "apress"
    print "<br>";
    echo $regs[3]: // "corn" endif:
    ?>


    При выполнении сценария будет получен следующий результат:
    http://www.apress.com

    http://www
    apress
    corn

    ereg_replace()
    Функция ereg_replace() ищет в заданной строке совпадение для шаблона и заменяет его новым фрагментом. Синтаксис функции ereg_replace():
    string ereg_replace (string шаблон, string замена, string строке)
    Функция егед_rерlасе() работает по тому же принципу, что и еreg(), но ее возможности расширены от простого поиска до поиска с заменой. После выполнения замены функция возвращает модифицированную строку. Если совпадение отсутствуют, строка остается в прежнем состоянии. Функция егед_герlасе(), как и еreg(), учитывает регистр символов. Ниже приведен простой пример, демонстрирующий применение этой функции:

    $copy_date ="Copyright 1999";
    $copy_date =ereg_rep1ace("([0-9]+)", "2000", $copy_date);
    print $copy_date: // Выводится строка "Copyright 2000"


    У средств поиска с заменой в языке РНР имеется одна интересная возможность — возможность использования обратных ссылок на части основного выражения, заключенные в круглые скобки. Обратные ссылки похожи на элементы необязательного параметра-массива совпадения функции еreg() за одним исключением:
    обратные ссылки записываются в виде \0,\1,\2 и т.д., где \0 соответствует всей строке, \1 — успешному совпадению первого подвыражения и т. д. Выражение может содержать до 9 обратных ссылок. В следующем примере все ссылки на URL в тексте заменяются работающими гиперссылками:

    $url ="Apress (http://www.apress.com"):
    $url = ereg_replace("http://(([A-Za-zO-9.\-])*)", "<a href=\"\\0\">\\0</a>". $ur1);
    print $url:
    // Выводится строка:
    // Apress (<a href="http://www.apress.com">http://www.apress.com</a>)

    eregi()
    Функция eregi() ищет в заданной строке совпадение для шаблона. Синтаксис функции еregi():

    int eregi (string шаблон, string строка [, array совпадения]')

    Поиск производится без учета регистра алфавитных символов. Функция eregi () особенно удобна при проверке правильности введенных строк (например, паролей). Использование функции eregi () продемонстрировано в следующем примере:

    $password ="abc";
    if (! eregi("[[:alnum:]]{8,10}, $password) :
    print "Invalid password! Passwords must be from 8 through 10 characters in length.":
    endif:
    // В результате выполнения этого фрагмента выводится сообщение об ошибке, // поскольку длина строки "abc" не входит в разрешенный интервал // от 8 до 10 символов.

    eregi_replace()
    Функция eregi_replace() работает точно так же, как ereg_replасе(), за одним исключением: поиск производится без учета регистра символов. Синтаксис функции
    eregi_replace():

    string eregi_replace {string шаблон, string замена, string строка)

    split()
    Функция split() разбивает строку на элементы, границы которых определяются по заданному шаблону. Синтаксис функции split():

    array split (.string шаблон, string строка [, int порог]}

    Необязательный параметр порог определяет максимальное количество элементов, на которые делится строка слева направо. Если шаблон содержит алфавитные символы, функция split() работает с учетом регистра символов. Следующий пример демонстрирует использование функции split() для разбиения канонического IP-адреса на триплеты:

    $iр = "123.345.789.000": // Канонический IP-адрес
    $iparr = split ("\.". $ip): // Поскольку точка
    является служебным символом.
    // ее необходиго экранировать.
    print "$iparr[0] <br>"; // Выводит "123"
    print "$iparr[l] <br>"; // Выводит "456"
    print "$iparr[2] <br>": // Выводит "789"
    print "$iparr[3] <br>": // Выводит "000"

    spliti()
    Функция spliti() работает точно так же, как ее прототип split(), за одним исключением: она не учитывает регистра символов. Синтаксис функции spliti():

    array spliti (string шаблон, string строка [. int порог])

    Разумеется, регистр символов важен лишь в том случае, если шаблон содержит алфавитные символы. Для других символов выполнение spliti() полностью аналогично split().

    sql_regcase()
    Вспомогательная функция sql_regcase() заключает каждый символ входной строки в квадратные скобки и добавляет к нему парный символ. Синтаксис функции sql-regcase():

    string sql_regcase (string строка}

    Если алфавитный символ существует в двух вариантах (верхний и нижний регистры), выражение в квадратных скобках будет содержать оба варианта; в противном случае исходный символ повторяется дважды. Функция sql_regcase() особенно удобна при использовании РНР с программными пакетами, поддерживающими регулярные выражения в одном регистре. Пример преобразования строки функцией sql_regcase():

    $version = "php 4.0":
    print sq1_regcase($version);
    // Выводится строка [Pp][Hh][Pp][ ][44][..][00]

    На этом пока придется закончить, ждите продолжение в следующих выпусках...

    Источник: Piter.com

     

    Все свои вопросы Вы можете задавать на нашем форуме.

    © 2002-2003 Copyright by GreatWeb Design
    Копирование материалов рассылки возможно только в случае явного указания на сайт "GreatWeb.RU" как на источник информации.



  • http://subscribe.ru/
    E-mail: ask@subscribe.ru
    Отписаться
    Убрать рекламу

    В избранное