Так уж сложилось у веб-мастеров, что на их сайты заходят как пользователи, так и спамерские роботы. Если первые заходят на сайт для поиска нужной информации, то вторым непременно подавай адреса e-mail'ов. Так называемые флудеры, которым попросту от нечего делать или от небольшого интеллекта так и хочется завалить ваши новости, статьи бестолковой лексикой. Ну а форум сообщениями, явно не относящимися к тематике рассматриваемой темы. Это неизбежно, как и то что за ночью приходит день и наоборот. Но с этим нужно бороться - иначе ваши порядочные пользователи вовсе потеряют интерес к вашему сайту - можете не сомневаться.
Самым простой метод противодействия данным явлениям - это банить таких посетителей по ip. Проще говоря, закрывать им доступ на ваш сайт. Данный метод пусть и не идеальная защита, но порядка 90% защиту он вам обеспечит. а это уже лучше, чем ничего.
Далее рассмотрим, как данная техника защиты работает на практике и как ее можно реализовать на php.
За дело
Для начала нам нужно получить список ip-адресов, которым будет закрыт доступ на наш сайт. Еще потребуется использовать массивы и циклы - вот где нам и пригодится php.
Дальше - больше :)
Для получения ip-адреса посетителя можно использовать суперглобальную переменную $_SERVER['REMOTE_ADDR'].
На php это реализуется следующим образом:
.
.
А теперь разберемся с остальными переменными нашего мини-скрипта. Создаем массив ($ban), куда помещаем все забаненые ip:
.
.
Как видите, ip нужно помещать в одинарные кавычки и отделять их друг от друга запятой (все просто и ясно - за что я и люблю php)
В следующая переменная ($count) будет занесено количество этих самых ip:
.
.
Для чего это все нужно - читайте дальше.
Что мы имеем:
1) IP адрес определенного посетителя - переменная $ip;
2) массив запрещенных IP-адресов - $ban;
3) число элементов этого массива - $count.
Все элементарно просто - берем и сверяем адрес $ip со списком запрещенных - а так как у нас их может быть несколько, то для этого понадобится обход всего массива забаненых адресов.
Эту работу за нас легко проделает цикл for:
.
.
.
Вот и получается, что если проверяемый адрес совпадет с одним из наших "нехороших", то мы и дадим знать его обладателю - I'm sorry, you've been banned. 68.225.34.86.
А вот и весь скрипт целиком - это для тех, кому лень его собирать по частям из статьи:
Добрый день уважаемые господа! В данной статье я хотел бы затронуть очень важную тему, а именно шаблоны в PHP. В этой статье я приведу простой, но работающий пример “шаблонов”, также мы рассмотрим все за и против использования шаблонов.
Использование шаблонов
Прежде чем использовать шаблоны, подумайте, действительно ли они вам так нужны? В данный момент существует огромное количество коммерческих вариантов шаблонов. Все они работают по одному принципу (значение, замена), но имеют огромное количество наворотов, таких как автоматическое изменения регистра переменных, поиск по регулярным выражениям и т.д., все это конечно хорошо и легко реализуемо. Когда я решил посмотреть “коммерческий” шаблон, я ужаснулся, один его класс весил 398 КБ. Это нормально? Также в сети можно найти множество бесплатных вариантов шаблонов (классы шаблонов в PHPBB, IPB…), но все они много весят и работают не слишком быстро. Я предлагаю вам простой каркас “шаблонов” на PHP, с его помощью можно сделать свой классный шаблонизатор, со всеми необходимыми вам функциями.
За и против
Приведу вам жизненный пример, не так давно я занимался разработкой программы для одного человека, заранее было обговорено, что я пишу программу, а дизайн это его дело. Через некоторое время, мой заказчик пишет мне, что дизайн для моей программы сделать невозможно. Конечно, человек ничего не знающий в web-программировании будет испытывать огромные затруднения, при построении дизайна в PHP-программе. Главная задача ‘шаблонов’ – это облегчить жизнь дизайнеру. Безусловно, главным плюсом использования шаблонов можно считать то, что дизайнер без помощи программиста сможет изменять свой web-проект. Также мне нравится само разделение – программа и дизайн.
Я не использую шаблоны в своих личных проектах, т.к. они дают дополнительную “нагрузку”. Шаблоны это хорошо, но использовать их надо только если пишешь какой, то публичный проект или выполняешь работу на заказ.
Реализация шаблонов на PHP
И так приступим. Всего у нас будет 2 ключевых файла.
1) file2compile.tpl – файл который мы будем парсить
2) template.php – главный файл содержащий класс шаблонов
Листинг файла file2compile.tpl:
Листинг файла template.php:
Теперь я подробно опишу содержание этих двух файлов.
Файл: file2compile.tpl
Тут приведен обычный HTML код. В данном файле можно найти переменные вида {TITLE}. Это как раз именно те переменные которые мы будем заменять на нужное нам значение.
Файл: template.php
Мы имеем PHP класс, разделенный на 3 функции. В самом начале файла мы объявляем классовые переменные.
$vars – массив со значениями (переменная, замена).
$template – файл который мы будем парсить.
Теперь перейдем к описанию функций.
Функция: get_tpl
В качестве аргумента функция принимает имя файла. В теле функции мы проверяем задан ли аргумент и существует ли файл. Если аргумент не задан и файл не существует мы возвращаем значение FALSE. В противном случае мы заполняем классовую переменную(template) содержанием файла.
Функция set_tpl
Функция принимает 2 значения, это переменная (напр. {TITLE)} и значение на которое мы будем ее заменять.
Функция tpl_parse
Функция не принимает никаких значений. В теле функции мы считывает массив $vars и производим замену установленных переменных на заданные значения.
Использование класса.
Для вывода на экран используйте следующие команды:
Заключение.
Надеюсь, моя статья поможет вам лучше понять, что такое шаблоны.
На полноту изложения темы я не претендую, это ведь статья, а не справочное пособие, но для начинающих будет вводной информацией в эту технику.
Собственно, о самом термине:
Автоматическое перенаправление пользователя со страницы, на которую он попал на другую страницу или сайт. Технически реализовать редирект можно целым рядом способов.
Данным механизмом следует пользоваться только в исключительных случаях, по той причине, что поисковые системы считают, что редирект может быть использован недобросовестными раскрутчиками, привлекающими таким способом аудиторию на собственый сайт со страниц специально созданных для поисковых машин на страницы действительно содержащие полезный контент, что выглядит как обман поисковиков.
Перед началом повествования сделаю небольшие замечания:
* Вам не обязательно быть PHP-программистом, чтобы разобраться в технике редиректа;
* Подразумевается, что сервер (будь-то локальный - localhost, или же ваш хостинг в интернете) поддерживает выполнение PHP-скриптов.
А вообще, если что будет непонятно, то милости прошу на php.net :)
Суть технологии или техники редиректа - это автоматическое перенаправление кого-то куда-то :) А куда именно - вы сами задаете в скрипте, таким образом, при выполнении скрипта он вас автоматически перенаправит на определенный web-адрес.
Получается, что переход идет не по прямой ссылке с сайта вида <a href="http://www.google.com">google.com</a>, а через скрипт.
1. Открываем любой html-редактор (хотя подойдет и блокнот) и набираем/вставляем в него следующий код:
2. Далее сохраняем наш файл с вышеприведенным кодом, например code.php и загружаем его на веб-сервер. К примеру, если вы загрузили code.php в корневую папку сайта codeguru.com.ua, то вызвать скрипт можно по URL http://www.coders-library.ru/code.php. После исполнения скрипта на сервере вы будете автоматически перенаправлены (средиректены :)) на полезный сайт для программистов realcoding.net - что и было указано в нашем скрипте.
Еще можно просто на сайте в теле страницы (внутри тегов <body>...</body>) поставить ссылку вида:
.
.
Вот такая нехитрая техника редиректа (redirect).
Для оптимизации работы с сетью используется механизм сохранения однажды полученных по HTTP документов в кеше с целью их повторного использования без обращения к серверу-источнику. Документ, сохраненный в кеше будет доступен при следующем обращении к нему, без выгрузки с сервера-источника, что призвано повысить скорость доступа клиента к нему и уменьшить расход трафика сети.
Сами кэши бываю двух видов - локальные и общие
Локальный это кеш, хранимый непосредственно на диске у клиента, создаваемый и управляемый его браузером. Общий - кэш прокси-сервера организации или провайдера и может состоять из одного или нескольких прокси-серверов. Локальный кеш присутствует, наверное в каждом браузере, общими пользуется значительная часть людей использующих Internet. И если малую часть сайтов сейчас оценивают по расходу трафика, то скорость загрузки - важный критерий, который должен учитываться при разработке Вашего web-проекта.
Для динамических страниц, создаваемых в результате работы PHP-программы, казалось бы, кэширование вредно. Содержание страницы формируются по запросу пользователя на основе какого-либо источника данных. Однако, кэширование может быть полезным. Управляя им Вы можете сделать работу с Вашим сервером комфортнее для пользователя, разрешая загрузку из кэш определенных страниц, предотвращая тем самым их повторную выгрузку с Вашего сервера и экономя пользователю время и трафик.
Кэшировать или нет?
Возможность сохранения в кэш страницы определяется динамичностью информации в источнике данных. Таким образом необходимость использования кэша определяется Вами, исходя из планируемого времени жизни страницы.
Если речь идет о формировании выборки по базе (например, поиск введенного пользователем слова), то такую страница обязательно следует запрашивать с сервера при каждом вызове без использования кэш, так как количество вариантов запрашиваемых слов огромно, а если мы к тому же имеем дело с меняющимся массивом данных, то кэширование бессмысленно. Или речь идет о формировании допустим графика приходящих посетителей (который изменяется с каждым визитом, то есть практически с каждым вызовом), то кеширование уже просто вредно.
Однако, если мы говорим о том же графике но за вчерашний день, то кэширование рекомендуется, так как данные изменяться уже не будут и мы можем экономить себе и пользователю ресурсы и время на загрузку таких страниц помещением их в локальный или общий кэш. Как продолжение этой ситуации формирование графика не в реальном масштабе времени, а ежечасно. Тут Вы можете заранее предсказать дату окончания "срока годности" сформированных данных.
PHP-программа может управлять кэшированием результатов ее работы формируя дополнительные поля в заголовке HTTP ответа вызовом функции Header().
Несколько общих утверждений характерных не только для PHP-программ:
* Страницы передаваемые по POST никогда не сохраняются в кэш.
* Страницы запрашиваемые по GET и содержащие параметры (в URL присутствует '?') не сохраняются в кэш, если не указано обратное
Таким образом в большинстве ситуаций дополнительных инструкций в программу добавлять не надо. Основные моменты на которые следует обратить внимание можно свести к двум:
* запрет кэширования документов, кэшируемых по умолчанию
* кэширование документов, не подлежащих кэшированию по умолчанию.
Рассмотрим пример - прайс лист обновляемый по понедельникам. Вы заранее знаете, что содержание страницы можно хранить в кэш до наступления новой недели, что и следует указать в заголовке ответа обеспечивая нужное поведение страницы в кэш. Основная задача - получить дату следующего понедельника в формате RFC-1123.
.
.
.
.
.
Этим методом можно эффективно управлять поведением страницы в кэш и пременим но для большого числа страниц - так или иначе можно выделить временные интервалы в течении которых содержание страницы остается постоянным. Реальное положение вещей таково, что страницы большинства динамических сайтов имеют определенное время жизни исходя из которго разработчик может сераер более приятным для работы.
Другой подход, применяемый при более оперативном обновлении информации и одновременной высокой посещаемости сервера (иначе кэширование не будет эффективным) состоит в использовании заголовка Cache-control: max-age=секунды, определяющий время по истечении которого документ считается устаревшим и имеющий больший приоритет при вычислении "свежести" документа. Если Вы публикуете новости с интервалом в 30 минут:
Процесс создания cookies на ASP очень прост. После создания этих файлов, они будут храниться на компьютерах у посетителей вашего сайта.
Одним из основных параметров у cookies является дата истечения срока их действия, т.е. expire date. Получается, что у вас, как у программиста, в руках жизнь этих файлов.
Еще отмечу, что если не указать дату expire для cookies, то они существуют до тех пор, пока пользователь не закрыл свой браузер.
Для примера:
Сейчас возьмите и откройте свой любимый бразуер (мой выбор в пользу огненного лиса Firefox :) ) и вызовите страницу с cookie.
Теперь просто удалите в коде строку (1), закройте браузер и еще раз вызовите код. Как вы можете видеть, уже имя сайта не отображается.
Все дело в том, что мы не модифицировали дату истечения срока действия cookie и при закрытии браузера они были потеряны.
Теперь рассмотрим код с добавленной датой expiration date:
Теперь после закрытия браузера и повторного вызова кода можно видеть, что cookie по-прежнему продолжает существовать.
В статье описан процесс регистрации базы данных в BDE из программы.
Для доступа к BDE будем использовать компонент Session (вкладка BDE на панели компонент). Поместим его на форму, пусть это будет Session1. Положим на форму также компонеты Table, DataSource и DBGrid.
1. Простая регистация базы данных (алиаса)
Для добавления стандартного алиаса можно воспользоваться методом AddStandardAlias(Name, Path, DefaultDriver) объекта Session1, где Name - имя алиаса, Path - физический путь к базе данных, DefaultDriver - тип базы данных.
Для стандарного алиаса DefaultDriver может быть трех типов: Paradox, DBASE, ASCIIDRV. Перед запуском метода AddStandardAlias должно быть определено значение SessionName.
Пример:
Регистарция базы данных в BDE производится методом AddAlias(Name, Driver, List) объекта Session1, где Name - имя алиаса, Driver - используемый драйвер БД, List - список параметров.
Вот пример кода, выполняющего действия, аналогичные описанным в пункте 1.
.
.
.
.
.
.
.
.
.
.
.
.
. 3. Удаление базы данных (алиаса) из BDE
Здесь все просто, запускаем метод Alias с указанием имени алиаса.
Проверить, существует ли интересующий нас алиас можно с помощью методa IsAlias.
Я несколько раз видел в конференциях вопросы типа "как мне добавить элементы управления в TTabbedNotebook или TNotebook во время выполнения программы?". Теперь, когда у меня выдалось несколько свободных минут, я попытаюсь осветить этот вопрос как можно подробнее.
TTabbedNotebook
Добавление элементов управления в TTabbedNotebook во время проектирования - красивая и простая задача. Все, что Вам нужно - это установить свойство PageIndex или ActivePage на необходимую страницу и начать заполнять ее элементами управления.
Добавление элементов управление во время выполнения приложения также очень просто. Тем не менее, в прилагаемой документации по Delphi вы не найдете рецептов типа Что-и-Как. Видимо для того, чтобы окончательно запутать начинающих программистов, фирма-изготовитель даже не удосужилась включить исходный код TTabbedNotebook в VCL-библиотеку. Таким образом, TTabbedNotebook остается для некоторых тайной за семью печатями. К счастью, я имею некоторый опыт, коим и хочу поделиться.
Первым шагом к раскрытию тайны послужит просмотр файла DELPHIDOCTABNOTBK.INT, интерфейсной секции модуля TABNOTBK.PAS, в котором определен класс TTabbedNotebook. Беглый просмотр позволяет обнаружить класс TTabPage, описанный как хранилище элементов управления отдельной страницы TTabbedNotebook.
Вторым шагом в исследовании TTabbedNotebook может стать факт наличия свойством Pages типа TStrings. В связи с этим отметим, что Delphi-классы TStrings и TStringList соорганизуются с двумя свойствами: Strings и Objects. Другими словами, для каждой строки в TStrings есть указатель на соответствующий Objects. Во многих случаях этот дополнительный указатель игнорируется, нам же он очень пригодится.
После небольшого эксперимента выясняем, что свойство Objects указывает на нашу копию TTabPage и ссылается на имя страницы в свойстве Strings. Блестяще! Всегда полезно знать что ищешь. Теперь посмотрим что мы можем сделать:
TNotebook
Операция по заполнению элементами управления компонента TNotebook почти такая же, как и в TTabbedNotebook - разница лишь в типе класса - TPage вместо TTabPage. Тем не менее, если вы заглянете в DELPHIDOCEXTCTRLS.INT, декларацию класса TPage вы там не найдете. По неизвестной причине Borland не включил определение TPage и в DOC-файлы, поставляемые с Delphi. Декларация TPage в EXTCTRLS.PAS (можно найти в библиотеке VCL-исходников), правда, расположена в интерфейсной части модуля. Мы восполним пропущенную информацию о классе TPage:
Теперь, по аналогии с вышеприведенной процедурой, попробуем добавить кнопку на TNotebook. Все, что мы должны сделать - заменить "TTabbedNotebook" на "TNotebook" и "TTabPage" на "TPage". Вот что должно получиться:
У меня есть форма с расположенными на ней компонентами TreeView и Memo. Значение свойства align обоих компонентов позволяет им занимать всю форму. Я хотел бы расположить между ними движок типа Splitter, пропорционально меняющий их размеры (один шире, другой меньше и наоборот). Какой компонент мог бы симитировать поведение Splitter и как это реализовать?
Предположим, Ваш TreeView расположен в левой, а Memo в правой части формы. Вам нужно сделать следующее:
* Установите свойство Align компонента TreeView на alLeft.
* Вырежьте (Ctrl-X) компонент TMemo из вашей формы.
* Добавьте компонент Panel и присвойте его свойству Align значение alClient.
* Внутри панели разместите другой компонент Panel.
* Установите его ширину, равной 8 пикселам, свойству Align присвойте значение alLeft.
* Скопируйте вырезанный компонент TMemo в панель Panel1 и присвойте свойству Align значение alClient.
Код может быть модифицирован для получения горизонтального движка - идея, надеюсь, будет вам понятна.
Panel2 - движок: теперь вам необходимо добавить процедуры, приведенные ниже. Ваш код будет выглядеть приблизительно так:
Есть ли Win32 API функция, позволяющая не только открыть НО И ЗАКРЫТЬ CD-ROM? Хотелось бы не тянуться ручками к РС, а нажать мышкой на кнопку. Компонентом TMediaPlayer пользоваться не хочу, тем более компакт он может только извлечь.
Для закрытия CD-ROM:
Для открытия CD-ROM:
Не забудьте включить MMSystem в список используемых модулей (uses).
Приведенный ниже код содержит функцию DuplicateComponents, позволяющую проводить клонирование любых компонентов и их потомков во время выполнения приложения. Действия ее напоминают операцию копирования/вставки (copy/paste) во время разработки приложения.
Новые компоненты при создании получают тех же родителей, владельцев (в случае применения контейнеров) и имена (естественно, несколько отличающихся), что и оригиналы. В данной функции есть вероятность багов, но я пока их не обнаружил. Ошибки и недочеты могут возникнуть из-за редко применяемых специфических методов, которые, вместе с тем, могут помочь программистам, столкнувшимися с аналогичными проблемами.
Данная функция может оказаться весьма полезной в случае наличия нескольких одинаковых областей на форме с необходимостью синхронизации изменений в течение некоторого промежутка времени. Процедура создания дубликата проста до безобразия: разместите на TPanel или на другом родительском компоненте необходимые элементы управления и сделайте: "newpanel := DuplicateComponents(designedpanel)".
Событие OncalcFields генерится ОЧЕНЬ часто и может быть необязательным и занимать большое количество времени, например, у вас есть таблица с неким вычисляемым полем, и при каждом редактировании таблицы вызывается следующий код:
Теперь, если Вы решили пройти последовательно каждую запись огромной таблицы, вы можете представить, какое количество таких событий будет сгенерировано! Они будут необязательны в случае, если вы сделаете обработку полей в отдельной процедуре.
Мой совет следующий: выключите генерацию события OnCalcFields, обработайте все поля и снова включите генерацию данного события, к примеру так:
.
.
.
.
.
.
.
.
.
.
.
Поля не вычисляются в течение времени обработки, которое может быть достаточно велико, но при наличие громоздких вычислений специфического поля (или даже нескольких полей), все вычисляется за один проход!
Данный метод позволяет исключить необязательный код и может быть использован повсюду, где применяются большие таблицы или сложный алгоритм калькуляции поля. Разница в скорости обработки таблицы довольно ощутима.
Я представляю на Ваш суд утилиту быстрого поиска по базе данных. Данная технология производит поиск по полям, преобразуя их значения в строки (все значения преобразуются в верхний регистр, включая действительные числа).
Данное решение может быть не самым быстрым, однако на поверку оно оказывается быстрее остальных, обнаруженных мною в Интернете (может вам повезет больше). Более того, представьте, что действительное значение какого-либо поля равно 4.509375354, а значение поиска равно 7, в этом случае утилита засчитает "попадание". Утилита удобна также тем, что она за один проход производит поиск более, чем в одном поле.
Это удобно, если у Вас имеются, к примеру, два поля с адресами. Это моя первая "серьезная" разработка, так как первое, с чем я столкнулся, изучая Delphi, стала необходимость включения процедуры поиска в любое приложение, работающее с базой данных. А так как поиск - вещь тоже сугубо специфическая, как и любое приложение, то мне пришлось побороть свой страх перед "крутым программированием" и попробовать написать свой поисковый механизм, удовлетворивший меня (и, надеюсь, других) своей скоростью и возможностью "мульти"-поиска по нескольким полям.
Я надеюсь, что он поможет тем программистам, кто часто сталкивается с подобными задачами. Технология довольно легка для понимания, но если у Вас возникли какие-либо вопросы, пошлите мне письмо электронной почтой, я буду рад Вам помочь. Посмотрев код, можно легко узнать поддерживаемые типы полей (добавить новые не составит проблем).
Каким способом можно производить поиск подходящих величин в момент ввода? Табличный курсор (визуально) должен перемещаться к наиболее подходящему значению при добавлении пользователем новых символов водимой величины.
Для поиска величины таблица держится открытой. Индекс должен, естественно, принадлежать полю, используемому элементом управления EditBox. В случае изменения содержимого EditBox, новое значение используется для вызова стандартной функции FindNearest таблицы TTable. Возвращаемая величина снова присваивается свойcтву Text элемента EditBox.
Я привел лишь общее решение задачи. Фактически во время изменения значения я включал таймер на период 1/3 секунды и в обработчике события OnTimer проводил операцию поиска (с выключением таймера). Это позволяло пользователю набирать без задержки нужный текст без необходимости производить поиск в расчете на вновь введенный символ (поиск проводился только при возникновении задержки в 1/3 секунды).
Вам также может понадобиться специальный обработчик нажатия клавиши backspace или добавления символа в любое место строки.
Вместо возвращения результатов элементу EditBox (который перезаписывает введенное пользователем значение), вы можете передавать результаты другому элементу управления, например компоненту ListBox. Вы также можете отобразить несколько наиболее подходящих значений, к примеру так:
Данная проблема возникает из-за того, что BDE вначале запрашивает базу данных для получения информации о таблице, прежде чем он начнет с ней работать. Как только появляется информация о таблице, она кэшируется и обращение к таблице во время всего сеанса (пока TDatabase.Connection имеет значение True) происходит практически мгновенно.
Для того, чтобы использовать кэшируемую информацию и при последующем запуске приложения, в конфигурации BDE найдите необходимый псевдоним и установите BDE CACHE = TRUE и BDE CACHE DIR = 'C:temp' или любой другой удобный каталог.
ПРИМЕЧАНИЕ:
При любом изменении структуры таблицы Вам придется удалять кэш вручную. Имя файла, в котором хранится кэш, Вы можете узнать, посмотрев в любом текстовом редакторе файл SCache.INI.