РНР 5 в подлиннике

Страница 43 из 554


88

Часть I. Основы Web-программирования

// иначе, если это "+", то заменяем его на " " else if(*st=' + 1) *р++=' ' ;

// а если ни то, ни другое — оставляем, как есть else *p++=*st; } while(*st++!=0); // пока не найдем нулевой код

}

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

Теперь мы можем слегка модифицировать предыдущий пример сценария, заставив его перед выводом данных декодировать их (листинг 3.6).

| Листинг 3.6. Файл c/postdecode.c

// Получение POST-данных с URL-декодированием. #include <stdio.h> #include <stdlib.h> #include "urldecode.c"

void main(void) {

// получаем значения переменных окружения char *RemoteAddr = getenv("REMOTE_ADDR"); char *ContentLength = getenv ("CONTENT_LENGTH") ,-//!! выделяем память для буфера QUERY_STRING

char *QueryString = malloc(strlen(getenv("QUERY_STRING")) + 1); //!! копируем QUERY_STRING в созданный буфер strcpy(QueryString, getenv("QUERY_STRING")); // декодируем QUERY_STRING UrlDecode(QueryString);

// вычисляем количество байтов данных — переводим строку в число int NumBytes = atoi (ContentLength);

// выделяем в свободной памяти буфер нужного размера

char *Data = (char*)malloc(NumBytes + 1);

// читаем данные из стандартного потока ввода

fread(Data, 1, NumBytes, stdin);

// добавляем нулевой код в конец строки

// (в С нулевой код сигнализирует о конце строки)

Data[NumBytes] - 0;

// декодируем данные (хоть это и не совсем осмысленно, но

// выполняем сразу для всех POST-данных, не разбивая их на параметры)

UrlDecode(Data);

// выводим заголовок

printf("Content-type: text/html\n\n") ; // выводим документ printf ("<htmlxbody>") ;

printf("<Ь1>Здравствуйте. Мы знаем о Вас все!</hl>");

Гпава 3. CGI изнутри

89

printf("Ваш ip-адрес: %s<br>",RemoteAddr); printf("Количество байтов данных: %d<br>", NumBytes); printf("Вот параметры, которые Вы указали: %s<br>",Data); printf("А вот то, что мы получили через url: %s",QueryString); printf ("</bodyx/html>") ;

}

Обратите внимание на строки, помеченные комментарием //!!. Теперь мы используем промежуточный буфер для хранения значения переменной окружения query_string. Зачем? Попробуем поставить все на место, т. е. не задействовать промежуточный буфер, а работать с переменной окружения напрямую, как это было в листинге 3.3. Тогда в одних операционных системах этот код будет работать прекрасно, а в других — генерировать ошибку общей защиты, что приведет к немедленному завершению работы сценария. В чем же дело? Очень просто: переменная QueryString ссылается на значение переменной окружения qoerystring, которая расположена в системной области памяти, а значит, доступна только для чтения. В то же время функция UrlDecode о, как мы уже замечали, помещает результат своей работы в ту же область памяти, где находится ее параметр, что и вызывает ошибку.

Чтобы избавиться от указанного недостатка, мы и копируем значение переменной окружения query_string в область памяти, доступной сценарию для записи — например, в какой-нибудь буфер, а потом уже преобразовываем его. Что и было сделано в последнем сценарии.

Несколько однообразно и запутанно, не так ли? Да, пожалуй. Но, как говорится, "это даже хорошо, что пока нам плохо" — тем больше будет причин предпочитать РНР другим языкам программирования (т. к. в РНР эти проблемы изжиты как класс).

Формы

До сих пор из всех полей формы мы рассматривали только текстовые поля и кнопки отправки (типа submit). Давайте теперь рассмотрим, в каком виде приходят данные от других элементов формы (а их существует довольно много).

Все элементы формы по именам соответствующих им тегов делятся на три категории:

L~) <input.. . >;

L~l <textarea. . .>. . .</textarea>;

L~l <select. . .xoption. . .>. . .</option>. . .</select>.

Каждый из этих тегов, конечно, может иметь имя. Ранее уже упоминалось, что пары имя=значение перед тем, как отправятся сценарию, будут разделены в строке параметров символом &. Кроме того, следует учитывать, что для тех компонентов формы, у тегов которых не задан параметр name, соответствующая строка имя=значение передана не будет. Это ограничение введено для того, чтобы можно было в форме определять служебные элементы, которые не будут посылаться сценарию. Например, в их число входят кнопки (подтверждения отправки или обычные, используемые при программировании на JavaScript) и т. д.




  Hostland.Ru

 «Бесплатный хостинг Hostland.Su» © 2006