Логин: Пароль: Забыли пароль? Регистрация
Рекламный блок

              

Страница 1 из 11
Форум » FOR WEB-MASTER`S » Учебник » Пишем свой PHP
Пишем свой PHP
cookДата: Пятница, 11.02.2011, 11:57 | Сообщение # 1

Уникальный Человек
Репутация: 1004
Сообщений: 1056
Награды: 3
Статус:
Бойко Артем (mr.prutik@mail.ru)

Разрабатываем собственный язык web-сценариев

Perl, Python, PHP, ASP – языков для веб-кодинга сейчас навалом, и все очень активно ими пользуются. Еще бы: динамический контент, удобное управление сайтом, форумы, "голосовалки", движки всякие. В общем, одним статичным HTML для создания сайта уже очень давно никто не обходится. Типичные ошибки, появляющиеся изо дня в день в скриптах на этих языках чуть ли не стандартизированы. Чувствуешь всю опасность ситуации? Чтобы сайт было действительно сложно сломать, он должен быть либо на обычном HTML, без всяких динамических наворотов, либо использовать свой собственный язык сценариев, еще неизвестный взломщику. А если учесть, что без динамического контента сейчас не жизнь, то у нас один выход – написать свой личный скриптовой язык и воспользоваться им при разработке сайта.

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

Интерпретатор web-языка может работать как cgi-приложение или как модуль web-сервера. Типичный модуль – это PHP. Типичные же представители cgi-языков – это Perl или Python. Ты, наверное, замечал, что скрипты для них помещены в отдельную папку (чаще всего cgi-bin), а первая их строка представляет собой что-нибудь вроде #!/usr/bin/perl. Если залезть в директорию /usr/bin/, то можно обнаружить там файл perl (perl.exe в windows) – это интерпретатор языка Perl. Это означает, что первой строкой в cgi-скриптах идет путь к приложению, ответвленному за их обработку. Web-сервер должен запустить его с такими параметрами, чтобы интепретатор понял, что ему нужно интерпретировать. Давай посмотрим, с какими. Для этого создавай в Си консольное приложение и вбивай туда следующий код:

#include <iostream>

#include <stdlib.h>

// подключаем нужные хидеры

using namespace std;

// пространство имен

int main(int argc, char *argv[])

{

for (int i = 0; i < argc; ++i)

{

printf(argv[i]);

// выводим переданный аргумент

printf("<br>");

// переходим на следующую строку

}

return 0;

// говорим, что все хорошо

}

Эта небольшая программка просто выводит каждый аргумент, с которым она была запущена. Нам очень важно разобраться, как же работают cgi-интерпретаторы, так как Apache будет ее запускать вовсе не на наших глазах. Компилируем код и сохраняем получившийся файл в /usr/bin/test.exe. Далее создаем файл /home/localhost/cgi-bin/test.tst (я использовал расширение tst, хотя ты можешь использовать любой - хоть обычный cgi) со следующим содержанием:

#!/usr/bin/test

// адрес нашего интерпретатора

print "Content-type: text/htmlnn";

// даем знать, какого типа возвращаемый результат

Открываем браузер и заходим по адресу: http://localhost/cgi-bin/test.tst. На экране мы увидим, что наша программа запускалась с двумя аргументами: /usr/bin/test и homeLOCALH~1cgi-bintest.tst. Несложно понять, что первый является адресом интепретатора, а второй - адресом скрипта на сервере, который мы открывали браузером. Многое стало ясно. Оказалось, что переменная argv[1] в Си будет содержать имя интерпретируемого файла.

[пишем основу]

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

Сотри все содержимое функции main, кроме последней строки, и введи следующее:

ifstream fin;

// Создаем обьект fin класса ifstream.

fin.open(argv[1]);

// Читаем исходный код нашей программы

char buf[80];

// Создаем буфер для чтения из файла

while (fin.getline(buf, 80)) // читаем построчно файл

{

// Здесь будет происходить обработка

// исходного кода нашего скрипта

}

Наш интерпретатор будет построчно читать файл и как-нибудь его интерпретировать. Реализовать построчную интерпретацию куда проще, чем хитрые многопроходные системы. Давай теперь придумаем синтаксис нашего web-языка. Придумаем и тотчас реализуем.

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

if (buf[0] == *"#" || strlen(buf) == 0) continue;

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

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

int line = 0;

И в самом начале цикла мы эту переменную увеличиваем на единицу:

++line;

Она нам еще пригодится.

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

struct my_type

{

char ch[30]; // имя переменной

char nm[255]; // значение переменной

};

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

my_type vars[999]; // массив структур my_type

int vars_count = 0; // текущее количество переменных

Так мы и будем хранить все переменные. Все очень просто. Чтобы ты понял, к чему я стремлюсь, я заранее приведу пример скрипта для нашего web-языка. Надеюсь, синтаксис у тебя не вызовет вопросов.

#!/usr/bin/test

# адрес интерпретатора

pragma = first

# название программы

var

# описание всех переменных после слова var

# переменная = значение

test1 = 0

test2 = 0

# start сообщает нас о начале кода

start

# числовые операции

test1 = 9

test2 = test1

stop

# после слова stop код вообще не читается

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

str_to_int(char * str);

// преобразовывает строку в число

exit_error(char * error, int line);

// выводит сообщение об ошибке кода

my_type get_vars(char* somevar);

// возвращает структуру переменных

// из строки вида "переменная = значение"

bool like(char * str1, char * str2);

// сравнивает две строки

void show_var(char * var);

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

[распознавание кода]

Для того чтобы скрипт читался правильно, предлагаю ввести переменную int step, которая бы показывала, на каком шаге выполнения сейчас находится наш код. Я ввел такую зависимость выполнения от значения переменной:

0 - мы на шаге поиска названия программы;

1 - на шаге поиска слова var;

2 - на шаге получения переменных и поиска слова start;

3 - на шаге выполнения кода и поиска слова stop;

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

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

if (like("show", buf)) // если найдена команда show

{

my_type bt = get_vars(buf);

// получаем структуру из текста вида "show = var"

show_var(bt.ch);

// Выводим на экран

}

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

plus var1 var2 - Равносильно var1 = var1 + var2

minus var1 var2 - Равносильно var1 = var1 - var2

multi var1 var2 - Равносильно var1 = var1 * var2

share var1 var2 - Равносильно var1 = var1 / var2

Так же мы можем добавить даже работу с MySQL. Можно в наш язык добавить поддержку циклов и, вообще, чего только душа пожелает. Но в данном примере я решил оставить только одну очень важную команду, без которой действительно не обойтись – это if. Шаблон у нее будет такой:

if var1 var2

#command

Принцип работы очень простой. Интерпретатор находит команду if, затем, если переменная var1 равняется переменной var2, выполняет команду, записанную в следующей строке, если они не равны, то команду он попросту игнорирует. Реализация проста, зато невероятно полезна. Например, ТОЧНОЕ сравнение строк можно произвести посредством трех функций: like, strstr и strlen.

После условия можно ввести уже не такую необходимую, но все равно очень полезную команду, которая выводила бы содержимое текстового файла, так как писать весь html-код в самой программе – это слишком. Команде я дал название read. Прототип такой:

read = var1

Найдя эту команду, интерпретатор открывает содержимое файла, записанного в var1, и выводит его нам на экран посимвольно. Реализуется команда несложно. В массиве структур находится именно та переменная, которая носит имя var1. Получается ее значение. Далее нами создается объект класса ifstream, с помощью которого читается файл и производится его посимвольный вывод.

Используя такой движок можно придумать любые команды. Главное - фантазию иметь.

[выжимаем из него все]

Основа у нас есть и, по-моему, неплохая. Теперь можно приступить к написанию собственного сайта на нашем языке. Идея сайта простенькая. Имеется домашняя страница. В ней 3 раздела: «контакты», «о себе» и «главная». Вся реализация - в одном файле. То есть, для того чтобы выполнить задуманное, нам придется работать с какой-то переменной. Брать мы ее будем из адреса посредством команды get. Также у сайта будет верхушка (файл top.txt), содержимое которого будет считываться на экран. Ниже приведен исходный код реализованной и вполне рабочей странички:

#!/usr/bin/dkt

# пример использования созданного веб-языка

# название программы

pragma = first

# описание переменных после слова var

var

# блок переменных

section1 = main

section2 = about

section3 = contact

file1 = main.txt

file2 = about.txt

file3 = contact.txt

top = top.txt

links = links.txt

bottom = bottom.txt

tmp = empty

emp =

# start означает начало программы

start

# читаем файл, который записан в переменной top

read = top

# читаем файл, который записан в переменной links

read = links

# получаем главную переменную

get tmp 1

# если она пуста (сравниваем с пустой переменной)

if tmp emp

# то выводим сообщение

show = '<center> выберите, пожалуйста, раздел </center>'

if tmp section1

read = file1

if tmp section2

read = file2

if tmp section3

read = file3

stop

Пример работы ты можешь увидеть на скриншоте. Это самый простой пример использования самой простой реализации нашего языка. Думаю, ты понял, что можно использовать html-код, который украсит все наши работы. Одна переменная может менять содержимое сайта, и наша одна страничка становится динамической. Между прочим, такую технологию можно будет использовать для смены шаблона.

[выводы]

Если у тебя сервак или хостер разрешит повесить свой бинарник в систему, то ты можешь использовать собственные web-проекты, разработанные так, как тебе удобно. Не всегда следует делать «как все». Иногда нужно выделиться из толпы. К тому же использование популярных вещей – это просто небезопасно.

INFO

В примерах я использую /usr/bin/, хотя на самом деле адрес у меня такой: k:/usr/bin/. Просто Apache собран так, как будто это /usr/bin/.

INFO

/home/localhost – рутовая директория нашего web-сервера, то есть именно отсюда будет черпать информацию пользователь, забравшийся браузером на localhost ;).

 
Форум » FOR WEB-MASTER`S » Учебник » Пишем свой PHP
Страница 1 из 11
Поиск:


Статистика форума Zorend.ru
Последние темы Популярные темы Лучшие пользователи Новые пользователи Звезды ZOREND`a
Глобальное обновление
Пара Анекдотов
Правила раздела
Считаем до 1000
Какая видео карта сейчас нормальная?
WebThumb 2.0 - Обмен посетителями на ваш сайт
халявные Icq налетай!
Аву плиз
 Считаем до 1000
 Конкурс "Уникальный человек"
 Участники конкурса "Уникальный человек"
 Играем в города :)
 Ваш аппарат
 Жалобы на участников конкурса "Уникальный человек"
 Зимняя шапка.
 Смайлики
Timoha - (Сообщений: 1091)
cook - (Сообщений: 1056)
pikus - (Сообщений: 1012)
Adrianoosem - (Сообщений: 419)
n1ceman - (Сообщений: 319)
b0ot - (Сообщений: 313)
sg-ua - (Сообщений: 250)
Аватар - (Сообщений: 250)
Alisasslom - (Зарегистрирован: 20.07.2015)
donkj4 - (Зарегистрирован: 20.07.2015)
meroslEr - (Зарегистрирован: 20.07.2015)
MelvinRat - (Зарегистрирован: 20.07.2015)
randiew16 - (Зарегистрирован: 20.07.2015)
ArthurGers - (Зарегистрирован: 20.07.2015)
CharlesCida - (Зарегистрирован: 20.07.2015)
guydd11 - (Зарегистрирован: 20.07.2015)
friendgog - (Репутация: 1187)
cook - (Репутация: 1004)
b0ot - (Репутация: 500)
pikus - (Репутация: 201)
Вадим - (Репутация: 102)
Timoha - (Репутация: 7)
-Wicked - (Репутация: 5)
plan - (Репутация: 5)