Для оптимизации работы с сетью используется механизм сохранения однажды полученных по HTTP документов в кеше с целью их повторного использования без обращения к серверу-источнику. Документ, сохраненный в кеше будет доступен при следующем обращении к нему, без выгрузки с сервера-источника, что призвано повысить скорость доступа клиента к нему и уменьшить расход трафика сети.
Сами кэши бываю двух видов - локальные и общие
Локальный это кеш, хранимый непосредственно на диске у клиента, создаваемый и управляемый его браузером. Общий - кэш прокси-сервера организации или провайдера и может состоять из одного или нескольких прокси-серверов. Локальный кеш присутствует, наверное в каждом браузере, общими пользуется значительная часть людей использующих Internet. И если малую часть сайтов сейчас оценивают по расходу трафика, то скорость загрузки - важный критерий, который должен учитываться при разработке Вашего web-проекта.
Для динамических страниц, создаваемых в результате работы PHP-программы, казалось бы, кэширование вредно. Содержание страницы формируются по запросу пользователя на основе какого-либо источника данных. Однако, кэширование может быть полезным. Управляя им Вы можете сделать работу с Вашим сервером комфортнее для пользователя, разрешая загрузку из кэш определенных страниц, предотвращая тем самым их повторную выгрузку с Вашего сервера и экономя пользователю время и трафик.
Кэшировать или нет?
Возможность сохранения в кэш страницы определяется динамичностью информации в источнике данных. Таким образом необходимость использования кэша определяется Вами, исходя из планируемого времени жизни страницы.
Если речь идет о формировании выборки по базе (например, поиск введенного пользователем слова), то такую страница обязательно следует запрашивать с сервера при каждом вызове без использования кэш, так как количество вариантов запрашиваемых слов огромно, а если мы к тому же имеем дело с меняющимся массивом данных, то кэширование бессмысленно. Или речь идет о формировании допустим графика приходящих посетителей (который изменяется с каждым визитом, то есть практически с каждым вызовом), то кеширование уже просто вредно.
Однако, если мы говорим о том же графике но за вчерашний день, то кэширование рекомендуется, так как данные изменяться уже не будут и мы можем экономить себе и пользователю ресурсы и время на загрузку таких страниц помещением их в локальный или общий кэш. Как продолжение этой ситуации формирование графика не в реальном масштабе времени, а ежечасно. Тут Вы можете заранее предсказать дату окончания "срока годности" сформированных данных.
PHP-программа может управлять кэшированием результатов ее работы формируя дополнительные поля в заголовке HTTP ответа вызовом функции Header().
Несколько общих утверждений характерных не только для PHP-программ:
* Страницы передаваемые по POST никогда не сохраняются в кэш.
* Страницы запрашиваемые по GET и содержащие параметры (в URL присутствует '?') не сохраняются в кэш, если не указано обратное
Таким образом в большинстве ситуаций дополнительных инструкций в программу добавлять не надо. Основные моменты на которые следует обратить внимание можно свести к двум:
* запрет кэширования документов, кэшируемых по умолчанию
* кэширование документов, не подлежащих кэшированию по умолчанию.
Рассмотрим пример - прайс лист обновляемый по понедельникам. Вы заранее знаете, что содержание страницы можно хранить в кэш до наступления новой недели, что и следует указать в заголовке ответа обеспечивая нужное поведение страницы в кэш. Основная задача - получить дату следующего понедельника в формате RFC-1123.
.
.
.
.
.
Этим методом можно эффективно управлять поведением страницы в кэш и пременим но для большого числа страниц - так или иначе можно выделить временные интервалы в течении которых содержание страницы остается постоянным. Реальное положение вещей таково, что страницы большинства динамических сайтов имеют определенное время жизни исходя из которго разработчик может сераер более приятным для работы.
Другой подход, применяемый при более оперативном обновлении информации и одновременной высокой посещаемости сервера (иначе кэширование не будет эффективным) состоит в использовании заголовка Cache-control: max-age=секунды, определяющий время по истечении которого документ считается устаревшим и имеющий больший приоритет при вычислении "свежести" документа. Если Вы публикуете новости с интервалом в 30 минут:
Все, что мы записываем в переменную $s (массив), будет доступно для чтения при следующем заходе посетителя на сервер. Про сессии, на самом деле, можно сказать очень много, чтобы описать возможности и особенноти.. Но если вы поюзаете пример и попробуете использовать в своих задачах, сами поймете.
Часто возникает необходимость передать переменные в самой строке URL. Для этого нужно воспользоваться кодированием строки с переменными. А все спецсимволы типа пробела тоже должны учитываться.
Без применения кодирования:
Если испытать в работе первый код, то наш SQL запрос будет с некоторыми отсутствующими символами. А нам это не подходит, ведь теряется весь смысл многословного запроса.
Именно для решения этой проблемы программистамы было придумано кодировать строку перед подачей ее скрипту. Сама функция кодирования называется URLEncode и вся строка запроса кодируется в безопасном режиме (safe mode).
Представляю краткую справочную информацию по использованию языка SQL в среде программирования Delphi. Для использования в программе команд языка SQL необходимо поместить на форму объект TQuery. Назовем его MyQuery. А поместив на форму объекты TDBGrid и TDataSource и связав все три объекта между собой, получим возможность видеть в объекте TDBGrid результаты SQL запросов.
Создание таблицы с помощью SQL запроса
Перед выполнением запроса должны быть определены следующие переменные строкового типа:
Приведенный ниже запрос создает таблицу состоящую из двух полей указанного типа:
.
.
.
.
.
.
.
.
.
.
Типы поля могут быть: int, float, char(10).
Добавление записи в таблицу
Добавление записи в таблицу посредством SQL запроса выполняется следующим способом:
Здесь val1, val2 - добавляемое значение целого или вещественного типа; val3 - добавляемое значение строкового типа.
Последовательность расположения добавляемых значений в тексте запроса важна и должна соответствовать порядку следования полей таблицы.
SQL запрос на выборку
Для выполнения простого SQL запроса на выборку всех записей из указанной таблицы достаточно следующего кода:
переменная tbl содержит название таблицы, а лучше - полный путь к таблице, например: 'c:programsdelphisqlfirst.dbf'. Свойство MyQuery.RecordCount содержит число записей, выбранных из таблицы SQL запросом.
[pagebreak]
Запрос SQL на выборку с условием
Переменная fld содержит название поля таблицы, а переменная val - значение этого поля. Результатом выполнения нижеследующего запроса являются все записи таблицы со значением val в поле fld.
.
.
.
.
.
.
.
.
.
.
А если воспользоваться приведенным ниже кодом, то в результате получим все строки таблицы, содержимое поля fld которых содержит значение val.
Запрос SQL для нахождения максимума или минимума
Программный код запроса:
Используя команду MyQuery.FieldByName('M').asInteger; можно получить значение максимума целого типа. Для нахождения минимума необходимо в запросе воспользоваться строкой SQL.Add('SELECT Min('+Fld+') as M');
Запрос SQL для удаления записей из таблицы
Для удаления записей из таблицы tbl значения поля fld которых равны val используется следующий код:
Запрос SQL для изменения записей в таблице
Принцип работы запроса аналогичен запросу на удаление, необходимо лишь указать updFld - обновляемое поле и updVal - новое значение для этого поля.
Пример запроса:
В приведенном ниже примере описано как можно получить список логических дисков, установленных в системе, а также определить их тип. Для этих целей используются функции winAPI GetLogicalDrives и GetDriveType.
Для работы примера на форму проекта поместите объекты Button1 и Memo1. В обработчике событий для Button1 нужно ввести указанный код.
В случае нажатия пользователем клавиши или изменении текущего элемента компонента ComboBox, вы обратите внимание на досадную задержку, возникающую при генерации события On.
Так как "работа кипит", я хотел бы отреагировать на изменение ItemIndex несколько позднее, например, 100 миллисекунд спустя. Вот что у меня получилось. На простой форме располагаем компоненты ComboBox и Label. Необходимым дополнением является вызов Application.ProcessMessages, позволяющий избежать замедления работы PC, когда очередь сообщений для формы пуста.
Возможно ли создание массива компонентов? Для показа статуса я использую набор LED-компонентов и хотел бы иметь к ним доступ, используя массив.
Прежде всего необходимо объявить массив:
.
.
При необходимости динамического создания LED-компонентов организуйте цикл, пример которого мы приводим ниже:
.
.
.
.
.
.
.
.
Если компоненты уже присутствуют на форме (в режиме проектирования), сделайте их элементами массива, например так:
.
.
.
.
.
.
.
.
.
.
Тем не менее у нас получился массив со случайным расположением LED-компонентов. Я предлагаю назначить свойству Tag каждого LED-компонента порядковый номер его расположения в массиве, а затем заполнить массив, используя это свойство:
.
.
.
.
.
.
.
.
Если вам нужен двухмерный массив, то для формирования индекса понадобится другая хитрость, например, хранение в свойстве Hint информации о времени создания компонентов.
Я несколько раз видел в конференциях вопросы типа "как мне добавить элементы управления в 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". Вот что должно получиться:
Возможно ли поместить изображение в одну из ячеек компонента StringGrid?
Такое позволяет обработчик события OnDrawCell. Приводим скелет кода, демонстрирующий принцип вывода изображения в ячейке компонента:
Достичь цели позволяют методы Draw() и StretchDraw() объекта TCanvas. В приведенном примере переменная Image1 класса TImage содержит заранее загруженное изображение.
У меня есть форма с расположенными на ней компонентами 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 - движок: теперь вам необходимо добавить процедуры, приведенные ниже. Ваш код будет выглядеть приблизительно так:
Один из примеров создания текстового компонента с трехмерной декоративной контурной рамкой (для создания компонента потребовалось около получаса. Он демонстрирует только принцип получения рамки. Я не стал колдовать над свойствами типа ParentFont..., т.к. это заняло бы еще немало времени и места).