Работа в сети и большие деньги

Учим PHP и пишем спамилку для DLE

Отправлено: 19.03.2009, в рубрике: PHP, SEO

Тема с получением ТИЦ от спама в DLE уже не работает, но продолжает прибавлять ссылочного. Владельцы говносайтов, потерявшие свой неправедно нажитый ТиЦ направо и налево торгуют подобными скриптами (по крайней мере предложений 5 я видел точно).

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

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

Листинг index.php

// лимит времени нам ни к чему

<?
set_time_limit(0);

// во вторые кавычки вводим ключ от http://anti-captcha.com. Инвайт у меня есть

define(’KEY’,”);
define(’MAX_ATTEMPS’,1);

// подключение бибилиотек

include ‘./libs/http.class.php’;
include ‘./libs/formsparser.class.php’;
include ‘./libs/anticaptcha.class.php’;

// создаём объект класса AntiCaptcha

$ocr = new AntiCaptcha(KEY);

// сюда будем записывать неудачи

$bad = fopen(”./bad.txt”,”w”);

// а сюда складывать удачные ссылки

$good = fopen(”./good.txt”,”w”);

// если данные уже ввели в форму, то поехали.. (если нет - то в конце листинга вызов формы)

if (isset($_POST['urls'])) {

// разбиваем список URL на отдельные строки по признаку “\r” - перевод строки

$urls = explode(”\r\n”,$_POST['urls']);

// принимаем логин, пароль, е-майл, сообщение из формы для регистрации на DLE. В личную

// информацию, кстати, тоже не забывайте ссылочку ставить в формате BB-кода.

$login = $_POST['login'];
$password = $_POST['password'];
$email = $_POST['email'];
$msg = $_POST['msg'];
$info = $_POST['info'];

// для каждого url’а выполняем следующее:

foreach ($urls as $url) {

// если строка пустая - выходим из цикла

if (empty($url)) break;

// если url заканчивается на ‘/’ - заменяем его на символ конца строки (0)

if (substr($url,-1,1) == ‘/’) $url = substr($url,0,-1);

// пытаемся регистрироваться (по количеству попыток, заданному в начале)

for ($i=0;$i<MAX_ATTEMPS;$i++) {

// флаг успешной регистрации. Сначала - false (ложь)

$reg = false;

// Выводим извещение “попытка [такая-то]”

echo ‘Попытка ‘.($i+1).’ ‘.$url.’ ‘;

// очищаем буфер вывода

flush();

// создаём объекты класса http и FormsParser (описаны в дополнительных библиотеках)

$http = new http;
$parser = new FormsParser;

// Получаем адрес страницы с регистрацией

$page = $http->GET($url.’/index.php?do=register’);
if ($postdata = $parser->getForm($page,array(”dle_rules_accept”))) {
$page = $http->POST($url.’/index.php?do=register’,$postdata);
}

// Начинаем регистрацию

$postdata = $parser->getForm($page,array(”name”,”password1″,”password1″));
if ($postdata) {
$postdata['name'] = $login;
$postdata['password1'] = $password;
$postdata['password2'] = $password;
$postdata['email'] = $email;

// ввели основные данные, теперь обрабатываем капчу

if (isset($postdata['sec_code']) && preg_match(’#antibot\.php#i’,$page)) {
file_put_contents(’./captcha.jpg’,$http->GET($url.’/engine/modules/antibot.php’));
try {
$code = $ocr->recognize(’./captcha.jpg’);
$postdata['sec_code'] = $code;
echo ‘<font color=”green”>каптча расшифрована (’.$code.’)</font> ‘;
} catch (Exception $error) {
echo ‘<font color=”red”>не удается расшифровать каптчу</font> ‘;
}
}

//второй этап регистрации - вводим дополнительную информацию

$page = $http->POST($url.’/index.php?do=register’,$postdata);
if ($postdata = $parser->getForm($page,array(”fullname”,”land”,”icq”))) {
$postdata['info'] = $info;
$http->POST(http::fixURL($url,$parser->action),$postdata);

//сообщение об удачной регистрации и пополнение файла good

echo “<font color=’green’>регистрация успешна</font> <br/>\r\n”;
fwrite($good,$url.”\r\n”);

//теперь оставляем комментарий

$page = $http->GET($url);
if (preg_match(”#href=[\"']?([^'\"\s<>]+?)\#comment[\"']?#is”,$page,$match)) {
if ($postdata = $parser->getForm($page,array(’login_name’,'login_password’))) {
$postdata['login_name'] = $login;
$postdata['login_password'] = $password;
$http->POST($url.’/index.php’,$postdata);
}
$post_url = http::fixURL($url,$match[1]);
if (!empty($post_url)) {
$page = $http->GET($post_url);
if ($postdata = $parser->getForm($page,array(’post_id’, ‘comments’))) {
$postdata['comments'] = $msg;
$http->POST($post_url,$postdata);
} else {
echo ‘<font color=”red”>не найдена форма отправки коментария</font> ‘;
}
}
} else {
echo ‘<font color=”red”>не удается найти URL на пост</font> ‘;
}
$reg = true;
break;
} else {
echo ‘<font color=”red”>не удается зарегистрироваться</font> ‘;
}
} else {
echo ‘<font color=”red”>не найдена форма</font> ‘;
}
echo “<br/>\r\n”;
}

//Если зарегистрироваться не удалось - записываем в bad

if (!$reg) {
fwrite($bad,$url.”\r\n”);
}
}
}

// вызов самой первой формы для ввода данных

else {
include ‘./templates/form.html’;
}
?>

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

1. Библиотека Anti-Captcha - находка для спамера, реализует возможности сервиса http://anti-captcha.com. Инвайт на сервис можно получить у меня.

Листинг anticaptcha.class.php

<?

class AntiCaptcha {
const FILE_NOT_FOUND = 0;
const CURL_ERROR = 1;
const SERVER_ERROR = 2;
const TIMEOUT = 3;

public $key;
public $server = ‘http://www.anti-captcha.com’;
public $phrase = false;
public $regsense = false;
public $numeric = false;
public $min_len = 0;
public $max_len = 0;

public $ocr_step_time = 10;
public $ocr_timeout = 120;

public $curl_timeout = 30;

private $id;

function __construct($key) {
$this->key = $key;
}

function recognize($filename) {
if (!file_exists($filename)) {
throw new Exception(’File not found’,self::FILE_NOT_FOUND);
}
$postdata = array(
‘method’ => ‘post’,
‘key’ => $this->key,
‘file’ => ‘@’.realpath($filename),
‘phrase’ => (int)$this->phrase,
‘regsense’ => (int)$this->regsense,
‘numeric’ => (int)$this->numeric,
‘min_len’ => $this->min_len,
‘max_len’ => $this->max_len,

);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $this->server.’/in.php’);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_TIMEOUT, $this->curl_timeout);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata);
$result = curl_exec($curl);
if (curl_errno($curl)) {
throw new Exception(curl_error($curl),self::CURL_ERROR);
}
curl_close($curl);
if (strpos($result, ‘OK’) === 0) {
list(,$this->id) = explode(’|',$result);
$start = time();
while (true) {
sleep($this->ocr_step_time);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $this->server.’/res.php?key=’.$this->key.’&action=get&id=’.$this->id);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_TIMEOUT, $this->curl_timeout);
$result = curl_exec($curl);
if (curl_errno($curl)) {
throw new Exception(curl_error($curl),self::CURL_ERROR);
}
curl_close($curl);
if (strpos($result, ‘OK’) === 0) {
list(,$result) = explode(’|',$result);
return $result;
} else if ($result == ‘CAPCHA_NOT_READY’) {
if ((time() - $start) > $this->ocr_timeout) {
throw new Exception(”OCR timeout”,self::TIMEOUT);
}
}
}
} else {
throw new Exception($result,self::SERVER_ERROR);
}
}
}

?>

2. Библиотека HTTP. Эмулирует работу HTTP-браузера, представлены самые важные для спамера функции POST и GET :)

листинг http.class.php

<?

class http {
const MULTIPART = “multipart/form-data”;
const ATOMXML = “application/atom+xml”;

public $proxy = null;
public $proxy_type = CURLPROXY_HTTP;
public $timeout = null;
public $follow_location = true;
public $referer = null;
public $custom_headers = null;
public $cookies = null;
public $user_agent = “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)”;

public $encoding = null;
public $current_url = null;
public $headers = array();

private $curl = null;
private $mhcurl = null;
private $mcurl = array();

function GET($url,$data=null) {
if (!is_null($data)) {
$url = parse_url($url);
$query = array();
if (isset($url['query'])) {
parse_str($url['query'],$query);
}
$query = $data + $query;
$url['query'] = http_build_query($query);
$url = self::buildURL($url);
}
if (is_array($url)) {
$this->multi_init($url);
return $this->processMultiRequest();
} else {
$this->init($url);
return $this->processRequest();
}
}

function POST($url,$data,$type=null) {
$this->init($url);
if (!is_null($type)) {
curl_setopt($this->curl, CURLOPT_HTTPHEADER, array(”Content-Type: “.$type));
}
curl_setopt($this->curl, CURLOPT_POST, true);
curl_setopt($this->curl, CURLOPT_POSTFIELDS, http_build_query($data));
return $this->processRequest();
}

private function multi_init($urls) {
$this->mhcurl = curl_multi_init();
$this->mcurl = array();
foreach ($urls as $i => $url) {
$this->mcurl[$i] = $this->init($url);
curl_multi_add_handle($this->mhcurl, $this->mcurl[$i]);
}
}

private function init($url) {
$this->current_url = $url;
$this->curl = curl_init($url);
curl_setopt($this->curl, CURLOPT_URL, $url);
if (parse_url($url,PHP_URL_SCHEME) == “https”) {
curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, 0);
}
if (!is_null($this->timeout)) {
curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->timeout);
}
if (!is_null($this->referer)) {
curl_setopt($this->curl, CURLOPT_REFERER, $this->referer);
}
if (!is_null($this->custom_headers)) {
curl_setopt($this->curl, CURLOPT_HTTPHEADER, $this->custom_headers);
}
if (!is_null($this->cookies)) {
curl_setopt($this->curl, CURLOPT_COOKIE, $this->processCookies($this->cookies));
}
if (!is_null($this->proxy)) {
curl_setopt($this->curl, CURLOPT_PROXYTYPE, $this->proxy_type);
curl_setopt($this->curl, CURLOPT_PROXY, $this->proxy);
}
curl_setopt($this->curl, CURLOPT_USERAGENT, $this->user_agent);
curl_setopt($this->curl, CURLOPT_FOLLOWLOCATION, $this->follow_location);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->curl, CURLOPT_HEADER, true);
return $this->curl;
}

private function processMultiRequest() {
$result = array();
$running = null;
do {
curl_multi_exec($this->mhcurl, $running);
} while($running);
foreach($this->mcurl as $curl) {
$headers_size = curl_getinfo($curl,CURLINFO_HEADER_SIZE);
$result[] = substr(curl_multi_getcontent($curl),$headers_size);
curl_multi_remove_handle($this->mhcurl, $curl);
}
curl_multi_close($this->mhcurl);
return $result;
}

private function processRequest() {
$result = curl_exec($this->curl);
$headers_size = curl_getinfo($this->curl,CURLINFO_HEADER_SIZE);
$headers = substr($result,0,$headers_size);
$this->processHeaders($headers);
$this->current_url = curl_getinfo($this->curl,CURLINFO_EFFECTIVE_URL);
$this->referer = $this->current_url;
curl_close($this->curl);
return substr($result,$headers_size);
}

private function processCookies($cookies) {
$result = “”;
foreach ($cookies as $key => $value) {
$result .= urlencode($key).”=”.urlencode($value).”;”;
}
return substr($result,0,-1);
}

private function processHeaders($headers) {
$this->headers = array();
foreach(explode(”\r\n”,$headers) as $header) {
if (strpos($header,”:”) !== false) {
list($key,$value) = explode(”:”,$header,2);
$key = trim($key);
$value = trim($value);
if (isset($this->headers[$key])) {
if (is_array($this->headers[$key])) {
$this->headers[$key][] = $value;
} else {
$this->headers[$key] = array($value);
}
} else {
$this->headers[strtolower($key)] = $value;
}
}
}
if (isset($this->headers['set-cookie'])) {
foreach ((array)$this->headers['set-cookie'] as $value) {
if (($pos = strpos($value,”;”)) !== false) $value = substr($value,0,$pos);
if (strpos($value,”=”) !== false) {
list($key,$value) = explode(”=”,$value,2);
} else {
$key = $value;
$value = “”;
}
$key = trim($key);
$value = trim($value);
$this->cookies[$key] = $value;
}
}
$this->encoding = null;
if (isset($this->headers['content-type'])) {
$pos = strpos($this->headers['content-type'],”charset”);
if ($pos !== false) {
$endpos = strpos($this->headers['content-type'],”;”,$pos);
if ($endpos === false) {
$charset = substr($this->headers['content-type'],$pos);
} else {
$length = $endpos - $pos;
$charset = substr($this->headers['content-type'],$pos,$length);
}
list(,$this->encoding) = explode(”=”,$charset,2);
}
}
}

final static function buildURL($data) {
$url = “”;

if (!isset($data['scheme'])) $data['scheme'] = “http”;

$url = $data['scheme'].”://”;
if (isset($data['user'])) {
$url .= $data['user'].(isset($data['pass']) ? “:”.$data['pass'] : “”).”@”;
}
$url .= $data['host'];
if (isset($data['port'])) {
$url .= “:”.$data['port'];
}
if (isset($data['path'])) {
$url .= $data['path'];
} else {
$url .= “/”;
}
if (isset($data['query'])) {
$url .= “?”.$data['query'];
}
if (isset($data['fragment'])) {
$url .= “#”.$data['fragment'];
}

return $url;
}

final static function fixURL($base,$link) {
if (!preg_match(’~^(http://[^/?#]+)?([^?#]*)?(\?[^#]*)?(#.*)?$~i’, $link.’#', $matchesLink)) {
return false;
}
if (!empty($matchesLink[1])) {
return $link;
}
if (!preg_match(’~^(http://)?([^/?#]+)(/[^?#]*)?(\?[^#]*)?(#.*)?$~i’, $base.’#', $matchesBase)) {
return false;
}
if (empty($matchesLink[2])) {
if (empty($matchesLink[3])) {
return ‘http://’.$matchesBase[2].$matchesBase[3].$matchesBase[4];;
}
return ‘http://’.$matchesBase[2].$matchesBase[3].$matchesLink[3];
}
$pathLink = explode(’/', $matchesLink[2]);
if ($pathLink[0] == ”) {
return ‘http://’.$matchesBase[2].$matchesLink[2].$matchesLink[3];
}
$pathBase = explode(’/', preg_replace(’~^/~’, ”, $matchesBase[3]));
if (sizeOf($pathBase) > 0) {
array_pop($pathBase);
}
foreach ($pathLink as $p) {
if ($p == ‘.’) {
continue;
} elseif ($p == ‘..’) {
if (sizeOf($pathBase) > 0) {
array_pop($pathBase);
}
} else {
array_push($pathBase, $p);
}
}
return ‘http://’.$matchesBase[2].’/’.implode(’/', $pathBase).$matchesLink[3];
}
}

?>

3. Библиотека FormsParser. Работает с формами. Заточена под DLE, но исправить недолго

листинг formsparser.class.php

<?php
class FormsParser {
public $action = “./”;
public $method = “get”;

public static $form_rule = array(
‘regexp’ => ‘#<form(\s)?(?(1)(.*))>(.*)</form>#isU’,
‘result’ => array(
2 => ‘params’,
3 => ‘body’
)
);
public static $input_rule = array(
‘regexp’ => ‘#<input(\s)?(?(1)(.*))/?>#isU’,
‘result’ => array(
2 => ‘params’
)
);
public static $select_rule = array(
‘regexp’ => ‘#<select(\s)?(?(1)(.*))>(.*)</select>#isU’,
‘result’ => array(
2 => ‘params’,
3 => ‘body’
)
);
public static $option_rule = array(
‘regexp’ => ‘#<option(\s)?(?(1)([^>]*))>((?:.*)(?=</option>)|(?:[^<>]+?))#isU’,
‘result’ => array(
2 => ‘params’,
3 => ‘value’
)
);
public static $textarea_rule = array(
‘regexp’ => ‘#<textarea(\s)?(?(1)(.*))>(.*)</textarea>#isU’,
‘result’ => array(
2 => ‘params’,
3 => ‘value’
)
);
public static $params_rule = array(
‘regexp’ => ‘#(\w*)\s*=\s*["\']?([^<>\s"\']*)["\']?#is’,
‘result’ => array(
1 => ‘key’,
2 => ‘value’
)
);

public function getForm($forms,$data) {
if (!is_array($forms)) {
$forms = $this->parseForms($forms);
}
foreach ($forms as $form) {
if ($data == array_intersect($data,array_keys($form['data']))) {
foreach ($form['data'] as $key => $value) {
$this->action = $form['action'];
$this->method = $form['method'];

if (is_array($value)) {
if (count($value) > 1) {
$form['data'][$key] = $value[1];
} else {
$form['data'][$key] = $value[0];
}
}
}
return $form['data'];
}
}
return false;
}

private function parseForm($body,$params) {
$data = array();

$params = $this->parseParams($params);
$data['action'] = (isset($params['action']) ? $params['action'] : ‘./’);
$data['method'] = (isset($params['method']) ? strtolower($params['method']) : ‘get’);

$inputs = $this->parseInputs($body);
$selects = $this->parseSelects($body);
$textareas = $this->parseTextareas($body);

$data['data'] = array_merge($inputs,$selects,$textareas);
return $data;
}

private function parseInputs($body) {
$data = array();
if ($inputs = self::matchRule(self::$input_rule,$body)) {
foreach ($inputs['params'] as $params) {
$params = $this->parseParams($params);
if (isset($params['name'])) {
$name = $params['name'];
$value = (isset($params['value']) ? $params['value'] : ”);
$data = self::addValue($data,$name,$value);
}
}
}
return $data;
}

private function parseSelects($body) {
$data = array();
if ($selects = self::matchRule(self::$select_rule,$body)) {
$count = count($selects['params']);
for ($i=0;$i<$count;$i++) {
$params = $this->parseParams($selects['params'][$i]);
if (isset($params['name'])) {
$name = $params['name'];
if ($options = $this->parseOptions($selects['body'][$i])) {
$data = self::addValue($data,$name,$options);
} else {
$data = self::addValue($data,$name);
}
}
}
}
return $data;
}

private function parseOptions($body) {
if ($options = self::matchRule(self::$option_rule,$body)) {
$data = array();
$count = count($options['params']);
for ($i=0;$i<$count;$i++) {
$params = $this->parseParams($options['params'][$i]);
if (isset($params['value'])) {
$data[] = $params['value'];
} else {
$data[] = $options['body'][$i];
}
}
return $data;
}
return false;
}

private function parseTextareas($body) {
$data = array();
if ($textareas = self::matchRule(self::$textarea_rule,$body)) {
$count = count($textareas['params']);
for ($i=0;$i<$count;$i++) {
$params = $this->parseParams($textareas['params'][$i]);
if (isset($params['name'])) {
$name = $params['name'];
$value = (isset($params['value']) ? $params['value'] : $textareas['value'][$i]);
$data = self::addValue($data,$name,$value);
}
}
}
return $data;
}

public function parseForms($page) {
if ($forms = self::matchRule(self::$form_rule,$page)) {
$count = count($forms['params']);
for ($i=0;$i<$count;$i++) {
$data[$i] = $this->parseForm($forms['body'][$i],$forms['params'][$i]);
}
return $data;
}
return false;
}

public static function matchRule($rule,$text) {
if (preg_match_all($rule['regexp'],$text,$match)) {
$result = array();
foreach ($rule['result'] as $matchKey => $resultKey) {
$result[$resultKey] = $match[$matchKey];
}
return $result;
}
return false;
}

private function parseParams($str) {
if ($params = self::matchRule(self::$params_rule,$str)) {
$params['key'] = array_map(’strtolower’,$params['key']);
$result = array_combine($params['key'],$params['value']);
return $result;
}
return false;
}

public static function addValue($data,$key,$values=”) {
if (!is_array($values)) {
$values = array($values);
}
foreach ($values as $value) {
if (isset($data[$key])) {
if (!is_array($data[$key])) {
$data[$key] = array($data[$key]);
}
$data[$key][] = $value;
} else {
$data[$key] = $value;
}
}
return $data;
}
}
?>

Ну и осталась самая мелочь - вывод формы, в которую вы будете вбивать данные для спама. Это очень просто делается в подключаемом файле form.html

<form method=”post” action=”./”>
URLs:<br/>
<textarea rows=’10′ cols=’50′ name=’urls’></textarea>
<br/>
Логин:<br/>
<input type=’text’ size=’50′ name=’login’><br/>
Пароль:<br/>
<input type=’text’ size=’50′ name=’password’><br/>
Email:<br/>
<input type=’text’ size=’50′ name=’email’><br/>
<br/>
О себе:<br/>
<textarea rows=’10′ cols=’50′ name=’info’></textarea>
<br/>
Собщение:<br/>
<textarea rows=’10′ cols=’50′ name=’msg’></textarea>
<br/>
<input type=’submit’ value=’Spam’>
</form>

И напоследок один многозначительный плюс. Как я уже сказал - благодарности принимаются в форме ссылок на пост и “спасибо” в комментариях, однако в первом случае ссылающийся может получить небольшую базу хороших DLE-сайтов.

На сегодня всё. Надеюсь, что не причинил этим постом вреда больше, чем пользы.

Можно скачать исходники здесь: http://uploadbox.com/files/48f6a6b290


Комментарии (15) на “Учим PHP и пишем спамилку для DLE”

  1. ZloyTony пишет:

    Хорошая статья. Неплохо было бы сделать подсветку синтаксиса php.

  2. Backs пишет:

    А не выложите ли архив исходных кодов- а то копировать не удобно :(

  3. bizon пишет:

    выложил

  4. Хабаровский бомж пишет:

    Чо не сидица?) Мог бы уже свой кодец налабать…

  5. PlainTeXT пишет:

    Сайты банят бысто за такой спам, неоднократно подтверждалось на практике))

  6. АВМастер пишет:

    PlainTeXT спасибо, теперь буду знать как конкурентов мочить. С утра начну с ТОПа, а завтра вторую страницу выдачи банить.

  7. Дмитрий пишет:

    Инвайтом на анти-капчу не поделитесь?

  8. bizon пишет:

    Пожалуйста: d71f886871

  9. Ivan пишет:

    Свеженький инвайт на anti-captcha
    0148085a38
    За новыми обращаться в аську: 484750200

  10. Андрей пишет:

    Здравствуйте.
    Подскажите пожалуйста, если стоит цель сделать аналогичное, но для реги профайлов на пхпбб, вбуллетин и прочих, то реализация сильно усложняется?

  11. Анатолий пишет:

    Ну и как пользоваться этим кодом?

  12. Павел пишет:

    Не так давно писал что-то подобное, но не справился. Спасибо за код с подробными комментариями! :)

  13. Slava пишет:

    Мне нужен небольшой скрипт для получения кукисов по логину и паролю- можете помочь с этим?

  14. Дмитрий пишет:

    Начал писать, свой постер. Такая проблема, для отображения каптчи нужны куки.
    В http.class.php есть параметр
    public $cookies = null;, скорей всего надо что-то в нем указывать, а вот что я не знаю.

Оставить комментарий

Имя (обязательно):
E-Mail (обязательно):
Ваш сайт: