Все про Интернет
       (N 384) 2011 - 2012
        << Архив передач >>
 Логин:  Пароль:
[регистрация]     запомнить 
 Поиск по сайту:
[Сайты зрителей] [Рейтинг] [Статьи] [Форум] [Блог] [Киберспорт] [Конкурсы] [О передаче]
 
Телефонная база абонентов своими руками

http://raxp.radioliga.com
(специально для Интернетомании)

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


Рис. 1. Телефонный справочник абонентов. Режим WEB монитора

С чего все начиналось и зачем это нужно? Сейчас уже никого не удивишь электронными телефонными справочниками, как локальными, так и онлайн. Появились даже такие “монстры-09” по всем городам СНГ, как MegaContacts [1]. Но у всех у них наблюдается несколько общих недостатков:

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

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

Краткий экскурс…

Что же такое – база данных? Само понятие ”база данных” появилось в 70-х годах прошлого столетия и обозначало любую упорядоченную совокупность данных. Как правило, нескольких файлов, где каждый файл представлял собой отдельную таблицу, содержащую одно или несколько полей базы. И по сей день все базы можно охарактеризовать следующими признаками:

  • возможность внесения изменений-обновлений в записи и модификаций в структуре таблиц
  • неоднократность использования несколькими пользователями
  • минимальная полнота данных для работы (“minimum minimore”)
  • оптимизация поисковых запросов (для ускорения пользования)
  • возможность защиты от несанкционироанного доступа (парольный доступ)
  • независимость от программы-оболочки
  • резервирование (создание дубликата базы в случае потери данных при сбое или намеренно)

Предпосылки реализации ПО. Существующие решения

Про уязвимость в PHP сценариях, обслуживающих онлайн-базы уже неоднократно упоминалось в глобальной сети. Найденные уязвимости позволяют взломщику на расстоянии выполнить произвольные SQL команды в базе данных или произвольный код на атакуемом сервере. Естественно, что под уязвимостью следует понимать не только ошибки в коде выполнения, но и элементарный недосмотр админа-програмиста или результаты “социальной инженерии”.

Уязвимость скрипта вы можете увидеть на примере следующего онлайн – справочника*
http://berdyansk.su/phone_private.php.

* аналогично для базы предприятий http://berdyansk.su/phone.php

Она заключается в недоработке алгоритма PHP скрипта выборки данных: если мы в поле поиска введем скажем 1 символ ”а”, то скрипт выдаст нам всю SQL базу с сервера (в архиве [2] вы найдете этот файл <1.htm>, размером около ~50МВ). А нам это и нужно. Но все-же недостаточно, ведь для дальнейшего использования необходимо привести ее в “удобоваримый вид”. Если взглянуть на содержимое файла внутри, то нужные нам поля ”Ф.И.О, Телефон, Адрес” будут выглядеть так:


<tr>
<td width="3%"><img src="images/10x10.gif" width="10" height="10"></td>
<td width="32%">Ф.И.О: <img src="images/10x10.gif" width="36" height="10"></td>
<td width="65%"><b>АБАВА Е.А.</b></td>
</tr>

<tr>
<td width="3%"><img src="images/10x10.gif" width="10" height="10"></td>
<td width="32%">Телефон: <img src="images/10x10.gif" width="36" height="10"></td>
<td width="65%"><b>снят</b></td>
</tr>

<tr>
<td width="3%"><img src="images/10x10.gif" width="10" height="10"></td>
<td width="32%">Адрес: <img src="images/10x10.gif" width="36" height="10"></td>
<td width="65%"><b>ул.ВЕРГОНОВА д.47 кв.8</b></td>
</tr>


естественно, что этот лишний “мусор” в базе нам никак не нужен. Как от него избавиться? Ведь вручную копировать записи дело неблагодарное. Для решения подобных проблем служат так называемые – ”парсеры”. Эти утилиты или программные модули просто осуществляют выборку нужных данных из общего ”хлама” за несколько секунд.

Поменьше слов - побольше дела…

Исходя из вышеизложенного, определим основные требования к нашему справочнику:

  • возможность произвольной выборки по телефону, адресу и расширенный поиск
  • возможность сортировки по выбранному полю (телефону, адресу, фамилии…) кликом на заголовке колонки поля
  • возможность подключения внешних баз, а также экспорта – импорта своей (локальной базы)
  • автономность базы и независимость, например от IDAPI/BDE (Borland Database Engine от Borland)
  • малый размер
  • возможность позвонить по выбранному номеру через модем
  • просмотр WEB камеры города

Вначале определимся со структурой данных в базе. Для построения справочника нам нужны следующие поля: “Телефон, Улица, Дом, Квартира, Ф.И.О. или название организаций”. Так как мы создаем простую базу, то целесообразней разместить все данные в одной таблице:

Таблица- Структура записей в базе
Имя поля Назначение
Телефон номер телефона
Улица место жительства
Дом номер дома
квартира номер квартиры
ФИО/Название инициалы абонента/название организации

По сути, эта структура и есть наша база, к созданию который мы и переходим…

Практика. Разработка ПО и средства отладки
Итак, приступим к основной задаче. Для работы нам понадобиться следующее:

  • среда Borland Delphi 5-7 (компиляция и отладка проекта парсера и телефонного справочника)
  • база абонентов для работы (входные данные)

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

“Ищейка берет след”. Парсим базу

Покажем, как реализовать на практике алгоритм парсера. Еще раз обратите внимание на содержимое файла <1.htm>: теги <td width="65%"><b> повторяются перед каждым набором данных, а значит, выделив то, что находится между ними и закрывающим тегом </b>, мы получим необходимую информацию:

Так как в исходной подстроке запись адреса (см. выше) ”ул.ВЕРГОНОВА д.47 кв.8” имеет цельный вид, то необходимо выделить отдельно: улицу, дом, квартиру. Для чего реализуем функцию окна поиcка в подстроке:

подгружаем "сырые данные" из файла <1.htm>
…
res:= tstringlist.Create;
res.LoadFromFile('1.htm');
…

поиск в подстроке
…
function sel(s: string; k: integer): string; //"ул.ВЕРГОНОВА д.47 кв.8"
var i,z,zz,zzz: integer;
    okno: string;
begin
 result:= '';
 //
 for i:=1 to length(s)-1 do begin //ищем начало "дом"
  okno:= s[i]+s[i+1];
  if okno= 'д.' then begin z:= i;break end
 end;
 for i:=length(s) downto 1 do begin //ищем первый пробел
  if s[i]= ' ' then begin zz:= i;break end
 end;
 zzz:= 0;
 for i:=1 to length(s)-1 do begin //ищем "кв"
  okno:= s[i]+s[i+1];
  if okno= 'в.' then begin zzz:= i;break end
 end;

 if k=1 then result:= copy(s,4,z-5);
 if (k=2)and(zzz<>0) then result:= copy(s,z+2,zz-z-2);
 if (k=2)and(zzz=0) then result:= copy(s,z+2,length(s));
 if (k=3)and(zzz<>0) then result:= copy(s,zz+4,length(s)-zz+4);
 if (k=3)and(zzz=0) then result:= ''
end;
…

Теперь реализуем функцию окна поиска строки:

собственно парсер
…
var i,j,z,k: integer;
      s,okno,b1,b2,b3,b4,b5: string; //временные переменные выборки
begin
 for i:= 0 to res.Count-1 do begin //перебираем все строки базы
  s:= res.Strings[i];
  okno := '';
  on_bd:= false;

  for j:= 1 to length(s) do begin
   okno:= copy(s,j,19); //поиск подстроки вида <td width="65%"><b>
   if okno = '<td width="65%"><b>' then begin
    for z:=j+19 to length(s) do if s[z]='<' then begin k:= z; break end; 
	//после найденной подстроки ищем закрывающий тег 
    application.ProcessMessages;
    //
    inc(gl); //счетчик записей-
    if gl=1 then b1:= copy(s,j+19,k-j-19);
    if gl=2 then b2:= copy(s,j+19,k-j-19);
    if gl=3 then begin //выборка по адресу- поиск в подстроке (см. выше)
     b3:= sel(copy(s,j+19,k-j-19),1);
     b4:= sel(copy(s,j+19,k-j-19),2);
     b5:= sel(copy(s,j+19,k-j-19),3);
     gl:=0; on_bd:= true //признак конца формирования 1- записи базы
    end
   end
  end;

  //загоняем найденную запись в базу-
  if on_bd then begin
   //sql- запрос
   bdc.Append;
   bdc.FieldValues['Телефон']:= b2;
   bdc.FieldValues['Улица']:= b3;
   bdc.FieldValues['дом']:= b4;
   bdc.FieldValues['кв'] := b5;
   bdc.FieldValues['ФИО/Название']:= b1;
   bdc.Post //обновить-
  end;
 end; 
bdc.SaveToFile('bd.cds') //сохраняем в бинарник

“Для чего нам понадобился BDC…?” – спросите Вы. Это есть не что иное, как компонент ClientDataSet из стандартной библиотеки DataAccess в Delphi. С помощью него мы будем производить добавление записи в нашу базу. Поскольку на выходе парсера (см. рис.2) получаемая база в бинарнике имеет размеры нескольких мегабайт, то для повышения скорости работы и уменьшения торможения при выборках рациональней держать ее прямо в ОЗУ. Что и делает этот компонент. Кроме того, использование ClientDataSet позволяет избавиться от необходимости каждый раз устанавливать BDE на машину, где будет эксплуатироваться база и соответственно реализовать автономное приложение. А используя методы компонента “SaveFile, LoadFromFile” мы получаем возможность экспорта-импорта нашей базы данных как в формате CSV (бинарном), так и широко распространненом сейчас XML, что обеспечивает независимость ПО от источника данных и соответственно придает универсальность оболочке справочника.


Рис. 2. Парсер базы

Управляем базой. Алгоритм выборки

Как правило, для ускорения работы с базой выбирают не все данные, а только те записи, что удолетворяют заданным пользователем критериям. Ведь весь смысл нашей затеи – именно удобный поиск… Эти критерии обеспечить достаточно просто, ведь существует так называемый фильтр, параметры которого можно задавать прямо в вышеупомянутом компоненте ClientDataSet (см. листинг 4) через свойство Filtered:

алгоритм выборки по базе (фильтр)
…
procedure Ttst.bdcFilterRecord(DataSet: TDataSet; var Accept: Boolean);
begin

 //функция POS дает "1" в случае совпадающего поискового запроса и 
 //записи в наборе данных DataSet
 if rb1.Checked then       //по номеру телефона
  accept:= (Pos(t, upcase(Dataset.fieldbyname('Телефон').asstring))>0);
 
 if rb2.Checked then begin //по улице/дому/квартире
 
 //если заполнено поле "улица"
 if (adr.Text<>'')and(dom.Text='')and(kom.Text='') then
   accept:= (Pos(a, upcase(Dataset.fieldbyname('Улица').asstring))>0);
 
 //если заполнено поле "дом"
 if (adr.Text='')and(dom.Text<>'')and(kom.Text='') then
   accept:= (Pos(d, upcase(Dataset.fieldbyname('дом').asstring))>0);
 
 //если заполнено поле "кв"
 if (adr.Text='')and(dom.Text='')and(kom.Text<>'') then
   accept:= (Pos(k, upcase(Dataset.fieldbyname('кв').asstring))>0);
 
 //если заполнено поле "улица, дом"
 if (adr.Text<>'')and(dom.Text<>'')and(kom.Text='') then
   accept:= (Pos(a, upcase(Dataset.fieldbyname('Улица').asstring))>0)and
            (Pos(d, upcase(Dataset.fieldbyname('дом').asstring))>0);
 
 //строгий поиск
 if (adr.Text<>'')and(dom.Text<>'')and(kom.Text<>'') then
   accept:= (Pos(a, upcase(Dataset.fieldbyname('Улица').asstring))>0)and
            (Pos(d, upcase(Dataset.fieldbyname('дом').asstring))>0)and
            (Pos(k, upcase(Dataset.fieldbyname('кв').asstring))>0);
 end;


 //расширенный поиск по любым введенным данным-
 if rb3.Checked then //по номеру телефона/улице/дому/квартире/ФИО-Названию
  accept:= (Pos(t, upcase(Dataset.fieldbyname('Телефон').asstring))>0)or
           (Pos(a, upcase(Dataset.fieldbyname('Улица').asstring))>0)or
           (Pos(d, upcase(Dataset.fieldbyname('дом').asstring))>0)or
           (Pos(k, upcase(Dataset.fieldbyname('кв').asstring))>0)or
           (Pos(f, upcase(Dataset.fieldbyname('ФИО/Название').asstring))>0);
end;
…

активизация выборки
…
bdc.Filtered:= false;	//удаляем предыдущий фильтр
bdc.DisableControls;	//блокируем набор данных до срабатывания выборки
bdc.Filtered:= true;	//включаем фильтр
bdc.EnableControls;	//разблокируем набор данных
…

База звонит?

Да-да, именно. Нет ничего проще позвонить по найденному номеру из базы. Для этого достаточно иметь любой подключенный к ТФоП (телефонной сети общего пользования) модем, а также свободный COM порт на вашем ПК и пользователю достаточно сделать двойной клик по найденной записи в таблице результатов. Эта функция реализуется так: выбираем свободный **COM (или виртуальный, если у вас USB модем) порт и посылаем в него следующую AT команду

  • в импульсном режиме 'ATDT '+ nomer + ';'+ #13 + #10 + 'ATH1'+ #13 + #10
  • в тональном режиме 'ATDP '+ nomer + ';'+ #13 + #10 + 'ATH1'+ #13 + #10

Где nomer - номер телефона в найденной записи. Модем, приняв данную последовательность команд, производит набор номера и поднимает трубку. Для того чтобы положить трубку, достаточно послать команду: 'ATH0'+ #13 + #10.

** сам модуль по работе с COM- портом вы найдете в [3].

Просмотр WEB камеры

В данной возможности уже нет ничего особенного и сложного. И все же такая мелочь привносит элемент интерактивности работы с базой, когда ты можешь увидеть не только безликие телефоны-адреса, но и “движение на улице”. При желании, более подробно ознакомиться с кодом реализации монитора WEB камер вы можете в [4].

Пользовательский интерфейс

Вот собственно и все. Лишь для удобства пользования выделим на форме отдельные панели для каждого типа поиска (см. рис.3), да и добавим сортировку данных по полю, воспользовавшись свойством IndexFieldNames='ваше поле' компонента ClienDataSet. В результает компиляции проекта имеем (см. рис.4, 5):


Рис. 3. Выбор типа поиска


Рис. 4. Определение критериев поиска


Рис. 5. Просмотр результатов

Заключение

Используя полученную оболочку пользователю не составит труда добавить в нее свою базу или оформить ее соответственно собственному вкусу и надобностям. Как пример, телефонный справочник “Запорожье-2007” [6]. Удачного поиска!

Полные исходные тексты, ресурсы проекта парсера и телефонного справочника (файл b09res.zip), а также исполняемый код (файл b09.zip) вы можете загрузить с сайта автора http://raxp.radioliga.com

Сокращенный вариант статьи опубликован в [7]

Ресурсы


Контактная информация:
raxp@mail.zp.ua

31.01.2009


[Переход к списку статей]

 
 

[Видеоархив]

Передача создана дизайн-студией Conus Video
По вопросам размещения рекламы или информации в передаче Internet@Mania пишите imania@mail.zp.ua, или звоните
8(0612)63-80-84


Share |
 
 


Провайдеры Запорожья
zp-provider.narod.ru
providers.portall.zp.ua
Домовые сети
linet.zp.ua
setka.zp.ua
biscom.zp.ua
homenet.zp.ua
www.16x.zp.ua
www.ss.zp.ua
www.skynet.zp.ua
www.watson.zp.ua
www.link.zp.ua
www.kichkas.net
www.neuro.zp.ua
innkom.zp.ua
Каталоги Запорожья
www.otvet.zp.ua
www.portall.zp.ua
www.zaporozhye.org
www.spravka.zp.ua
Форумы
www.forumzone.zp.ua
forum.mail.zp.ua
forum.tinet.zp.ua
forum.nulled-warez.org
forum2.biscom.zp.ua
myforum.net.ua
forum.ru-board.com
forstud.org.ua
Чаты
chatzone.zp.ua
4at.zp.ua
chatinet.zp.ua
chatik.zp.ua
Компьютерные сайты
www.ixbt.com
www.techlabs.ru
www.thg.ru
www.overclockers.ru
Игровые сайты
www.games.zp.ua
www.ag.ru
www.gamemag.ru
www.uaplay.com
www.gameg.info
Журналы
www.seti.com.ua
www.cpp.com.ua
www.shpil.com
www.chip.ua
Блоги
revolver.ru
dirty.ru
photoblog.ru
www.autoblog.ru

 
    Передача создана дизайн-студией Conus Video
    По вопросам размещения рекламы или информации в передаче Internet@Mania пишите нам imania@mail.zp.ua, или звоните 8(0612)63-80-84