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

Программирование в Web

  Все выпуски  

Программирование в Web Выпуск 20 от 18/12/2006 Основы PHP - Урок-14


 
Программирование в web

ОСНОВЫ PHP
 

 
Внимание!!!
Все материалы уроков, публикуемых в этом и во всех последующих выпусках рассылки «Программирование в web», являются интеллектуальной собственностью авторов и ведущих рассылки. По всем вопросам размещения или публикации данных материалов на собственных ресурсах или где-либо еще, или иного использования, не связанного с личным ознакомлением и самостоятельным обучением, - обращайтесь на адрес автора. Любое использование этих материалов в коммерческих или иных целях, явно не разрешенное автором, является незаконным.
 

 
У Р О К    14 — ПРАКТИКУМ
Здравствуйте уважаемые подписчики!

Снова у меня появилось немного времени, и вот, новый выпуск. В этом выпуске, помимо нашего Практикума будет наконец-то открыт блок Вопрос-Ответ. Так что можете начинать присылать свои вопросы. Сразу оговорюсь, что хотелось бы, чтобы на большинство вопросов отвечали сами подписчики. Не бойтесь делиться своим опытом, от этого никто не пострадает, а даже наоборот.


Ну что же, продолжаем наш Практикум и в этом выпуске будем модернизировать нашу гостевую книгу. Снова повторюсь, эта гостевая книга не претендует на звание шедевра. Шедевры будете делать вы сами, я же просто пытаюсь рассказать вам, что сделать что-то своими руками не слишком сложно, была бы развита фантазия, были бы необходимые знани, хорошая память и жажда эксперимента, — и вы сможете создать свой собственный проект любой сложности. Возможно у вас самих есть уже готовые какие-то решения и вы можете и желаете поделиться ими с другими подписчиками, присылайте, и, если они не очень большие по размеру, я их опубликую с разбором каждого дейтсвия в ближайшем выпуске. Не жадничайте.Итак, продолжим…



МОДЕРНИЗИРОВАННЫЙ КАРКАС ГОСТЕВОЙ КНИГИ:

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


Поля, которые заполняет посетитель:
Поле Имя или Ник (обязательное поле);
Поле e-mail адрес (обязательное поле);
Поле адреса сайта;
Поле номера ICQ;
Поле сообщения (обязательное поле);
Автоматические поля:
Дата;
Время;
IP-адрес посетителя;
И для дальнейшего развития - пустое поле для ответа модератора.

Что же, в предыдущем варианте у нас не было проверки на предмет того, что правильно ли посетитель ввел свои обязательные данные и ввел ли он их вообще. Таким образом, любой посетитель, который пожелает немного похулиганить, сможет добавить множество пустых записей, что естественно скажется на внешнем облике нашей гостевой книги. Попробуем решить эту проблему.


Дизайн гостевой книги, как договорились ранее, вы сделаете сами, здесь же сосредоточимся на самом сценарии. Код предыдущего вариант я приводить не буду, а сразу приведу код модернизированного вариант, а о конкретных изменениях поговорим после этого кода, то есть чуть ниже по тексту. Итак вот измененный код сценария:


<?php

//////// Форма ////////
print '<table align="center" cellpadding="1" cellspacing="0" border="0" width="90%">
<form method="post" name="guestbook">
<tr><td align="left" width="25%"><b>Имя или Ник:(*)</b></td>
<td align="left"><input type="text" name="postername" size="25" value="';
if (isset($cleanform)) {echo "";}
else {echo $_REQUEST['postername'];}
print'"></td></tr><tr><td align="left" width="25%"><b>E-mail адрес:(*)</b></td>
<td align="left"><input type="text" name="posteremail" size="25" value="';
if (!isset($_REQUEST['posteremail'])||$_REQUEST['posteremail']==""||isset($cleanform)) {echo "@";}
else {echo $_REQUEST['posteremail'];}
print '"></td></tr><tr><td align="left" width="25%"><b>Адрес сайта:</b></td>
<td align="left"><input type="text" name="posterweb" size="25" value="';
if (!isset($_REQUEST['posterweb'])||$_REQUEST['posterweb']==""||isset($cleanform)) {echo 'http://';}
else {echo $_REQUEST['posterweb'];}
print '"></td></tr><tr><td align="left" width="25%"><b>Номер ICQ:</b></td>
<td align="left"><input type="text" name="postericq" size="25" value="';
if (isset($cleanform)) {echo "";}
else {echo $_REQUEST['postericq'];}
print '"></td></tr><tr><td align="left" width="25%"><b>Ваше сообщение:(*)</b></td>
<td align="left"><textarea name="postermess" ROWS="7" COLS="35">';
if (isset($cleanform)) {echo "";}
else {echo $_REQUEST['postermess'];}
print '</textarea></td></tr>
<tr><td colspan="2" align="center"><input type="submit" name="posting" value="Добавить"></td></tr>
<tr><td colspan="2" align="center">
<hr width="80%">
<table align="center" cellpadding="1" cellspacing="1" border="0" width="90%">
<tr><td align="center">
<font color="darkblue">Поля, помеченные звездочкой (*), обязательны для заполнения!!!</font>
</td></tr></table>
</td></tr></table>
<hr width="80%">';
print $alerted;
//////// Конец формы ////////

//Пишем код обработчика добавления новой записи
if(isset($_REQUEST['posting'])) { // Если нажата кнопка "Добавить" - Начинаем добавление сообщения в базу данных сообщений
$nameposter=htmlspecialchars(trim($_REQUEST['postername'])); // Принимаем из формы имя или ник отправителя
$emailposter=htmlspecialchars(trim($_REQUEST['posteremail'])); // Принимаем из формы email-адрес отправителя
$messposter=htmlspecialchars(trim($_REQUEST['postermess'])); // Принимаем из формы текст сообщения отправителя
// Проверяем, заполнено ли поле номера ICQ, если заполнено и заполнено правильно, то принимаем его
// из формы, иначе принимаем пустую строку
if ((preg_match('/^[0-9]{5,10}$/is', trim($_REQUEST['postericq'])))==1)
{$icqposter=htmlspecialchars(trim($_REQUEST['postericq']));}
else {$icqposter="";}
// Проверяем, заполнено ли поле Web-адреса, если заполнено и заполнено правильно,
// то принимаем его из формы, иначе принимаем пустую строку
if (trim($_REQUEST['posterweb'])!=""||trim($_REQUEST['posterweb'])!="http://")
{$webposter=htmlspecialchars(trim($_REQUEST['posterweb']));}
else {$webposter="";}
// Выражение для проверки корректности введенного email-адреса отправителя.
// Оно построено на работе с регулярными выражениями, его
// разбором займемся чуток позже, но кто знаком с
// регулярными выражениями Perl - тот уже знает что в нем
// проверяется.
$correct_email='/^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_.-]+)([.]{1})([a-zA-Z0-9]{2,4})$/is';
// Проверяем, заполнены ли все обязательные поля и правильно ли
// заполнено поле email-адреса отправителя
if($nameposter!=""&&(($emailposter!=""||$emailposter!="@"||strlen($emailposter)>=6)&&((preg_match("$correct_email", $emailposter))==1))&&$messposter!="")
{ // Если все обязательные поля заполнены, то...
// Проверяем на флуд
if ((($_COOKIE['flood']==true)||($_SESSION['flood']==true))&&($floodfilter))
{$alerted='<table align="center" cellpadding="1" cellspacing="1" border="0" width="90%"><tr>
<td align="center"><center><font color="red" size="2">Антифлуд!!!<br>
Вы можете отправить не более одного сообщения за сессию!!!</font></center><br>
</td></tr></table><hr width="80%">';}
else {
// Создаем массив по новому сообщению, подготавливая его для записи в файл базы данных сообщений
$data=array(
"name"=>$nameposter,
"email"=>$emailposter,
"web"=>$webposter,
"icq"=>$icqposter,
"mess"=>$messposter,
"ip"=>$ipguest,
"date"=>"$dayguest г.  $timeguest",
"host"=>$hostguest,
"agent"=>$agentguest,
"ans"=>""
);
// Сохраняем новое сообщение в файле базы данных сообщений
$f=fopen("data/base.php", "a+"); // Открываем файл базы сообщений (если файл не существует, то он будет создан
flock($f, LOCK_EX); // Блокируем доступ к файлу для других процессов
fwrite($f,serialize($data)."\n"); // Запаковываем и записываем сообщение в файл базы
flock($f, LOCK_UN); // Снимаем блокировку с файла
fclose($f); // Закрываем файл
unset($_REQUEST['posting']); // Сбрасываем переменную, хранящую состояние кнопки Добавить
// Устанавливаем переменную, по которой определяем, нужно ли форму очистить или нет
// Здесь задумка такая, если в форме не все обязательные поля
// заполнены, или некоторые поля заполнены не правильно, мы
// возвращаем все еще заполненную форму, чтобы проще было внести
// исправления, если же данные приняты и все корректно,
// произведем добавление этой новой записи в базу и очистим
// форму, для этого и служит эта переменная. Можно все это
// сделать по другому, но я здесь пошел по этому пути.
$cleanform=1;
// В этой переменной мы храним сообщение, которое будет
// выведено, после попытки добавления новой записи
$alerted='<table align="center" cellpadding="1" cellspacing="1" border="0" width="90%">
<tr><td align="center"><center><font color="darkblue">
<b>Ваше сообщение успешно добавлено!!!</b></font></center><br> ;</td></tr></table><hr width="80%">';
// Следующие три строчки предназначены для защиты от флуда
// Этими строками мы устанавливаем кукисы, которые
// сигнализируют, что этим посетителем запись в базу уже
// добавлена
setcookie("flood", "true", time()+3600*24*365); // Этот куки будет жить целый год :)
$_SESSION['flood']=true; // Помещаем в переменной сессии информацию о том, что запись этим посетителем уже добавлялась
$_COOKIE['flood']=true; // Подстраховываемся и тоже самое, что в переменную сессии, помещаем и в переменную куки
// А следующие две строки обновляют страницу гостевой книги
// Спросите зачем? Все просто, если мы этого не сделаем, то
// запись будет показана, но если вдруг мы решим нажать кнопку
// браузера Обновить, браузер запросит нас о повторной
// отправке данных. Мы можем отказаться, и тогда мы будем
// перенаправлены на системную страницу ошибки, либо можем
// согласиться, и тогда браузер попытается повторно отправить
// данные в базу гостевой (а если нет проверки на флуд, то в
// гостевой книге появятся две абсолютно одинаковые записи. Это
// не то, что нам нужно, поэтому мы насильно заставляем браузер
// перезагрузить страницу без повторной отправки данных.
Header("Location:$siteaddress/index.php?cat=modules&page=guestbook");
exit(); // Завершаем работу сценария
}
}
else { // Если не все обязательные поля заполнены, то выводим это сообщение
$alerted='<table align="center" cellpadding="1" cellspacing="1" border="0" width="90%"><tr>
<td align="center"><center><font color="red" size="2">Вы, либо не заполнили все обязательные поля,<br>
(помечены звездочкой (*)),<br>либо неправильно заполнили поле email-адреса!!!</font></center><br>
</td></tr></table><hr width="80%">';
unset($_REQUEST['posting']);
}

} // Пишем обработчик показа записей
if(file_exists("data/base.php")){ // Если файл базы существует, то осуществляем показ записей
$guesty=file("data/base.php"); // Читаем данные из файла базы
// Переворачиваем массив, чтобы самая последняя запись стала
// самой первой, то есть при показе записей на странице самая
// свежая запись будет самой первой, а самая старая - самой
// последней
$guesty=array_reverse($guesty);
foreach($guesty as $guest) {
if ($guest=="") {continue;} //Если попалась пустая строка в файле, просто игнорируем ее
$gues=unserialize($guest); // Распаковываем очередную запись
// Показываем очередную запись
print "<table width=\"98%\" align=\"center\" cellpadding=\"2\" cellspacing=\"1\" border=\"0\"><tr>";
print "<td width=\"100%\" align=\"left\"><b>Сообщение от:</b> 
<a href=\"mailto:$gues[email]\"><b>$gues[name]</b>< /a>";
print "   <b>Адрес web-сайта:</b> 
<a href=\"$gues[web]\" TARGET=\"_blank\">$gues[web]</a>";
print "   <b>ICQ:</b> 
<a href=\"http://www.icq.com/whitepages/wwp.php?uin=$gues[icq]\" TARGET=\"_blank\"><b>$gues[icq]</b></a></td></tr>";
$guesmess=htmlspecialchars(trim($gues['message']));
print "<tr><td width=\"100%\"><br><p>$guesmess</p><br></td></tr>";
print "<tr><td width=\"100%\" align=\"left\">
<b>Сообщение добавлено:</b> $gues[date]   <b>С IP-адреса:</b> $gues[ip]</td></tr>";
print "</tr></table><hr width=\"80%\">";
}
}
else {print("<center><font color=\"red\" size=\"2\">Записей нет!</font></center>");} // Если файл базы отсутствует

?>

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


Все проверки, собственно говоря, мы, естественно, помещаем в код обработчика добавления новой записи (а где же ему еще быть?). Все строки достаточно комментированы, поэтому, думаю, сложности в понимании кода у вас не должно возникнуть. Единственно, вы наверняка обратили внимание на вот эту строку - $correct_email='/^([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_.-]+)([.]{1})([a-zA-Z0-9]{2,4})$/is';. Что же происходит в этой строке? Переменной $correct_email присваивается какое-то значение. Это самое значение не что иное, как регулярное выражение которое позволяет проверить корректность введенного адреса электронной почты. Подробнее о регулярных выражениях мы еще будем разговаривать в последующих уроках, и тогда же вы сможете достаточно легко понять, что это выражение конкретно означает. Сейчас же скажу лишь, что проверка по регулярному выражению здесь применена по той причине, что она в данном случае оказывается намного проще других способов, а также все адреса электронной почты достаточно стандартизированы, а именно, всегда до знака @ стоит имя почтового ящика, как правило, оно в адресе присутствует обязательно. Далее, после @ всегда идет имя домена почтового сервера, предоставляющего электронный адрес, затем идет точка и имя домена верхнего уровня для почтового сервера. Таким образом адреса вида 1@1, @.com и другие будут некорректными и именно их мы не допустим в нашу базу сообщений а предложим посетителю ввести правильный адрес (пусть он даже будет не существующим (это проверить конечно можно, но вряд ли в этом будет участвовать посетитель, а это не то, что нам нужно), но он будет правильным с точки зрения стандартизации электронных адресов).


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


Вот практически и готова наша гостевая книга, а точнее ее каркас. У нас уже есть в ней проверки ввода обязательных полей и корректности вводимых данных, есть некоторая, пусть и не совершенная, защита от флуда (захламление мусорными сообщениями), предусмотрено поле для ответа администратора (на случай, если будет сделана панель администрирования гостевой). Самая свежая запись всегда будет самой первой отображена. Но, еще раз повторюсь, эта гостевая книга еще очень далека от совершенства. Так, мы хоть и немного обезопасили ее, но все равно еще позволяем писать различные теги и различные скриптики в наши сообщения. В большинстве случаев они конечно не сработают, но кому хочется видеть в записях какую-нибудь рекламу с адресом какого-нибудь рекламируемого ресурса? Кроме того, наша гостевая книга пока будет показывать все сообщения, сколько бы их в базе не было, на одной странице, что, сами понимаете, при достаточно большом количестве этих самых сообщений ничуть не ускорит загрузку и показ страницы. Естественно, нам стоило бы подумать о страничной организации отображения записей, допустим показывать записи по 10 штук на страницу. Вот об этом я предлагаю подумать вам самим. А заодно, кто решит эту задачу, возможно пожелаете поделиться с другими. Могу сказать, что решить эту проблему будет не просто, если, конечно, вы не найдете в сети уже готовые решения. Я предлагаю решить эту проблему самостоятельно! Тем более, что все необходимое для этого мы уже изучили. Могу дать небольшую подсказку, — без циклов вам скорее всего не обойтись. Ваши решения присылайте мне на мой адрес, все правильные самые лучшие решения будут обязательно опубликованы в ближайших выпусках. Решение должно быть с подробными комментариями, что и почему вы сделали именно так, а не иначе.


 

 
Ваши вопросы:
Вопрос от Nadina

Вопросы по материалам тринадцатого урока:
1. php-код для такой гостевой страницы может вставляться в html-код страницы или вся страница должна быть php?
2. И второй вопрос - нужно ли дополнительное программное обеспечение на компьютере, чтобы писать php. Если да - то какое именно.


Ответ ведущего:

Ответ на первый вопрос: Есть несколько способов интеграции HTML-кода и кода PHP: один - и HTML и PHP находятся в одном файле с расширением, которое предусмотрено для php-сценариев, и располагаются отдельными блоками, отдельно блок php-сценария и отдельно блок html-кода, при этом не забывайте, что сценарий php должен обязательно обрамляться тегами открытия и закрытия сценария; другой - код php вставляется в код html находящемся в файле с расширением для сценариев php; третий - код php прерывается и закрывается закрывающим тегом, затем пишется необходимое количество кода html, затем снова открывается сценарий php и продолжается его код, все это, естественно, в файле с расширением для php-сценариев; четвертый - можно поступить так, как я поступил в нашем сценарии гостевой книги, то есть выводить код HTML по команде print или echo PHP, представляя код HTML в виде строк или предварительно присвоив этот код строково й переменной; пятый - код PHP и код HTML находятся в разных файлах, но с расширениями для сценариев PHP и подключаются друг к другу по инструкции include (require...), при этом будет абсолютно не важно что включается во что, вы можете включить php сценарий в файл с кодом HTML или же наоборот, подключать код HTML в код PHP, этот способ хорош тем, что позволяет отделить дизайн от исполняемого кода; шестой - код HTML и код PHP располагаются в разных файлах, при этом код HTML в файле с раширением отличным от расширения для сценариев PHP, в этом случае вы сможете включить только файл с HTML кодом в файл сценария, но не наоборот, этот способ также как и предыдущий хорош для максимального отделения дизайна от программы; седьмой способ - шаблонизация, о нем в одном из последующих уроков.


Ответ на второй вопрос: Никакой специальный софт для написания PHP-программ вам не нужен. Вы легко можете воспользоваться любым удобным для вас текстовым редактором (правда, не рекомендовал бы вам использовать для этих целей Word и аналогичные ему, файлы php-сценария должны быть именно текстовыми), например, можете воспользоваться даже стандартным NotePad. Лично я использую два редактора - HTMLReader и NotePad++, оба достаточно удобны и бесплатны. Что касается отладки программ на PHP, то для этих целей сцществует масса всевозможных решений. Можно написать на 100 процентов работоспособный код и не проверяя его закинуть на сервер (но кто гарантирован от ошибок?), можно отлаживать ваши сценарии непосредственно на сервере (не всегда удобно и чаще всегда дороговато), а можно воспользоваться различными, предназначенными им енно для этого, комплексами. Таких комплексов существует тоже немало, но, лично я предпочитаю комплекс Denwer. Прост в установке, не требует никакой особой настройки, легок для скачивания, бесплатен, позволяет отлаживать не только PHP-сценарии, но и Perl, Asp, Phyton, имеет в своем составе сервер MySQL и повзоляет подключить любой другой, например, PostGreSQL, кроме того вы можете отлаживать свои сценарии, создав виртуальный хостинг с именем, аналогичным имени вашего хостинга на удаленном сервере и вызывать его по адресу так, как-будто вы находитесь в сети. В общем рекомендую использовать именно его.


 

 
Ответы на ваши вопросы:

Пока ответов не поступало, так как еще не было и вопросов :) . Если к следующему выпуску пришлете ваши вопросы, то, возможно к послеследующему выпуску пришлют и ответы. Если вопросов и ответов будет много, выпуски буду стараться делать чаще.


 

 
Объявления!!!

Следующий выпуск рассылки ожидайте скорее всего уже в Новом 2007 году. Постараюсь не затягивать с ним, но, если будет время, возможно сделаю выпуск и еще до Нового года.

В последующих выпусках планируется сделать блок вопросов и ответов, в котором вы сможете задавать интересующий вас вопрос (касающийся, естественно, уже пройденных уроков, без забегания вперед), и, в котором другие подписчики смогут дать ответ на ваш вопрос. Если вы считаете, что данный блок был бы желателен в рассылке, прошу написать на мой адрес любое, даже пустое письмо, главное, чтобы в письме присутствовала тема, в которой вы и дадите свой ответ на это мое предложение, например, тема может быть такой: "...Наличие блока вопрос-ответ обязательно..." или "...Блок вопрос-ответ не нужен..." или "...Было бы неплохо создать блок вопрос-ответ...", в общем, вот в таком плане. Односложные темы, типа "Да" или "Нет" создавать не стоит, так как антиспамовый фильтр моей почтовой программой может просто-напросто принять такое письмо за спам и у далить его с сервера, либо, если фильтр не сработает, то я сам могу не понять что означают эти темы, и, не глядя, удалить такое письмо, таким образом я не смогу узнать вашего мнения по этому вопросу.

Если у вас возникли какие-то вопросы, не стесняйтесь, задавайте. Для этого, всего лишь, пошлите на мой адрес письмо с вопросом и с темой, в которой обязательно укажите какого урока и какого языка касается вопрос. Например, тема может быть такой - «Основы PHP. Урок 13. Вопрос». Также, с такой же темой и на этот же адрес вы можете прислать и свои дополнения к уроку. Если дополнения будут существенными, то в последующих уроках они обязательно будут учтены.

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

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

Маленькая просьба. Многие из вас присылают мне запросы на отправку им того или иного, не полученного ранее, выпуска рассылки. У меня не всегда есть возможность это сделать. Поэтому предлагаю вам для начала посмотреть нужный выпуск в архиве рассылки. Рассылка выходит сразу на трех рассыльных сервисах, и по некоторым причинам (мне не известным) некоторые сервисы не принимают адресов, в которых встречаются именя конкурирующих рассыльных сервисов, по этой причине я опубликую только одну ссылку на архив рассылки только одного рассыльного сервиса, а именно Content.mail.ru. Вот ссылка на на этот архив рассылки - http://content.mail.ru/pages/p_21931.html. В обще м-то это объявление наверное лишнее, ведь в каждом выпуске каждой рассылки, вне зависимости от того, на каком сервисе она выходит, всегда указан этот самый адрес архива рассылки. На сабскрайб.ру и на контент.мэйл.ру этот адрес указывается в самом низу выпуска, а на мэйллист.ру - в самом верху выпуска. Так что, при достаточном внимании, вы сами легко сможете найти нужную ссылку на архив рассылки.

 

 
Внимание!!!
Все материалы уроков, публикуемых в этом и во всех последующих выпусках рассылки «Программирование в web», являются интеллектуальной собственностью авторов и ведущих рассылки. По всем вопросам размещения или публикации данных материалов на собственных ресурсах или где-либо еще, или иного использования, не связанного с личным ознакомлением и самостоятельным обучением, - обращайтесь на адрес автора. Любое использование этих материалов в коммерческих или иных целях, явно не разрешенное автором, является незаконным.
 

 
Наш проект и наши друзья
Автор рассылки — Anatolick
Архив рассылки — http://content.mail.ru/pages/p_21931.html
Сайт проекта — «Russian discussions Zone»
Движок для небольших сайтов — «Tanat-Engine»
Проект Web Help — «Web-Help.int.ru»
Дискуссионный лист — «Все для Всех о РС»
Дискуссионный лист — «File Info Masters»
Дискуссионный лист — «Напряги мозги»
Дискуссионный лист — «Ищем все…»
Дискуссионный лист — «Все обо Всем по Email»
Дискуссионный лист — «Внимание! Розыск…»
Дискуссионный лист — «Английский для Всех и каждого»
Группа стандартизации в Web — W3C.org
 

В избранное