Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Письмо с вложением
 
 автор: wyfinger   (03.01.2011 в 10:19)   письмо автору
 
 

Добрый день,
есть задача отправить письмо с вложением,
пытаюсь использовать следующее:
function XMail($from, $to, $subj, $text, $filename) {
    $f    = fopen($filename,"rb");
    $un   = strtoupper(uniqid(time()));
    $head = "From: $from\n";
    $head .= "To: $to\n";
    $head .= "Subject: $subj\n";
    $head .= "X-Mailer: PHPMail Tool\n";
    $head .= "Reply-To: $from\n";
    $head .= "Mime-Version: 1.0\n";
    $head .= "Content-Type:multipart/mixed;";
    $head .= "boundary=\"----------".$un."\"\n\n";
    $zag  = "------------".$un."\nContent-Type:text/html;\n";
    $zag  .= "Content-Transfer-Encoding: 8bit\n\n$text\n\n";
    $zag  .= "------------".$un."\n";
    $zag  .= "Content-Type: application/octet-stream;";
    $zag  .= "name=\"".basename($filename)."\"\n";
    $zag  .= "Content-Transfer-Encoding:base64\n";
    $zag  .= "Content-Disposition:attachment;";
    $zag  .= "filename=\"".basename($filename)."\"\n\n";
    $zag  .= chunk_split(base64_encode(fread($f,filesize($filename))))."\n";

    if (!@mail("$to", "$subj", $zag, $head))
        return 0;
    else
        return 1;

}


Проблема заключается в том, что файл $filename размером порядка 20 Mb, а ограничение на оперативную память, если я не ошибаюсь, 10 Mb, письмо не отправляется...
Что делать?

Насколько я понимаю письмо можно отправить и напрямую через сокеты, возможно ли в этом случае отправлять файл кусками, т.е. не загружая целиком и есть ли хороший кусок-пример?

  Ответить  
 
 автор: lightning.say   (03.01.2011 в 10:23)   письмо автору
 
   для: wyfinger   (03.01.2011 в 10:19)
 

http://softtime.ru/scripts/mailattach.php

  Ответить  
 
 автор: Trianon   (03.01.2011 в 11:25)   письмо автору
 
   для: wyfinger   (03.01.2011 в 10:19)
 

>Проблема заключается в том, что файл $filename размером порядка 20 Mb, а ограничение на оперативную память, если я не ошибаюсь, 10 Mb, письмо не отправляется...

>Насколько я понимаю письмо можно отправить и напрямую через сокеты,
Это несовсем равноценные методы.
В частности, все проблемы по корректному оформлению заголовка письма, отправляемого от имени Вашего сервера Вам придется решать самостоятельно.
Кроме того, на хостинге должен быть разрешен fsockopen на 25-й порт.
Это, в целях борьбы со спаммерами, тоже делают не всегда.
Но тем не менее, такой подход имеет право на существование.

>возможно ли в этом случае отправлять файл кусками, т.е. не загружая целиком
Безусловно, так и следует делать.

http://www.faqs.org/rfcs/rfc2821.html

  Ответить  
 
 автор: Wyfinger   (04.01.2011 в 06:37)   письмо автору
 
   для: Trianon   (03.01.2011 в 11:25)
 

Написал вот что, должно работать, но не работает. Я подозреваю, что smtp сервер меня временно банит (много подключался при отладке).
Посмотрите пожалуйста:
// Отправление письма с вложением
function SMail($server, $from, $from_pass, $to, $subject, $message, $file_name) {

    // Если файл указан, он должен существовать и читаться
    if($file_name != "")
        if(!file_exists($file_name) || !is_readable($file_name)) {
            return -1;
        }

    $f    = fopen($file_name,"r");
    $un   = strtoupper(uniqid(time()));

    $connect = fsockopen ($server, 25, $errno, $errstr, 30);
    fputs($connect, "EHLO localhost\r\n");
    fputs($connect, "AUTH LOGIN\r\n");
    fputs($connect, base64_encode($from)."\r\n");
    fputs($connect, base64_encode($from_pass)."\r\n");
    fputs($connect, "MAIL FROM:$from\r\n");            // Может быть MAIL FROM:<$from> ????
    fputs($connect, "RCPT TO:$to\r\n");                // Может быть RCPT TO::<$to> ????
    fputs($connect, "DATA\r\n");

    $headers   = "Date: ".date("D, j M Y G:i:s")." +0700\r\n";
    $headers  .= "From: <$from>\r\n";
    $headers  .= "Reply-To: <$from>\r\n";
    $headers  .= "X-Priority: 3 (Normal)\r\n";
    $headers  .= "To: <$to>\r\n";
    $headers  .= "Subject: =?windows-1251?Q?".str_replace("+","_",str_replace("%","=",urlencode($subject)))."?=\r\n";
    $headers  .= "MIME-Version: 1.0\r\n";
    $headers  .= "Content-Type: multipart/mixed;\r\n";
    $headers  .= "boundary=\"----------".$un."\"\n\n";

    $body    = "------------".$un."\nContent-Type:text/html;\r\n";
    $body   .= "Content-Transfer-Encoding: 8bit\n\n$message\r\n\r\n";

    $body   .= "------------".$un."\r\n";
    $body   .= "Content-Type: application/octet-stream; name=\"".basename($file_name)."\"\r\n";
    $body   .= "Content-Transfer-Encoding:base64\r\n";
    $body   .= "Content-Disposition:attachment; filename=\"".basename($file_name)."\"\r\n\r\n";

    // Отправка текста письма и заголовков
    fputs($connect, $headers);
    fputs($connect, $body);

    // Теперь читаем и отправляем файл кусками с буфером в 50 кб
    while($string = fgets($f, 50*1024)) {
        fputs($connect, chunk_split(base64_encode($string)));
    }
    // Завершение
    fputs($connect, "\r\n------------".$un."\r\n");
    fputs($connect, ".\r\n");
    while($str = fgets($connect,515))         // DEBUG ONLY !!!
  {                                           // DEBUG ONLY !!!
    echo $str;                                // DEBUG ONLY !!!
    if(substr($str,3,1) == " ") { break; }    // DEBUG ONLY !!!
  }                                           // DEBUG ONLY !!!
    fputs($connect, 'quit');                // Может быть QUIT ????
    fsockopen($connect);
    fclose($f);

}


Вызывать приблизительно так:
SMail("smtp-server", "from@mail.ru", 'from-password', "to-email", "subject", "message-text", 'file-to-attach');

  Ответить  
 
 автор: Trianon   (04.01.2011 в 08:02)   письмо автору
 
   для: Wyfinger   (04.01.2011 в 06:37)
 

    fputs($connect, "EHLO localhost\r\n");
    fputs($connect, "AUTH LOGIN\r\n");


Это не дело. Следует не только отправлять команды, но и читать, воспринимать и анализировать отклик.

  Ответить  
 
 автор: Wyfinger   (04.01.2011 в 13:03)   письмо автору
 
   для: Trianon   (04.01.2011 в 08:02)
 

Я анализировал во время отладки, до отправки тела сообщения все вроде нормально.
Вообще мне нужно отправить письмо с конкретного ящика на конкретный ящик, особой универсальности не требуется.
Я экспериментирую с mail.ru.

  Ответить  
 
 автор: Trianon   (04.01.2011 в 13:04)   письмо автору
 
   для: Wyfinger   (04.01.2011 в 13:03)
 

анализировать нужно в процессе диалога.
Отклики, отличные от ожидаемых, писать в лог.

  Ответить  
 
 автор: Wyfinger   (05.01.2011 в 13:23)   письмо автору
 
   для: Wyfinger   (04.01.2011 в 06:37)
 

Данная, отладочная версия функции работает:
// Отправление письма с вложением
function SMail($server, $from, $from_pass, $to, $subject, $message, $file_name) {

    // Если файл указан, он должен существовать и читаться
    if($file_name != "")
        if(!file_exists($file_name) || !is_readable($file_name)) {
            return "File not found or not readable";
        }

    $un   = strtoupper(uniqid(time()));

    $connect = fsockopen ($server, 25, $errno, $errstr, 30);
    fputs($connect, "EHLO localhost\r\n");
    while($str=fgets($connect,515)) { echo $str; if(substr($str,3,1)==" ") {break;} } echo "\r\n";
    fputs($connect, "AUTH LOGIN\r\n");
    while($str=fgets($connect,515)) { echo $str; if(substr($str,3,1)==" ") {break;} } echo "\r\n";
    fputs($connect, base64_encode($from)."\r\n");
    while($str=fgets($connect,515)) { echo $str; if(substr($str,3,1)==" ") {break;} } echo "\r\n";
    fputs($connect, base64_encode($from_pass)."\r\n");
    while($str=fgets($connect,515)) { echo $str; if(substr($str,3,1)==" ") {break;} } echo "\r\n";
    fputs($connect, "MAIL FROM:$from\r\n");            // Может быть MAIL FROM:<$from> ????
    while($str=fgets($connect,515)) { echo $str; if(substr($str,3,1)==" ") {break;} } echo "\r\n";
    fputs($connect, "RCPT TO:$to\r\n");                // Может быть RCPT TO::<$to> ????
    while($str=fgets($connect,515)) { echo $str; if(substr($str,3,1)==" ") {break;} } echo "\r\n";
    fputs($connect, "DATA\r\n");
    while($str=fgets($connect,515)) { echo $str; if(substr($str,3,1)==" ") {break;} } echo "\r\n";

    $headers   = "Date: ".date("D, j M Y G:i:s")." +0700\r\n";
    $headers  .= "From: <$from>\r\n";
    $headers  .= "X-Mailer: The Bat! (v3.99.3) Professional\r\n";
    $headers  .= "Reply-To: <$from>\r\n";
    $headers  .= "X-Priority: 3 (Normal)\r\n";
    $header   .= "Message-ID: <".rand().'.'.date("YmjHis")."@mail.ru>\r\n";
    $headers  .= "To: <$to>\r\n";
    $headers  .= "Subject: =?utf-8?Q?".str_replace("+","_",str_replace("%","=",urlencode($subject)))."?=\r\n";
    $headers  .= "MIME-Version: 1.0\r\n";
    $headers  .= "Content-Type: multipart/mixed;\r\n";
    $headers  .= "    boundary=\"----------".$un."\"\r\n\r\n";

    $body    = "------------".$un."\nContent-Type:text/html;\r\n";
    $body   .= "Content-Transfer-Encoding: 8bit\n\n$message\r\n\r\n";

    $body   .= "------------".$un."\r\n";
    $body   .= "Content-Type: application/octet-stream; name=\"".basename($file_name)."\"\r\n";
    $body   .= "Content-Transfer-Encoding:base64\r\n";
    $body   .= "Content-Disposition:attachment; filename=\"".basename($file_name)."\"\r\n\r\n";

    // Отправка текста письма и заголовков
    fputs($connect, $headers);
    fputs($connect, $body);

    // Теперь читаем и отправляем файл кусками с буфером в 50 кб
    $file    = fopen($file_name,"r");
    while($string = fread($file, 1*1024)) {
        fwrite($connect, chunk_split(base64_encode($string)));
    }
    // Завершение
    fputs($connect, "\r\n------------".$un."\r\n");
    //while($str=fgets($connect,515)) { echo $str; if(substr($str,3,1)==" ") {break;} } echo "\r\n";
    fputs($connect, ".\r\n");
    while($str=fgets($connect,515)) { echo $str; if(substr($str,3,1)==" ") {break;} } echo "\r\n";
    fputs($connect, 'quit');                // Может быть QUIT ????
    while($str=fgets($connect,515)) { echo $str; if(substr($str,3,1)==" ") {break;} } echo "\r\n";
    fsockopen($connect);
    fclose($f);

}


Письмо отправляется, приложение тоже.
Однако обнаружилась проблема с функцией base64_encode().
Дело в том, что
base64_decode(base64_encode("string1").base64_encode("string2")) <> string1string2


Может кто-нибудь детально знаком со стандартом base64, это так должно быть и как этого избежать?
(возможно нужно писать свою функцию)

  Ответить  
 
 автор: Wyfinger   (05.01.2011 в 13:25)   письмо автору
 
   для: Wyfinger   (05.01.2011 в 13:23)
 

в догонку: есть еще какие-нибудь стандарты кодирования для писем, кроме base64 ?

  Ответить  
 
 автор: Trianon   (05.01.2011 в 16:09)   письмо автору
 
   для: Wyfinger   (05.01.2011 в 13:25)
 

Quoted-Printable

Но кодировать им двоичные данные не выйдет в принципе, а большие объемы текстов с применением национальных алфавитов хоть и получится, но будет весьма неэффективным решением.

  Ответить  
 
 автор: Wyfinger   (05.01.2011 в 15:28)   письмо автору
 
   для: Wyfinger   (05.01.2011 в 13:23)
 

Вот эта функция работает:
// Отправление письма с вложением
function SMail($server, $from, $from_pass, $to, $subject, $message, $file_name) {

    // Если файл указан, он должен существовать и читаться
    if($file_name != "")
        if(!file_exists($file_name) || !is_readable($file_name)) {
            return "File not found or not readable";
        }

    $un = strtoupper(uniqid(time()));
    $log = "";

    $connect = fsockopen ($server, 25, $errno, $errstr, 30);
    fputs($connect, "EHLO localhost\r\n");
    while($str=fgets($connect,515)) {if(substr($str,3,1)==" ") {break;} $log .= "\r\n".$str; };
    fputs($connect, "AUTH LOGIN\r\n");
    while($str=fgets($connect,515)) {if(substr($str,3,1)==" ") {break;} $log .= "\r\n".$str; };
    fputs($connect, base64_encode($from)."\r\n");
    while($str=fgets($connect,515)) {if(substr($str,3,1)==" ") {break;} $log .= "\r\n".$str; };
    fputs($connect, base64_encode($from_pass)."\r\n");
    while($str=fgets($connect,515)) {if(substr($str,3,1)==" ") {break;} $log .= "\r\n".$str; };
    fputs($connect, "MAIL FROM:$from\r\n");            // Может быть MAIL FROM:<$from> ????
    while($str=fgets($connect,515)) {if(substr($str,3,1)==" ") {break;} $log .= "\r\n".$str; };
    fputs($connect, "RCPT TO:$to\r\n");                // Может быть RCPT TO::<$to> ????
    while($str=fgets($connect,515)) {if(substr($str,3,1)==" ") {break;} $log .= "\r\n".$str; };
    fputs($connect, "DATA\r\n");
    while($str=fgets($connect,515)) {if(substr($str,3,1)==" ") {break;} $log .= "\r\n".$str; };

    $headers  = "Date: ".date("D, j M Y G:i:s")." +0700\r\n";
    $headers .= "From: <$from>\r\n";
    $headers .= "X-Mailer: The Bat! (v3.99.3) Professional\r\n";
    $headers .= "Reply-To: <$from>\r\n";
    $headers .= "X-Priority: 3 (Normal)\r\n";
    $headers  .= "Message-ID: <".rand().'.'.date("YmjHis")."@mail.ru>\r\n";
    $headers .= "To: <$to>\r\n";
    $headers .= "Subject: =?utf-8?Q?".str_replace("+","_",str_replace("%","=",urlencode($subject)))."?=\r\n";
    $headers .= "MIME-Version: 1.0\r\n";
    $headers .= "Content-Type: multipart/mixed;\r\n";
    $headers .= "    boundary=\"----------".$un."\"\r\n\r\n";

    $body  = "------------".$un."\nContent-Type:text/html;\r\n";
    $body .= "Content-Transfer-Encoding: 8bit\n\n$message\r\n\r\n";

    $body .= "------------".$un."\r\n";
    $body .= "Content-Type: application/octet-stream; name=\"".basename($file_name)."\"\r\n";
    $body .= "Content-Transfer-Encoding:base64\r\n";
    $body .= "Content-Disposition:attachment; filename=\"".basename($file_name)."\"\r\n\r\n";

    // Отправка текста письма и заголовков
    fputs($connect, $headers);
    fputs($connect, $body);

    // Теперь читаем и отправляем файл кусками с буфером в 30 кб
    // (размер буфера должен быть кратеy 3 из-за специфики base64)
    $file = fopen($file_name,"r");
    while($string = fread($file, 30*1024)) {
        fwrite($connect, chunk_split(base64_encode($string)));
    }
    // Завершение
    fputs($connect, "\r\n------------".$un."\r\n");
    while($str=fgets($connect,515)) {if(substr($str,3,1)==" ") {break;} $log .= "\r\n".$str; };
    fputs($connect, ".\r\n");
    while($str=fgets($connect,515)) {
        if(substr($str,3,1)==" ") {break;}
        $log .= "\r\n".$str;
        if(intval(substr($str,0,3))!=250)  return $log;  // Ошибка, вернем лог
    };
    fputs($connect, 'quit');                // Может быть QUIT ????
    fsockopen($connect);
    fclose($f);

}


Проблема была с тем, что буфер должен быть кратен 3 из-за специфики base64.

  Ответить  
 
 автор: Trianon   (05.01.2011 в 16:12)   письмо автору
 
   для: Wyfinger   (05.01.2011 в 15:28)
 

кратность буфера у Вас задает не мифическая тройка, а [умалчиваемый] параметр функции chunk_split() (и конечно сам алгоритм base64, который 3 байта кодирует четырьмя символами. )
Фактически, буфер у Вас должен быть размером, кратным 58368, ну иль на худой конец - 29184.
А если не сильно жалко - 233472.
Проверяйте.

Кроме того эти дикие циклы с условиями на каждой реплике диалога, которые безусловно вполне оправданы сами по себе, всё же достойны оказаться вынесенными в отдельную функцию.
Неужели не тянет?!

  Ответить  
 
 автор: Wyfinger   (05.01.2011 в 16:57)   письмо автору
 
   для: Trianon   (05.01.2011 в 16:12)
 

Поясните откуда цифры, пожалуйста. Не понял.
chunk_split(), режет длинную base64 строку на короткие, разделенные \r\n.
Но для base64 нет символа \r\n, поэтому
base64_decode(chunk_split(base64_encode($string))) = $string

(для строки > 76 символов)

Или я где-то не прав? Вышеприведенную функцию проверял для буфера = 30 байт
и файла ~10 кБ. Работает верно.

А по поводу функции - эти циклы меня нисколько не напрягают, да и не важно это.

P.S. С поставленной задачей пока не справился - скрипт говорит, что письмо отправленно, т.е. smtp сервер вернул "успешно", но письма так и нет. Файл всего 20 Мб, а Маил.Ру говорит, что готов принять 30. Загадка...

  Ответить  
 
 автор: Trianon   (05.01.2011 в 17:00)   письмо автору
 
   для: Wyfinger   (05.01.2011 в 16:57)
 

>Поясните откуда цифры, пожалуйста. Не понял.
>chunk_split(), режет длинную base64 строку на короткие, разделенные \r\n.
на короткие строки, какой именно длины?
Понятно же, что выход должен быть кратен этой длине.
Иначе возникнут обрывки ничем не оправданные.

>(для строки > 76 символов)

Сколько байт исходного потока создаст 76 символов потока сообщения?
Совершенно очевидно, это не единственная кратнось, которую желательно предусмотреть при буферизации.
Какой еще кратный множитель выберем (читайте - Вы выбрали уже)?

  Ответить  
 
 автор: Wyfinger   (05.01.2011 в 17:34)   письмо автору
 
   для: Trianon   (05.01.2011 в 17:00)
 

Так ведь совершенно не обязательно, чтобы в закодированном виде все строки были
одинаковой длины. Важно чтобы исходные данные были кратны трем, тогда Base64 не будет выравнивать блок до 3 байтов нулями.

Строки:
3fLuIO/w7uLl8O737e7l
IPHu7uH55e3o5Swg5Ovo
7e3gIOru8u7w7uPuIOHu
6/z45SAyMCDh4Ony

и

3fLuIO/w7uLl8O737e7lIPHu7uH55e3o5Swg5Ovo7e 3gIOru8u7w7uPuIOHu6/z45SAyMCDh4Ony


декодируются одинаково.

  Ответить  
 
 автор: Trianon   (05.01.2011 в 17:50)   письмо автору
 
   для: Wyfinger   (05.01.2011 в 17:34)
 

>Так ведь совершенно не обязательно, чтобы в закодированном виде все строки были
>одинаковой длины.

Почему?

>Важно чтобы исходные данные были кратны трем, тогда Base64 не будет выравнивать блок до 3 байтов нулями.

Это ваше "Важно" важно не более и не менее, чем мое "обязательно" из абзаца выше.

Если Вы заглянете в стандарт, то увидите, что исходные данные вовсе не обязаны быть кратны трем, как и выходные - четырем:

----
The encoded output stream must be represented in lines of no more
than 76 characters each. All line breaks or other characters not
found in Table 1 must be ignored by decoding software.

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

  Ответить  
 
 автор: Wyfinger   (06.01.2011 в 01:28)   письмо автору
 
   для: Trianon   (05.01.2011 в 17:50)
 

Вы извините, я Ваших доводов не понимаю.
Вы приводите факты, подтверждающие лишь то, что кодировать нужно кратное 3 число байт,
а также то, что символы перевода строки (и все остальное) игнорируются при декодировании.

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

Почему же:
> Фактически, буфер у Вас должен быть размером, кратным 58368,
> ну иль на худой конец - 29184.
> А если не сильно жалко - 233472.

?

P.S. Мои письма с файлом 20 Мб так и не доходят, хотя с небольшими (1-2) Мб все нормально
и на большие smtp сервер говорит "Ok". Экспериментирую с разными почтовыми сервисами.

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

  Ответить  
 
 автор: Trianon   (06.01.2011 в 01:40)   письмо автору
 
   для: Wyfinger   (06.01.2011 в 01:28)
 

>Вы извините, я Ваших доводов не понимаю.
>Вы приводите факты, подтверждающие лишь то, что кодировать нужно кратное 3 число байт,
>а также то, что символы перевода строки (и все остальное) игнорируются при декодировании.

Если переводы строки все сплошь игнорировать , все кусочки окажутся вытянутыми в одну большую строку.
При этом абсолютно все равно, где были разрывы - через 3 символа, через 33 или через 3000.

Понятно, почему при некратном буфере происходит ошибка - у Вас просто не заполняется битами до конца четверка символов.

Непонятно, почему Вы считаете 3 осмысленной кратностью. Непонятно, но не особо интересно.
76 символов (выбранных функцией chunk_split) это 76/4 * 3 = 57 байт.
Вот эти 57 байт и есть осмысленная кратность.
Другая осмысленная кратность - размер физического сектора устройства - 512 байт (следствие архитектуры устройств внешней памяти)
Третья осмысленная кратность - распространенный размер страницы виртуальной памяти - 4096 байт (следствие процессорной архитектуры ) .
Умножьте одно на другое - получите эти числа.
Дальнейший спор считаю бессмысленным.

Ну а что двадцатиметровые письма не доходят - так может на сервере ограничение действует?

  Ответить  
 
 автор: Wyfinger   (06.01.2011 в 07:01)   письмо автору
 
   для: Trianon   (06.01.2011 в 01:40)
 

На счет размера страниц памяти я как-то не думал. Теперь не спорю.

А письма действительно не доходят из-за ограничений хостинга.
Буду переезжать.

  Ответить  
 
 автор: coloboc66   (01.08.2016 в 09:39)   письмо автору
 
   для: Wyfinger   (06.01.2011 в 07:01)
 

Тема письма на кириллице в utf-8 отображается корректно, а тело письма (сообщение) на кириллице выдаёт "кракозябры". Почему???

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования