Html code will be here


Курс
РАЗРАБОТЧИК
ВЕБ - ПРИЛОЖЕНИЙ

Бесплатный курс по
web - разработке
- бесплатное обучение
- бесплатные обновления
- сертификаты

О курсе

Преимущества курса
"Разработчик web-приложений"
  • Курс бесплатный
  • По окончанию курса можно получить сертификат
  • Курс создан в виде лекций и предназначен для того, чтобы в целом понять профессию и решить готовы ли вы серьезно изучать веб-разработку
  • Изучать курс можно в любое удобное для вас время
  • Курс рассчитан на 3 месяца, без учета обновлений
  • Курс переодически будет пополняется новыми уроками и литературой
  • Доступ к курсу и все обновления останутся вашими навсегда

Кто такой
web-разработчик и чем он занимается? 

Веб-разработчик (web-developer) – специалист, который использует различные языки программирования для того, чтобы писать, обновлять и устранять ошибки в программных алгоритмах веб-сайтов, мобильных и десктопных приложениях и сервисах. Их работа являются движущей силой в IT-индустрии и позволяет давать рынку качественные и функциональные цифровые продукты.

Основной плюс веб-разработчики- это высокая востребованность на рынке труда и творческий характер работы – каждый проект будет уникальным. Также у этих специалистов есть возможность удаленной работы и работы на себя, принятие самостоятельных решений. Зарплата веб- разработчика варьируется от 60 до 200 тысяч рублей, в зависимости от опыта и места работы.

Чему вы научитесь на курсе.

1. Основам предпринимательства для web-разработки.


2. Проектированию web-приложений.


3. Разработке приложений.


4. Использованию MasterPage.


5. Научитесь оптимизировать приложения.


6. Научитесь использовать криптографические методы защиты информации.


7. Научитесь создавать интерактивные веб-сайты.

СОДЕРЖАНИЕ КУРСА 

1. МОДУЛЬ

Основы предпринимательства для web-разработчиков.


Тема 1. Сущность предпринимательства. Предпринимательская сеть – форма организации межфирменного взаимодействия субъектов предпринимательства.


Тема 2. Коммерческие организации как субъект предпринимательской деятельности. Эффективность, правовые основы и культура предпринимательской деятельности. Безопасность предпринимательской деятельности.


Тема 3. Современная концепция делового планирования.

- Понятие проекта и дисциплина «Бизнес-планирование».


Тема 4. Цикл делового проекта.


Тема 5. Основные особенности бизнес-планирования.


Тема 6. Методы ситуационного анализа бизнеса.


Тема 7. Содержание бизнес – плана.


2. МОДУЛЬ

Проектирование и разработка

web-приложений.


Тема 1. Описание .NET Framework.


Тема 2. Использование MasterPage.


3.Дополнительная литература :
"ASP.NET Core. Разработка приложений" Джеймс Чамберс

3. МОДУЛЬ

Оптимизация

web-приложений.


Тема 1. Функции, определяемые пользователем.


Тема 2. Объекты.

Тема 3. Массивы.

Тема 4. Строки.

5. Дополнительная литература :
"Изучаем РНР 7"
Руководство по созданию интерактивных веб-сайтов. Дэвид Скляр

4. МОДУЛЬ

Обеспечение безопасности web-приложений.


Тема 1. Безопасность базы данных.


Тема 2. Безопасность клиентских приложений.


Тема 3. Криптографические методы защиты информации.


5. МОДУЛЬ

Практическое задание.


6. ЛИТЕРАТУРА


7. ОБНОВЛЕНИЯ


8. СЕРТИФИКАТ

получить сертификат.














КУРС

РАЗРАБОТЧИК
ВЕБ - ПРИЛОЖЕНИЙ 

курс создан в виде лекций и будет переодически пополняться новыми уроками.
1 МОДУЛЬ

Основы предпринимательства для web-разработчиков. 

Тема 1. Сущность предпринимательства. Предпринимательская сеть – форма организации межфирменного взаимодействия субъектов предпринимательства



- Что такое предпринимательская деятельность? Это самостоятельная, осуществляемая на свой риск деятельность, направленная на систематическое получение прибыли от пользования имуществом – продажи товаров, выполнения работ или оказания услуг лицами, зарегистрированными в этом качестве в установленном законом порядке.

- Предпринимательская деятельность классифицируется по различным признакам: формам собственности, виду деятельности, количеству собственников, организационно-правовым и экономическим формам, отраслевой принадлежности и другим показателям.
- Как появляется предпринимательская идея, и каков ее жизненный цикл? Предпринимательская идея представляет собой выявленный возможный интерес фирмы-производителя, имеющий видимые очертания какой-либо конкретной экономической формы. Выявление такого интереса может осуществляться посредством совмещения возможностей предпринимателя с потребностями рынка или, наоборот, путем совмещения потребностей рынка с возможностями предпринимателя.

- Жизненный цикл предпринимательской идеи:
1. Зарождение предпринимательской идеи
2. Первая экспертная оценка
3. Получение рыночной информации
4. Расчеты затрат на производство продукции
5. Независимая экспертная оценка 3 и 4-го этапов
6. Принятие предпринимательского решения
7. Подготовка к практической реализации идеи
8. Реализация предпринимательской идеи
- Причины риска в предпринимательстве и способы их устранения.
Риск - потенциальная, численно измеримая возможность неблагоприятных ситуаций и связанных с ними последствий в виде потерь, ущерба, убытков, вплоть до банкротства и ликвидации предпринимательской единицы из-за нестабильности и неопределенности.
- Предпринимательская среда: внешняя среда (структура элементов и описание), внутренняя среда, внутрифирменное предпринимательство.
Предпринимательская среда - это наличие условий и факторов, воздействующих на субъекты предпринимательской деятельности и требующих принятия управленческих решений для их устранения или приспособления. Она представляет собой интегрированную совокупность объективных и субъективных факторов, позволяющих субъектам предпринимательства добиваться успеха в реализации поставленных целей, и подразделяется на внешнюю, как правило, независимую от субъектов предпринимательства среду, и внутреннюю, которая формируется непосредственно субъектом предпринимательства.
- Предпринимательская сеть, основы формирования.
Предпринимательскую сеть можно идентифицировать как группу организаций- участников того или иного рынка, объединившихся для эффективного использования ресурсов и специфических преимуществ для совместной реализации предпринимательских проектов. Используя преимущественно горизонтальные связи и механизмы специализации и взаимодополнения, они получают дополнительные возможности к достижению более высоких результатов.

Тема 2. Коммерческие организации как субъект предпринимательской деятельности. Эффективность, правовые основы и культура предпринимательской деятельности. Безопасность предпринимательской деятельности.

- Сущность терминов «Организация» и «Предприятие», их различие. Типы организаций: коммерческие/некоммерческие.
Юридическое лицо – это организация, имеющая в собственности, хозяйственном ведении или оперативном управлении обособленное имущество, отвечает по своим обязательствам этим имуществом, может быть истцом и ответчиком в суде.
Предприятие – это целостный технологический комплекс с замкнутым производственным циклом, т. е. имущественный комплекс, включающий элементы, позволяющие субъекту предпринимательской деятельности самостоятельно производить продукцию и тем самым систематически получать прибыль. Набор элементов имущественного комплекса зависит от профиля деятельности, финансово-экономических, территориальных и иных условий функционирования предприятия. В соответствии с действующим гражданским законодательством организация признается юридическим лицом только после государственной регистрации в установленном порядке и должна обладать определенными присущими ей признаками, без которых она не может не только быть признана юридическим лицом, но и участвовать в законном хозяйственном обороте.
Основные признаки, характеризующие организацию как юридическое лицо, следующие:
- наличие обособленного имущества, обеспечивающее материально-техническую возможность функционирования организации, ее экономическую самостоятельность и надежность;
- способность выступать от своего имени, т. е. в соответствии с законодательством заключать все виды гражданско-правовых договоров с хозяйствующими партнерами, потребителями продукции (работ, услуг), поставщиками всех видов (сырья, материалов, топлива, энергии, комплектующих изделий и т. п.), с гражданами и другими юридическими и физическими лицами;
- право (возможность) быть истцом, предъявлять виновной стороне иски, а также быть ответчиком в суде (арбитражном суде) при невыполнении обязательств в соответствии с законодательством и договорами;
- наличие требуемого законодательством регистрационного свидетельства, а в специально оговоренных случаях и лицензии на право осуществления тех или иных конкретных видов деятельности.

- Организационно-правовые формы коммерческих организаций: индивидуальный предприниматель, хозяйственные товарищества, производственные кооперативы, государственные унитарные предприятия, акционерное общество.

Какие факторы влияют на выбор организационно-правовой формы?

- Формы интеграции компаний (тресты, концерн, холдинговая компания, конгломераты, картель):
- Полностью объединенные организации (тресты) образуются в результате слияния коммерческих организаций, полностью теряющих при этом свою юридическую и хозяйственную самостоятельность.
Концерн представляет форму объединения самостоятельныхорганизаций, связанных посредством системы участия в капитале, финансовых связей, договоров об общности интересов, патентно-лицензионных соглашений, а также тесного производственного сотрудничества.
Холдинговой компанией признается коммерческая организация независимо от его организационно-правовой формы, в состав активов которой входят контрольные акции организаций.
Конгломераты – организационная форма интеграции, включающая под единым финансовым контролем целую сеть разнородных компаний. Конгломераты возникают в результате слияния различных компаний без всякой производственной общности независимо от их горизонтальной и вертикальной интеграции.
Картель – это горизонтальное договорное объединение коммерческих организаций, как правило, одной отрасли, которые, оставаясь юридически самостоятельными, отказываются от части своей хозяйственной самостоятельности в соответствии с картельным договором. Цель – ограничение или ликвидация риска конкуренции.
Консорциум – это горизонтальное договорное объединение коммерческих организаций для осуществления единого капиталоемкого проекта.

- Принципы и методы оценки эффективности предпринимательской деятельности.
1. Основной принцип - взаимосвязь цели и конечного результата деятельности,
2. Второй принцип оценки эффективности предпринимательства – наличие нескольких критериев оптимальности.
3. В процессе целеполагания следует отдавать преимущество целям,
характеризующим устойчивость рыночных позиций.
4. Четвертый принцип – взаимосвязь жизненного цикла продукции и показателей предпринимательской деятельности.

- Этика и культура в предпринимательстве. Корпоративная культура.
Этика деловых отношений – это система универсальных и
специфических нравственных требований и норм поведения, реализуемых в
профессиональной деятельности. В нее входят:
- этическая оценка внутренней и внешней политики коммерческой организации;
- моральные принципы членов коммерческой организации;
- моральный климат в коммерческой организации;
- нормы делового этикета.
Корпоративная культура – это система ценностей и убеждений, разделяемых всеми работниками компании, предопределяющая их поведение и характер жизнедеятельности организации.
При анализе корпоративной культуры следует выделить три основных момента.
1. базовые предположения, которых придерживаются члены организации в
своем поведении и действиях.
2. ценности (ценностные ориентации), которых должен придерживаться
человек.
3. «символика», посредством которой ценностные ориентации передаются
членам организации.
- Организационно-управленческие инновации (3 основных вида):
1.Инновация продукции обеспечивает рост прибыли, расширение доли на рынке, сохранение клиентуры и повышение престижа.
2.Инновация технологии направлена на повышение производительности труда и экономию ресурсов, что позволяет увеличить прибыль коммерческой организации, усовершенствовать технику безопасности, эффективно использовать внутрифирменные информационные системы.
3. Социальные инновации представляют собой общий процесс планомерного улучшения гуманитарной сферы коммерческой организации, способствуют расширению возможностей на рынке рабочей силы, мобилизуют персонал организации на достижение поставленных целей.

- Безопасность предпринимательской деятельности.Коммерческая тайна.
1. Экономическая безопасность
2. Враждебные слияния и поглощения
3. Противостояние рейдерству
4. Информационная безопасность
Коммерческая тайна – право организаций не разглашать, сохранять в тайне сведения
и документы о своей деятельности, чтобы предотвратить возможность нанесения ущерба компании ее конкурентами.

Тема 3. Современная концепция делового планирования.
- Понятие проекта и дисциплина «Бизнес-планирование».

Проект - это ограниченное по времени целенаправленное изменение отдельной системы с установленными требованиями к качеству результатов, возможными рамками расхода средств и ресурсов и специфической организацией. Цель проекта – это доказуемый результат и заданные условия реализации общей задачи проекта
В нашу жизнь вошла концепция - управление проектами. Основу этой концепции составляет взгляд на проект как на изменение исходного состояния любой системы (например, предприятия), связанное с затратой средств и времени. Процесс этих изменений, осуществляемых по заранее разработанным правилам в рамках бюджета и временных ограничений, - это управление проектами, осуществляемое на основе делового планирования или бизнес-планирования. Дисциплина «Деловое планирование», ее методы и средства позволяют:
1. разработать и обосновать концепцию проекта;
2. оценить эффективность проекта с учетом факторов риска и неопределенности;
3. выполнить предварительное технико-экономическое обоснование проекта и разработать бизнес-план проекта;
4. осуществить системное планирование проекта на всех фазах его жизненного цикла;
5. разработать смету и бюджет проекта;
6. подобрать исполнителей проекта через процедуру конкурсов (торгов);
7. подготовить и заключить контракты на поставку;
8. организовать оптимальную процедуру закупок и поставок;
9. организовать реализацию проекта, в том числе подобрать так называемую «команду» проекта;
10. обеспечить эффективный контроль и регулирование, а также управление изменениями, неизбежными в ходе реализации проекта;
11. организовать эффективное завершение проекта;
12. организовать системное управление качеством продукции проекта;
13. в полной мере учесть так называемый «человеческий фактор», оказывающий нередко решающее воздействие на эффективность проекта в целом.
- Участники бизнес – планирования и их функции.
Состав участников проекта, их роли, распределение функций и ответственности зависят от типа, вида, масштаба и сложности проекта, а также от фаз жизненного цикла проекта. Неизменными можно считать таких участников, как инициатора, заинтересованное лицо, заказчика, инвестора, исполнителя, производителей, продавцов и потребителей.


Тема 4. Цикл делового проекта.

- Цикл делового проекта.
Развитие делового проекта от первоначальной идеи до ее реализации может быть представлено в форме цикла, включающего три отдельные фазы: предынвестиционную, инвестиционную и оперативную, где каждая из трех фаз может быть подразделена на этапы:
- Предынвестиционная фаза
1. Анализ инвестиционных возможностей
2. Предварительное ТЭО
3. Анализ альтернатив объекта и предварительный выбор
4. Бизнес – план
5. Доклад об инвестиционных возможностях
- Инвестиционная фаза
1. Переговоры и заключение контрактов
2. Проектирование
3. Строительство
4. Маркетинг
5. Обучение
- Эксплуатационная (оперативная фаза)
1. Приемка и запуск
2. Замена оборудования
3. Расширение, инновация
- Место бизнес – проекта в жизненном цикле компании.
В качестве ближнего окружения большинства проектов выступает «родительская организация», где данный проект является составной частью жизненного цикла деловой активности организации. Также проект может быть тесно связан с выпуском новой продукции или услуг и осуществлением необходимых для этих целей изменений, поэтому проект связан еще и с жизненным циклом продукта.

- Типичные ошибки и недостатки при осуществлении бизнес – планирования.
1. Недостаточный анализ существующего состояния и обоснование требований к проекту не позволяют вскрыть проблемы, четко определить потребности в изменении состояния системы и подготовить необходимую информацию для принятия решения.
2. Нечетко определены цели проекта.
3. Вместо объективного поиска альтернатив предпочтение отдается излюбленному варианту.
4. Ответственность в проекте распределена недостаточно четко и согласованно.
5. Команда проекта недостаточно укомплектована квалифицированным персоналом (лимитированность расхода трудовых ресурсов).
6. Недооценка риска осуществления проекта.

Тема 5. Основные особенности бизнес-планирования.

- Основные функции бизнес-плана.
- Внутрифирменная деятельность:
1. Разработка стратегии (концепции) развития фирмы и конкретизация отдельных направлений ее деятельности
2. Разработка и осуществление проектов создания новой продукции (услуги)
3. Оценка внутреннего научного, технического, производственного и коммерческого потенциала фирмы и выявление резервов
4. Подготовка и осуществление мероприятий по внедрению новых технологий и приобретению оборудования
5. Контроль за финансовыми результатами деятельности фирмы
6. Мероприятия по снижению степени риска в деятельности фирмы
7. Формирование благоприятного имиджа фирмы
8. План мер предупреждения банкротства и выхода из кризисных ситуаций
- Внешние функции:
1. Привлечение инвестиций для выполнения проектов
2. Обоснование для включения проектов в государственные программы и получение средств из централизованных источников
3. Получение банковских кредитов
4. Обеспечение успешной реализации акций фирмы на фондовом рынке
5. Организационно- финансовое обоснование необходимости создания совместных производств и других форм совместной деятельности
6. Разработка и осуществление мероприятий по созданию финансово-промышленных групп


таблица
таблица
- Маркетинг, его виды.
Маркетинг включает в себя комплекс мероприятий:
1. Исследование продукта (изделия или вида услуг)
2. Определение наиболее эффективных способов продвижения товаров на рынке
3. Анализ форм и каналов сбыта
4. Анализ рынка, на котором функционирует предприятие
5. Изучение потребителя
6. Анализ объема товарооборота предприятия
7. Изучение конкурентов, определение форм и уровня конкуренции
8. Исследование рекламной деятельности
9. Исследование мотивов поведения потребителя на рынке

таблица

Тема 6. Методы ситуационного анализа бизнеса. 



- Цель ситуационного анализа.
Под ситуационным анализом принято понимать проводимый периодически (1-2 раза в год) анализ деятельности фирмы в ее отношениях с внешним для нее миром. Целью ситуационного анализа является «внутренняя ревизия» и оценка прошлой деятельности фирмы, рассмотрение ее достижений и неудач, вскрытие причин тех и других, выявление компетентности сотрудников и эффективности их работы, а также выработать правильную стратегию на будущее.
Использование такого способа анализа помогает компании быстро отвечать на рыночные изменения, повышение уровня конкуренции, динамику цен, снижение качества продукции или ухудшение иных критериев производства.
- Классификация методов анализа деловых ситуаций.
Методы сбора материала могут быть классифицированы по признаку способа полученной информации на следующие четыре группы: путем личных наблюдений и экспериментов, на основе имеющегося опыта и аналогов, путем анкетирования, с использованием внешнего аудита и консалтинга.

Тема 7. Содержание бизнес – плана.

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

- Раздел 1. Описание продукции (товаров, услуг).
Описание продукции включает краткую характеристику потребительских свойств продукции, которую будет предлагать предприятие, а также результаты сравнительного анализа с аналогами продукции на существующих рынках.

- Раздел 2. Оценка рынка сбыта.
Описание этого раздела рекомендуется выполнять по следующим направлениям:
1. Изучение товара (новизна, конкурентоспособность, способность удовлетворить потребности покупателей)
2. Изучение рынка как такого (географическое положение, емкость рынка и возможная доля товара при различном стечении обстоятельств, острота конкуренции, тенденции развития)
3. Изучение покупателей (возможные покупатели; типичные способы использования предлагаемого товара, характерные для этих покупателей; побудительные мотивы, заставляющие приобретать товары данного рода; факторы, формирующие покупательские предпочтения и влияющие на их рыночное поведение; возможность выделения более или менее однородных групп (сегментация) покупателей по потребностям, побудительным мотивам и т. д., оценка численного состава каждого такого сегмента; потребности, не удовлетворенные товарами данного вида (вашими и конкурентов); влияние научно-технических достижений на развитие потребностей актуальных и потенциальных покупателей.
4. Изучение конкурентов (эта информация позволит в последующем сформировать реальную оценку рынка и составить прогноз объемов продаж предприятия)

- Раздел 3. Оценка конкурентов:
1. Обследование конкурентов, владеющих наибольшей долей рынка (3-4 фирмы):
2. Выявление наиболее динамично развивающихся предприятий на данном рынке (2-3 фирмы).
3. Установление торговых марок и знаков конкурентов.
4. Определение особенностей товаров (продукции) конкурентов, по которым их предпочитают покупатели.
5. Изучение форм и методов сбытовой деятельности конкурентов, используемых каналов товародвижения.
6. Установление ценовой политики конкурентов.
7. Оценка сильных и слабых сторон конкурентов в различных областях и сферах деятельности.

- Раздел 4. Стратегия и план маркетинга:
1. Общая стратегия маркетинга.
2. Ценообразование.
3. Тактика реализации продукции.
4. Политика по послепродажному обслуживанию и предоставление гарантий.
5. Реклама и продвижение товара на рынок.

- Раздел 5. Прогноз объемов продаж:
1. Объем продаж по периодам (календарный год с разбивкой по месяцам или кварталам, на последующие три года или пять лет и т. п.). Полезным оказываются множественные прогнозы объемов продаж, когда даются средние, то есть наиболее вероятные, и оптимистические прогнозы.
2. Объемы продаж по видам продукции.
3. Объемы продаж по группам потребителей.
4. Доля рынка, то есть процент от общего объема продаж на рынке, который предприятие предполагает обеспечить для себя.


- Раздел 6. План производства.
Основной целью данного раздела является предоставление информации по обеспеченности с производственной стороны выпуска продукции и разработка мер по развитию производства. В этот раздел необходимо включить такие сведения, как местоположение предприятия, виды требуемых производственных мощностей, необходимые производственные помещения, потребность в основных производственных фондах и оборотных средствах.

- Раздел 7. Организационный план.
В данном разделе приводится информация, характеризующая организационную структуру управления предприятием, а также сведения о персонале. Особое значение имеет планирование численности персонала, что должно осуществляться с учетом планируемого объема производства, а также расчет фонда оплаты труда, который будет востребован при определении себестоимости реализуемой продукции (работ, услуг).

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

- Раздел 9. Оценка риска.
Главное для этого раздела умение заранее предугадать все типы возможных рисков, с которыми может столкнуться предприятие, источники этих рисков и моменты их возникновения, а затем, разработать меры по сокращению числа этих рисков и минимизации потерь, которые они могут вызвать.
Для этого необходимо сделать следующее:
1. Выявить полный перечень возможных рисков.
2. Определить вероятность возникновения каждого риска.
3. Оценить ожидаемый размер убытков при возникновении рисков.
4. Проранжировать риски по вероятности их возникновения.
5. Установить приемлемый уровень риска и отбросить все риски, вероятность возникновения которых ниже принятого уровня.

- Раздел 10. Финансовый план.
Этот раздел бизнес-плана призван обобщить материалы предыдущих разделов и представить их в стоимостном выражении. Информация этого раздела является ключевой при принятии потенциальным инвестором или кредитором решения об участии в разрабатываемом проекте.
Оценка финансовой состоятельности бизнес-плана основывается на трех финансовых формах, называемыми базовыми формами финансовой оценки: таблица финансовых результатов; таблица движения денежных средств; прогнозный баланс.

- Раздел 11. Стратегия финансирования.
В этом разделе следует изложить план получения финансовых средств для создания или расширения предприятия. Требуется решить, сколько необходимо средств для реализации бизнес-плана, определить источник и форму получения финансовых ресурсов, когда можно ожидать полного возврата вложенных средств и получения инвесторами дохода на них. Рассматривая различные сценарии финансирования проекта, важно определить наиболее рациональную структуру капитала. Капитал предприятия делится на две основные группы: собственный и заемный.

2 МОДУЛЬ

Проектирование и разработка
web-приложений. 

ТЕМА 1. Описание .NET Framework.



Платформа .NET Framework – это интегрированный компонент Windows, который поддерживает создание и выполнение нового поколения приложений и Веб-служб XML.

Двумя основными компонентами платформы .NET Framework являются общеязыковая среда выполнения (CLR) и библиотека классов .NET Framework. Основой платформы .NET Framework является среда CLR. Среду выполнения можно считать агентом, который управляет кодом во время выполнения и предоставляет основные службы, такие, как управление памятью, управление потоками и удаленное взаимодействие. При этом накладываются условия строгой типизации и другие виды проверки точности кода, обеспечивающие безопасность и надежность. Фактически основной задачей среды выполнения является управление кодом. Код, который обращается к среде выполнения, называют управляемым кодом, иначе код называется неуправляемым.
Другой основной компонент платформы .NET Framework – библиотека классов, представляет полную объектно-ориентированную коллекцию типов, которые применяются для разработки приложений, начиная от обычных, запускаемых из командной строки или с графическим интерфейсом пользователя, и заканчивая приложениями, использующими последние технологические возможности ASP.NET, такие как Web Forms и Веб-службы XML.

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

На рис. 1.1. приведена общая архитектура .NET Framework в проекции на версии этой платформы.
таблица
1.1.1. Возможности среды CLR. 

Среда CLR управляет памятью, выполнением потоков, выполнением кода, проверкой безопасности кода, компиляцией и другими системными службами. Эти средства являются внутренними для управляемого кода, который выполняется в среде CLR.
По соображениям безопасности управляемым компонентам присваиваются разные степени доверия, зависящие от ряда факторов, в число которых входит их происхождение (например, Интернет, сеть предприятия или локальный компьютер). Это означает, что управляемый компонент может или не может выполнять операции доступа к файлам, операции доступа к реестру или другие важные функции, даже если он используется в одном активном приложении.
Среда выполнения обеспечивает управление доступом для кода. Например, пользователи могут доверить исполняемому приложению, внедренному в веб-страницу, воспроизведение анимации на экране или звукозаписи, не позволяя ему при этом получить доступ к личным данным, файловой системе или сети. Таким образом, средства безопасности CLR предоставляют подлинному развернутому в Интернете программному обеспечению исключительно богатые функции.
Среда выполнения также обеспечивает надежность кода, реализуя инфраструктуру строгой типизации и проверки кода, которую называют системой общих типов (CTS). Система общих типов обеспечивает самоописание всего управляемого кода. Различные языковые компиляторы создают управляемый код, удовлетворяющий системе общих типов. Это означает, что управляемый код может принимать другие управляемые типы и экземпляры, при этом обеспечивая правильность типов и строгую типизацию.
Кроме того, управляемая среда выполнения исключает многие часто возникающие проблемы с программным обеспечением. Например, среда выполнения автоматически управляет размещением объектов и ссылками на объекты, освобождая их, когда они больше не используются. Автоматическое управление памятью исключает две наиболее часто возникающие ошибки приложений: утечки памяти и недействительные ссылки на память.

Среда выполнения также повышает продуктивность разработчиков. Например, программисты могут писать приложения на привычном языке разработки, при этом используя все преимущества среды выполнения, библиотеку классов и компоненты, написанные сторонними разработчиками на других языках.
Среда выполнения разработана для повышения производительности. Хотя общеязыковая среда выполнения предоставляет многие стандартные службы времени выполнения, управляемый код никогда не интерпретируется.
Средство компиляции по требованию (JIT) позволяет всему управляемому коду выполняться на машинном языке компьютера. Между тем диспетчер памяти устраняет возможность фрагментации памяти и увеличивает объем адресуемой памяти для дополнительного повышения производительности.
И наконец, среда выполнения может размещаться в высокопроизводительных серверных приложениях, таких как Microsoft SQL Server и Internet Information Services (IIS). Такая инфраструктура позволяет использовать управляемый код для написания собственной логики программ, пользуясь при этом высочайшей производительностью лучших производственных серверов, которые поддерживают размещение среды выполнения.

1.1.2. Библиотека классов платформы .NET Framework. 

Над уровнем CLR находится набор базовых классов платформы, а над ним расположены слой классов данных и XML, а также слой классов для создания Веб-служб (Web Services), Веб- и Windows-приложений (Web Forms и Windows Forms). Собранные воедино, эти классы известны под общим названием FCL (Framework Class Library) (рис. 1.2). Эта библиотека открывает доступ к системным функциям, включая и те, что прежде были доступны только через API Windows, а также к прикладным функциям для Веб-разработки ( ASP.NET ), для доступа к данным (ADO.NET), обеспечения безопасности и удаленного управления. Имея в своем составе более 4000 классов, библиотека FCL способствует быстрой разработке настольных, клиент-серверных и других приложений и Веб-служб.
таблица
Набор базовых классов платформы – нижний уровень FCL – не только прячет обычные низкоуровневые операции, такие как файловый ввод-вывод, обработка графики и взаимодействие с оборудованием компьютера, но и обеспечивает поддержку большого количества служб, используемых в современных приложениях (управление безопасностью, поддержка сетевой связи, управление вычислительными потоками, работа с отражениями и коллекциями и т.д.).
Над этим уровнем находится уровень классов, которые расширяют базовые классы с целью обеспечения управления данными и XML. Классы данных позволяют реализовать управление информацией, хранящейся в серверных базах данных. В число этих классов входят классы SQL, дающие программисту возможность обращаться к долговременным хранилищам данных через стандартный интерфейс SQL. Кроме того, набор классов, называемый ADO.NET, позволяет оперировать постоянными данными. Платформа .NET Framework поддерживает также целый ряд классов, позволяющих манипулировать XML-данными и выполнять поиск и преобразования XML.
Базовые классы, классы данных и XML расширяются классами, предназначенными для построения приложений на основе трех различных технологий: Web Services (Веб-службы), ASP.NET (Web Forms, Веб-формы) и Windows Forms (Windows-формы). Веб-службы включают в себя ряд классов, поддерживающих разработку облегченных распределяемых компонентов, которые могут работать даже с брандмауэрами и программами трансляции сетевых адресов (NAT). Поскольку Веб-службы применяют в качестве базовых протоколов связи стандартные протоколы HTTP и SOAP, эти компоненты поддерживают в киберпространстве подход "plug-and-play".
Инструментальные средства Web Forms и Windows Forms позволяют применять технику Rapid Application Development (RAD, быстрая разработка приложений) для построения Веб- и Windows-приложений. Эта техника сводится к перетаскиванию элементов управления с панели инструментов на форму, двойному щелчку по элементу и написанию кода, обрабатывающего события, связанные с этим элементом.
В общем, FCL можно использовать для разработки следующих типов приложений и служб:
1. консольные приложения;
2. приложения с графическим интерфейсом пользователя Windows (Windows Forms);
3. приложения ASP.NET ;
4. Веб-службы;
5. службы Windows.
Например, классы Windows Forms представляют собой полный набор типов, существенно упрощающих разработку графических интерфейсов пользователя Windows. При написании приложения форм ASP.NET можно использовать классы Web Forms.


1.1.3. Развитие платформы .NET

Версия .NET Framework 3 является ничем иным как: .NET Framework 2.0 + 4 новые подсистемы:
  • Windows Presentation Foundation (WPF) – новая подсистема интерфейса пользователя и программный интерфейс на основе XML и векторной графики.
  • Windows Workflow Foundation (WF) – новая идеология программирования, предлагаемая компанией Microsoft, основанная на бизнес-сущностях и потоках.
  • Windows Communication Foundation (WCF) – сервис-ориентированная система обмена сообщениями, которая позволяет программам взаимодействовать локально или удаленно подобно веб-сервисам.
  • Windows CardSpace (WCS) – это способ безопасной идентификации пользователей при перемещении между ресурсами Интернета без необходимости повторного ввода имен и паролей.
.NET Framework 3.5 предоставляет новые возможности технологий из версий 2.0 и 3.0 и дополнительные технологии в виде новых сборок. В .NET Framework 3.5 впервые представлены следующие технологии:
  • LINQ;
  • новые компиляторы для C#, Visual Basic, C++ и J#;
  • ASP.NET AJAX.
Пакет обновления 1 (SP1) для .NET Framework 3.5 содержит обновления нескольких сборок, поставляемых с .NET Framework 3.5. Обновления включают изменения, не затрагивающие связанные компоненты, а также дополнительные функциональные возможности технологий, вошедших в состав .NET Framework 3.5. В .NET Framework 3.5 с пакетом обновления 1 (SP1) входят следующие технологии:
  • платформа динамических данных ASP.NET ;
  • ADO.NET Entity Framework;
  • поддержка поставщика данных SQL Server 2008;
  • поддержка .NET Framework Client Profile.
1.2. Обзор технологии ASP.NET

ASP.NET – это платформа для создания Веб-приложений и Веб-сервисов, работающих под управлением IIS.
Сегодня существуют другие технологии, позволяющие создавать Веб-приложения. К ним, прежде всего, относятся популярные сегодня языки PHP и PERL, технологии JSP, CSP, более старая технология CGI и т.д. Однако, ASP.NET отличается от них высокой степенью интеграции с серверными продуктами, а также с инструментами Microsoft для разработки, доступа к данным и обеспечения безопасности. Кроме того, использование ASP.NET позволяет разрабатывать Веб- и Windows приложения, используя очень похожие технологические цепочки, одинаковые языки программирования, технологии доступа к данным и т.д. Более того, базовые языки программирования, с помощью которых сегодня возможна разработка Веб-приложений являются полностью объектно-ориентированными, что делает разработку исполнимой части, а также ее модификацию, обслуживание, отладку и повторное использование гораздо более простым занятием, чем в других технологиях.

1.2.1. Жизненный цикл Веб-страниц ASP.NET

При выполнении страницы ASP.NET осуществляется ее жизненный цикл, во время которого исполняется ряд шагов обработки, такие как: инициализация, определение элементов управления, восстановление и поддержание рабочего состояния, выполнение кода обработчика событий, а также отрисовка. Знание жизненного цикла страницы необходимо, чтобы иметь возможность записывать код в нужный шаг жизненного цикла с нужным результатом. Кроме этого, при создании собственных элементов управления необходимо ознакомиться с жизненным циклом страницы, чтобы гарантировать правильную инициализацию элементов управления, сбор свойств элементов управления и текущих данных состояния, а также запуска любого управляющего кода.
Примечание: Далее будут использоваться такие термины, как состояние просмотра (оно же – состояние вида, ViewState ), сессия (Session) и другие. Их объяснение будет дано позднее, в разделе " Управление состоянием в ASP.NET "

1.2.1.1. Общие этапы жизненного цикла страницы

В целом страница проходит через этапы, описанные в табл. 1.1. Кроме этапов жизненного цикла страницы существуют этапы приложения, которые выполняются до и перед запросом, но не являются обязательными для страницы.
таблица
таблица
На каждом этапе жизненного цикла страницы она вызывает события, которые могут быть использованы для управления выполнением собственного кода. В случае элементов управления обработчик событий привязывается к событию при помощи атрибутов типа onclick, или в коде.
Страницы также поддерживают автоматическую обработку: ASP.NET производит поиск методов с соответствующими именами и автоматически выполняет эти методы при возникновении определенных событий. Если атрибут AutoEventWireup в директиве @Page установлен в значение true (или не установлен, так как он имеет значение true по умолчанию), события страницы автоматически привязываются к методам, которые используют правила именования Page_event, например Page_Load и Page_Init..
Табл. 1.2 показывает события жизненного цикла страницы, которые используются наиболее часто. Могут существовать и другие события, но они почти не используются в сценариях обработки страниц. Вместо этого они в большинстве случаев используются
серверными элементами управления на странице ASP.NET для своей инициализации и отображения.
таблица
таблица
Отдельные серверные элементы управления ASP.NET обладают собственным жизненным циклом, сходным с жизненным циклом страницы. Например, события Init и Load происходят во время соответствующих событий страницы.
Хотя Init и Load рекурсивно происходят с каждым элементом, они выполняются в обратном порядке. Событие Init (а также Unload ) для каждого дочернего элемента происходят до возникновения соответствующего события в его контейнере (снизу вверх). Однако событие Load в контейнере происходит до событий Load в дочерних элементах управления (сверху вниз).
При наследовании класса из класса Page кроме обработки событий страницы можно также переопределять методы базовых классов страницы. Например, при переопределении метода страницы InitializeCulture для динамической установки языка и региональных параметров. Стоит обратить внимание на то, что при создании обработчика событий с использованием синтаксиса Page_event базовая реализация вызывается явным образом и поэтому не требует вызова в методе. Например, метод базового класса страницы OnLoad вызывается вне зависимости от создания метода Page_Load. Однако при переопределении метода OnLoad с применением ключевого слова override ( Overrides в Visual Basic) необходимо вызвать базовый метод явным образом. Например, при переопределении метода страницы OnLoad необходимо вызвать base.OnLoad() ( MyBase.OnLoad() в Visual Basic) для запуска базовой реализации.

1.2.2. Управление состоянием в ASP.NET

Если просмотреть HTML-код любой aspx-страницы, то можно обратить внимание, что внутри формы страницы находятся скрытые поля:
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTY1NDU2MTA1MmRkIrOULfk+GC2eXyao7O8emfNAp+4=" />


Эти поля используются для возврата информации серверу. Возврат информации серверу осуществляется с помощью механизма состояний просмотра (состояние вида, ViewState ). Как видно, строка ViewState не является читабельной, т.к. выглядит как последовательность случайных символов. На самом деле, значение ViewState представляет собой строку, заданную в формате Base64 и пользователь может достаточно легко интерпретировать эти данные, преобразовав их в формат ASCII.
ViewState используется для сохранения состояний между отправками страниц на сервер и обратно на клиент, и позволяет серверу понять, как восстановить страницу к прежнему виду и узнать, какие поля пользователь изменил на странице. Это не единственный механизм сохранения состояния, используемый в ADO.NET. Рассмотрим эти механизмы.
В табл. 1.3, 1.4, 1,5 приводится краткий сравнительный анализ всех доступных для управления состоянием опций.
таблица
таблица
таблица
таблица
1.2.3. Состояние просмотра ViewState

Веб-элементы управления ASP.NET используют состояние просмотра по умолчанию. Оно позволяет им сохранять их свойства между отправками данных (postback). С помощью свойства ViewState можно добавить в коллекцию состояния просмотра свои собственные данные. В частности, можно здесь хранить простые типы данных и свои собственные специальные объекты.
Как и в основе большинства опций для управления состоянием в ASP.NET, в основе состояния просмотра лежит коллекция типа словаря, где каждый элемент индексируется с помощью уникального строкового имени. Например:
ViewState["CurrentPage"] = 3;
Этот код помещает в коллекцию ViewState значение 3 (или, скорее, целое число, которое содержит значение 3) и присваивает ему описательное имя CurrentPage. Если в коллекции ViewState на текущий момент нет элемента с именем CurrentPage, в нее будет автоматически добавлен такой новый элемент.
Если элемент с таким именем уже существует, он будет заменен. При извлечении значения следует использовать имя ключа. Помимо этого, также следует привести извлекаемое значение к соответствующему типу данных. Этот дополнительный шаг является обязательным, потому что коллекция ViewState сохраняет (хранит) все элементы в виде объектов обобщенного типа, что позволяет ей иметь дело со многими различными типами данных.

Ниже показан код, который извлекает значение CurrentPage и преобразовывает его в целое число:
int counter; if (ViewState["CurrentPage"] != null) { counter = (int)ViewState["CurrentPage"]; }

При попытке отыскать значение, которого нет в коллекции, будет выдано исключение NullReferenceException. Чтобы исключить возможность возникновения такой ситуации, прежде чем пытаться извлечь и привести к определенному типу данные, которых может и не быть, следует выполнить проверку на наличие значения null.

1.2.3.1. Сохранение объектов в состоянии просмотра

В состоянии просмотра можно сохранять свои собственные объекты, причем так же легко как числовые и строковые типы. Однако чтобы элемент был сохранен в состоянии просмотра, ASP.NET должен быть способен преобразовать его в поток байтов для того, чтобы он мог быть добавлен в скрытое поле для ввода данных на странице. Этот процесс называется сериализацией. Если объекты не поддаются сериализации (а по умолчанию это именно так), при попытке поместить их в состояние просмотра, появится сообщение об ошибке.

Чтобы сделать объекты пригодными для сериализации, следует просто добавить перед объявлением соответствующего класса атрибут Serializable. Например, ниже показан чрезвычайно простой класс BookPage:
[Serializable] public class BookPage { public int PageNamber; public string Text; public BookPage(int pageNamber, string text) { PageNamber = pageNamber; Text = text;
} }
Поскольку класс BookPage помечен как пригодный для сериализации/поддающийся сериализации, он может быть сохранен в состоянии просмотра:
BookPage page = new BookPage (3, "Понедельник начинается в субботу"); ViewState["CurrentPage"] = page;
Не забывайте о том, что когда используются специальные объекты, при извлечении из состояния просмотра данные обязательно должны приводиться к какому-нибудь типу: BookPage cust = (BookPage)ViewState["CurrentPage"];
Чтобы класс поддавался сериализации, он должен отвечать следующим требованиям:
  • он должен иметь атрибут Serializable ;
  • все порождаемые от него классы тоже должны иметь атрибут Serializable ;
  • все индивидуальные переменные этого класса должны представлять собой поддающиеся сериализации типы данных, а все не поддающиеся сериализации типы данных должны сопровождаться атрибутом NonSerialized (во время процесса сериализации они будут просто игнорироваться).
6.2.3.2. Оценивание преимуществ использования состояния просмотра

Применение состояния просмотра является идеальным вариантом, потому что не предполагает использования никаких ресурсов памяти сервера и появления случайных ограничений (типа таймаута). Но есть и некоторые причины, когда состояние просмотра лучше не применять:
  • Когда необходимо сохранить критически важные данные, возможность изменения пользователем которых должна быть полностью исключена (например, сообразительный пользователь мог бы изменить данные состояния просмотра в запросе на обратную отправку данных). В таком случае, лучше использовать состояние сеанса.
  • Когда необходимо сохранить информацию, которая будет использоваться несколькими страницами. В таком случае больше подойдет состояние сеанса, cookie-наборы или строка запроса.
  • Когда необходимо сохранить чрезвычайно большой объем информации и не хочется, чтобы это повлияло на скорость передачи данных страницы. В таком случае может оказаться лучше использовать базу данных или состояние сеанса. Чтобы повысить скорость передачи данных на странице, состояние просмотра, если оно не используется, лучше отключить. Хотя отключить состояние просмотра можно как на уровне приложения, так и на уровне страницы, наиболее правильный вариант – отключить его на уровне элемента управления. Элемент управления не нуждается в состоянии просмотра в трех следующих случаях:
  • Когда этот элемент управления никогда не изменяется. Например, кнопка со статическим текстом не нуждается в состоянии просмотра.
  • Когда этот элемент управления заново заполняется данными после каждой отправки данных. Например, элемент управления типа надписи ( Label ), отображающий текущее
время, значение для которого устанавливается в обработчике событий Page.Load, не нуждается в состоянии просмотра.
  • Когда этот элемент управления представляет собой элемент управления для ввода данных и изменяется только после того, как пользователь выполнит соответствующие действия. После каждой отправки данных ASP.NET будет заполнять такие элементы управления данными, используя введенные в форме значения. Это означает, что текст в текстовом поле или выбранный элемент в поле со списком не будут утрачиваться, даже если состояние просмотра не используется.
Чтобы отключить состояние просмотра для какого-нибудь одного элемента управления, необходимо установить для свойства EnableViewState этого элемента управления значение false. Чтобы отключить состояние просмотра для всей страницы и всех отображаемых на ней элементов управления, необходимо установить значение false для свойства EnableViewState этой страницы или используйте в директиве Page атрибут EnableViewState, как показано ниже:

<%@ Page Language="c#" EnableViewState="false" ... %>

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

1.2.4. Строка запроса

Одним из самых серьезных ограничений состояния просмотра является то, что оно работает только на одной странице. Если пользователь переходит на другую страницу, сохраненная в нем информация утрачивается. Существует несколько способов решить эту проблему; то, какой из них будет наиболее подходящим, зависит от имеющихся требований.
Наиболее распространенный подход – передавать информацию с помощью строки запроса в URL-адресе. Именно этот подход часто применяется в поисковых службах. Например, при выполнении поиска на Веб-сайте Google, пользователь будет перенаправлен на новый URL-адрес, включающий указанные им параметры поиска:

http://www.google.ru/search?ie=UTF-8&hl=ru&q=evolution&redir_esc=y&ei=iRKRS5ndN5-inQOH96DTBg

Строка запроса – это та часть URL-адреса, которая находится после вопросительного знака.

Преимуществом строки запроса является то, что она проста и не возлагает никакой нагрузки на сервер. В отличие от межстраничной пересылки данных, строка запроса может запросто переносить одну и ту же информацию со страницы на страницу. Однако она имеет несколько ограничений:
  • она может передавать информацию только в виде простых строк, которые должны содержать допустимые для использования в URL-адресе символы;
  • передаваемая с помощью строки запроса информация визуально доступна для пользователя и любого другого работающего в Интернете человека;
  • инициативный пользователь может решить изменить строку запроса и предоставить новые значения, которые программа никак не ожидает получить и от которых она не имеет защиты;
  • многие браузеры имеют ограничения касательно длины URL-адреса (которая, как правило, не должна превышать 1-2 КБ), поэтому в строку запроса нельзя поместить большое количество информации, и все равно придется выполнять проверку на совместимость с большинством браузеров.
И все-таки добавление информации в строку запроса является полезной технологией. Она особенно подходит для приложений баз данных, в которых пользователю отображается список элементов, соответствующих записям в базе данных (например, это может быть список продуктов): пользователь выбирает элемент, после чего он перенаправляется на другую страницу, содержащую детальную информацию о том элементе, который был им выбран. Один из наиболее простых способов реализовать такую схему – это заставить первую страницу отправлять идентификатор элемента второй странице. Вторая страница затем будет отыскивать этот элемент в базе данных и отображать детальную информацию о нем. Эта технология очень часть применяется на сайтах электронной коммерции, таких как Amazon.com.

1.2.4.1. Использование строки запроса

Чтобы сохранить информацию в строке запроса, ее придется сначала самостоятельно поместить туда. Как правило, это означает, что придется использовать специальный элемент управления HyperLink или оператор Response.Redirect(), подобный тому, который показан ниже:
// Переходим на страницу products/default.aspx. int categoryID = 10; Response.Redirect("products/default.aspx?category=" + recordID.ToString());

Отправлять можно и несколько параметров, только тогда их следует разделять с помощью амперсанда ( & ), как показано ниже:
Response.Redirect("products/default.aspx?category=" + categoryID.ToString()+"&subcategory="+subcategoryId.ToString());

Получающей странице легче работать со строкой запроса. Она может получать значения из коллекции типа словаря QueryString, предоставляемой встроенным объектом Request, как показано ниже:
string ID = Request.QueryString["category"];

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

1.2.5. Cookie

Специальные cookie-наборы – это еще один способ сохранить информацию для последующего использования. Cookie-наборы представляют собой небольшие файлы, которые создаются на жестком диске клиента (или, если они являются временными, в памяти Веб-браузера). Одним из преимуществ cookie-наборов является то, что они
работают "прозрачно" и пользователь даже не знает о том, что эта информация должна быть сохранена. Они также могут запросто использоваться любой страницей в приложении и даже сохраняться между посещениями, что подразумевает действительно долгосрочное хранение. Они имеет те же недостатки, что и строки запросов. А именно: они могут хранить только простую строковую информацию, и пользователь запросто может получить к ним доступ и просмотреть их, отыскав и открыв соответствующий файл. Эти факторы делают их неподходящим вариантом, когда требуется сохранить сложную или секретную информацию или просто большие объемы данных.
Некоторые пользователи отключают функцию, отвечающую за cookie-наборы, в своих браузерах, что приводит к появлению проблем при работе с Веб-приложениями, которые требуют их. В целом, cookie-наборы можно назвать распространенным явлением, потому что так много сайтов используют их. Однако они могут ограничивать потенциальную аудиторию и никак не подходят для браузеров, встроенных в мобильные устройства.
Прежде чем использовать cookie-наборы, следует импортировать пространство имен System.NET, которое позволяет работать с соответствующими типами, как показано ниже:
using System.Net;
В использовании cookie-наборов в принципе нет ничего особого сложного. Коллекцию Cookies предоставляют два объекта: объект Request и объект Response (оба из которых предоставляются через свойства объекта Page ). Главное запомнить следующее: извлекать cookie-наборы следует из объекта Request, а устанавливать их следует с помощью объекта Response.
Чтобы установить cookie-набор, необходимо создать новый объект System.Net.HttpCookie. Затем, необходимо заполнить его строковой информацией и присоединить его к текущему Веб-ответу, как показано ниже:
// Создаем объект cookie HttpCookie cookie = new HttpCookie("Language"); // Устанавливаем в нем значение cookie["LanguagePref"] = "English"; // Добавляем его в текущий Веб-ответ Response.Cookies.Add(cookie);
Cookie-набор, добавленный таким образом, будет сохраняться до тех пор, пока пользователь не закроет окно браузера, и будет отправляться вместе с каждым запросом. Чтобы создать cookie-набор с более длинным сроком хранения, необходимо установить дату истечения срока, как показано ниже:
// Этот cookie будет оставаться действительным в течение одного года. cookie.Expires = DateTime.Now.AddYears(1);
Извлекаются cookie по имени с помощью коллекции Request.Cookies, как показано ниже:
HttpCookie cookie = Request.Cookies["Language"];
// Проверяем, был ли найден cookie с таким именем.
// Это хорошая мера предосторожности, потому что пользователь может отключить поддержку cookie's,
//а в таком случае cookie не будет существовать. string language; if (cookie != null) { language = cookie["LanguagePref"]; }

Единственный способ удалить cookie – это заменить его на cookie-набор, дата истечения срока хранения которого уже прошла. Следующий фрагмент кода демонстрирует, как это можно сделать:
HttpCookie cookie = new HttpCookie("LanguagePref"); cookie.Expires = DateTime.Now.AddDays(-1); Response.Cookies.Add(cookie);

1.2.6. Использование Session

Состояние сеанса (Session) – это самая сложная технология управления состояниями. Она позволяет сохранять информацию на одной странице и затем получать к ней доступ с другой страницы, а также поддерживает объекты любого типа, включая специальные, создаваемые самим разработчиком, типы данных. Лучше всего то, что состояние сеанса использует тот же основанный на коллекциях синтаксис, что и состояние просмотра. Единственное отличие – имя встроенного свойства страницы, которое в данном случае выглядит так: Session.

Каждый клиент, который получает доступ к приложению, имеет свой сеанс и свою отдельную коллекцию данных. Состояние сеанса идеально подходит для сохранения таких данных, как элементы, которые находятся в "корзине для покупок" пользователя, когда он переходит с одной страницы на другую. Но использование состояния сеанса имеет некоторые недостатки. Хотя оно решает многие из проблем, которые возникают в случае применения других технологий управления состояниями, его использование вынуждает Веб-сервер сохранять дополнительную информацию в памяти. Эта необходимость в использовании дополнительных ресурсов памяти сервера, пусть даже в маленьком объеме, очень быстро может достичь угрожающего производительности уровня, когда к сайту начнут получать доступ сотни или тысячи клиентов.

1.2.6.1. Архитектура сеанса

Управление сеансом не является частью HTTP-стандарта. Поэтому ASP.NET приходится выполнять некоторую дополнительную работу, чтобы отследить информацию сеанса и привязать ее к соответствующему ответу.
ASP.NET отслеживает каждый сеанс с помощью уникального 120-ти битового идентификатора. ASP.NET использует для генерации этого значения оригинальный алгоритм, что, согласно статистике, обеспечивает гарантию того, что число будет уникальным и достаточно случайным для того, чтобы злонамеренный пользователь не смог воссоздать или угадать идентификатор сеанса, которым будет пользоваться данный клиент. Этот идентификатор является единственным фрагментом информации, который передается между Веб-сервером и клиентом. Когда клиент предоставляет идентификатор сеанса, ASP.NET отыскивает соответствующий сеанс, извлекает из сервера состояний
"сериализованные" данные, преобразовывает их в "реальные" объекты и помещает эти объекты в специальную коллекцию для того, чтобы к ним можно было получить доступ в коде. Весь этот процесс выполняется автоматически.

Рассмотрим, как ASP.NET хранит данные в сессии.

Когда ASP.NET обрабатывает HTTP-запрос, тот проходит через конвейер различных модулей, которые могут реагировать на события приложения. Одним из модулей в этой цепочке является модуль SessionStateModule (который находится в пространстве имен System.Web.SessionState ). Этот модуль генерирует идентификатор сеанса, извлекает из внешних поставщиков состояния данные сеанса и затем привязывает эти данные к контексту вызовов запроса. Он также сохраняет данные состояния сеанса, когда обработка страницы завершается. Однако важно понимать, что модуль SessionStateModule фактически не хранит данные сеанса. Вместо этого, состояние сеанса сохраняется во внешних компонентах, которые называются поставщиками состояния. Весь этот процесс показан на рис. 1.4.
таблица
Рис. 1.4. Архитектура состояния сеанса в ASP.NET
Состояние сеанса представляет собой пример сменной архитектуры в ASP.NET. Поставщиком состояния может быть любой класс, который реализует интерфейс IStateClientManager, а это означает, что способ работы состояния сеанса можно настроить, просто создав (или купив) новый .NET-компонент. ASP.NET включает три заготовленных поставщика состояния, которые позволяют сохранять информацию в процессе, в отдельной службе и в базе данных SQL Server.

1.2.6.2. Использование состояния сеанса

Взаимодействовать с состоянием сеанса можно используя класс System.Web.SessionState.HttpSessionState, который на Веб-странице ASP.NET доступен в виде встроенного объекта Session. Синтаксис для добавления элементов в эту коллекцию и их извлечения выглядит практически точно так же, как и синтаксис, который используется для добавления элементов в состояние просмотра страницы.

Например, сохранить объект DataSet в памяти сеанса можно следующим образом:

Session["ds"] = ds;

После этого, его можно извлечь с помощью соответствующей операции преобразования:

ds = (DataSet)Session["ds"];

Контекст состояния сеанса охватывает все приложение и является глобальным для текущего пользователя. Состояние сеанса утрачивается в следующих случаях:
  • если пользователь закрывает и заново запускает браузер;
  • если пользователь получает доступ к той же странице через другое окно браузера при сохранении доступа к Веб-странице из исходного окна браузера (разные браузеры ведут себя по-разному в такой ситуации);
  • если сеанс завершается из-за отсутствия активности со стороны пользователя (по умолчанию сеанс автоматически завершается после 20 минут простоя);
  • если программист завершает сеанс, вызывая метод Session.Abandon().
В первых двух случаях, сеанс фактически остается в памяти, потому что Веб-сервер не имеет ни малейшего понятия о том, что клиент закрыл или сменил окно браузера. Сеанс будет находиться в памяти, оставаясь недоступным, до тех пор, пока, в конце концов, не истечет срок его действия.

1.2.6.3. Поставщики состояния сеанса

Параметр настройки состояния сеанса Mode позволяет указывать, какой поставщик состояния сеанса должен использоваться для хранения данных состояния сеанса между запросами. Допустимые значения описываются ниже.

1.2.6.3.1. Off

Установка значения Off приводит к отключению функции управления состоянием сеанса для всех страниц в приложении. Это может немного повысить производительность Веб-сайтов, которые не используют состояние сеанса.

1.2.6.3.2. InProc

Установка значения InProc напоминает подход, который использовался для хранения состояния сеанса в классической версии ASP. Это значение указывает ASP.NET хранить информацию в текущем домене приложения, что обеспечивает наилучшую производительность, но наименьший срок службы: если администратор перезапустит сервер, данные состояния будут утрачены.
Значение InProc используется по умолчанию и подходит для большинства Веб-сайтов небольшого размера. Однако в сценарии с группой серверов от него не будет никакого толку. Сделать так, чтобы состояние сеанса могли совместно использовать сразу несколько серверов, можно только воспользовавшись внепроцессным поставщиком или службой состояний SQL Server. Еще одна причина, по которой установка значения InProc может быть нежелательной, состоит в том, что оно подразумевает создание более "хрупких" сеансов. В ASP.NET, домены приложений нередко создаются заново в ответ на различные операции типа изменения конфигурационных настроек или обновления страниц, а так же при достижении определенных пороговых значений (независимо от того, произошла ошибка или нет). Если будет обнаружено, что домен приложения часто перезапускается, что приводит к преждевременному завершению сеансов, можно попытаться устранить этот эффект, изменив те или иные параметры модели процесса, или воспользоваться другим более надежным поставщиком состояния сеанса.

Прежде чем использовать внепроцессную модель (StateServer) или службу состояний SQL Server, придется принять во внимание следующие моменты:

  • Когда выбирается режим StateServer или SqlServer, сохраняемые в состоянии сеанса объекты должны допускать сериализацию. Иначе ASP.NET не сможет передавать их службе состояний или сохранять в базе данных.
  • Если ASP.NET обслуживает группа Веб-серверов, придется выполнить некоторые дополнительные конфигурационные шаги для гарантии того, что все Веб-серверы будут работать синхронно. Иначе, не исключено, что один сервер будет кодировать информацию не так, как другой, а это, несомненно, приведет к появлению проблем, если во время сеанса пользователь будет перенаправляться от одного сервера к другому (решением этой проблемы является изменение раздела <machineKey> файла machine.config так, чтобы он был одинаковым на всех серверах).
  • Если не используется внутрипроцессный поставщик состояния, событие SessionStateModule.End не будет инициироваться, и все обработчики этого события в файле global.asax или HTTP-модуле будут игнорироваться.

1.2.6.3.3. StateServer

В случае установки этого значения, ASP.NET будет использовать для управления состоянием отдельную службу Windows. Даже при запуске на том же самом Веб-сервере эта служба будет загружаться за пределами основного процесса ASP.NET, что обеспечивает для нее базовый уровень защиты, когда возникает необходимость перезапустить процесс ASP.NET. Недостатком такого подхода является то, что из-за того, что данные состояния передаются между двумя процессами, увеличивается время задержки. Если доступ к данным сеанса получается часто, и они часто изменяются, это может сильно замедлить работу.
Выбрав режим StateServer, обязательно следует указать значение для параметра stateConnectionString. Эта строка сообщает TCP/IP-адрес компьютера, на котором запускается служба StateServer, и номер его порта (который определяется ASP.NET и который, как правило, не требуется изменять). Это позволяет обслуживать службу StateServer на другом компьютере. Если не изменить значение этого параметра, будет использоваться локальный сервер (адрес которого выглядит так: 127.0.0.1).

1.2.6.3.4. SqlServer

Это значение указывает ASP.NET использовать для хранения данных сеанса базу данных SQL Server, применяя параметры, определенные в атрибуте sqlConnectionString. Такой способ управления состоянием является самым удобным, но и пока что самым медленным. Чтобы его можно было использовать, на сервере должна быть установлена база данных SQL Server. Установка значения для атрибута sqlConnectionString выполняется по схеме, подобной той, что используется для получения доступа к данным ADO.NET. В целом это подразумевает указание источника данных (т.е. адреса сервера), имени пользователя и пароля, если только не используется интегрированная система безопасности SQL.
Обычно база данных состояния всегда называется "ASPState". Поэтому строка подключения в файле web.config не отображает явно имя базы данных. Вместо этого, она просто отражает месторасположение сервера и тип аутентификации, который будет использоваться:

<sessionState sqlConnectionString="data source=127.0.0.1;Integrated Security=SSPI" ... />

При желании использовать другую базу данных (с такой же структурой), необходимо установить для атрибута allowCustomSqlDatabase значение true и убедиться в том, что строка подключения включает параметр Initial Catalog, указывающий имя базы данных, которую следует использовать:

<sessionState allowCustomSqlDatabase="false" sqlConnectionString= "data source=127.0.0.1;Integrated Security=SSPI;Initial Catalog=CustDatabase" ... />

Выбрав режим SqlServer, также можное установить значение для необязательного атрибута sqlCommandTimeout. Этот атрибут указывает максимальное количество секунд, в течение которых должен ожидаться ответ от базы данных, прежде чем запрос будет отменен. По умолчанию ему присваивается значение, равное 30 секундам.

1.3. Принципы разработки пользовательского интерфейса Интернет-приложений

Вопросы построения пользовательского интерфейса являются одними из самых важных в процессе разработки приложения. В случае разработки Веб-приложения, они являются особенно актуальными, т.к. процесс создания пользовательского интерфейса здесь имеет ряд существенных отличий от традиционных Windows-приложений. При построении Веб-приложения необходимо учитывать тот факт, что его интерфейс отображается в окне браузера, и, следовательно, ограничен его возможностями.
Разработку пользовательского интерфейса Веб-приложения можно производить как с помощью редактирования исходного кода страницы, так и с использованием встроенного в Visual Studio визуального редактора. Наиболее эффективным способом является использование комбинированного метода, при котором в некоторых режимах редактирования целесообразно пользоваться визуальными средствами, в других же случаях – средствами редактирования исходного кода.
Основной сложностью при разработке пользовательского интерфейса Веб-приложения является позиционирование его элементов. Существует четыре основных режима размещения элементов управления Веб-страницы:
  • Абсолютное позиционирование (absolutely positioned) – позволяет располагать элементы в точности там, куда их помещает разработчик. При этом элементы управления имеют абсолютное положение на странице.
  • Относительное позиционирование (relatively positioned) – очень похоже на абсолютное с той разницей, что позиция элемента задается относительно элемента, имеющего статическое расположение на странице.
  • Статическое позиционирование (statically positioned) – при котором положение элементов управления определяется относительно других элементов управления, размещенных на странице. При этом все элементы располагаются последовательно один за другим.
  • Без заданного атрибута позиционирования (no positioning attribute) – при котором редактором удаляется любая информация относительно позиционирования элемента управления. При этом используется статическое позиционирование.
Статическое позиционирование рекомендуется использовать в случае, когда расположенный на странице текст чередуется с элементами управления.
При использовании абсолютного и относительного позиционирования Visual Studio добавляет специальные атрибуты, задающие положение элемента. В следующем примере показан фрагмент кода HTML, в котором описывается расположение трех кнопок с разными атрибутами позиционирования:
<asp:Button ID="Button1" runat="server" Style="z-index: 100; left: 436px; position: absolute;top: 187px" Text="Button1" /> <asp:Button ID="Button2" runat="server" Style="left: 245px; position: relative; top: 266px" Text="Button2" /> <asp:Button ID="Button3" runat="server" Style="position: static" Text="Button3" />

Для элемента Button1 использовалось абсолютное позиционирование, для Button2 – относительное, Button3 – статическое (рис. 1.5).
таблица
Рис. 1.5. Перегрузка данных и обработка запроса Для создания пользовательского интерфейса Веб-приложения возможно использование как серверных, так и HTML элементов управления. Доступ к серверным элементам управления возможен из кода приложения, что дает больше возможностей по управлению ими. Однако серверные элементы требуют больше ресурсов, т.к. для них необходимо сохранение значений атрибутов в состоянии вида.
Если сгруппировать HTML и серверные элементы управления, по видам задач программирования, можно получить табл. 1.6.
таблица
таблица
1.3.1. Работа с текстом
Одной из наиболее часто возникающих задач при создании Веб-приложения, является работа с текстом. Для этого существует несколько различных способов, начиная от Response.Write("Текст") и заканчивая использованием элемента Label или TextBox с установленным в True значением свойства ReadOnly.
Рассмотрим небольшой пример, который переопределяет текст, отображаемый при помощи элемента Label, на текст, набранный пользователем в элемент TextBox. Для этого реализуем следующую страницу:
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<br />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> <br /> <asp:Button ID="Button1" runat="server" Text="Button" OnClick="OnClick"/>
</div>
</form>
</body>

Как видно, изначально компонент Label1 отображает текст Label. Реализуем обработчик события OnClick кнопки так, чтобы она отображала в Label набранный пользователем текст: protected void OnClick(object sender, EventArgs e)
{ Label1.Text = TextBox1.Text; }
Результат работы представлен на рис. 1.6.
таблица
Рис. 1.6. Смена выводимой надписи в элементе Label при нажатии на соответствующую кнопку

1.3.2. Использование элементов CheckBox, CheckBoxList, RadioButton, RadioButtonList и BulletedList

В ряде случаев необходимо принимать от пользователя булевые значения, для этих целей применяются элементы CheckBox, CheckBoxList, RadioButton и RadioButtonList. Элементы CheckBox и RadioButton отличаются тем, что CheckBox позволяет устанавливать значения одного или нескольких флажков одновременно, в то время как RadioButton – только одно значение. Окончание List говорит о том, что данный элемент управления представляет собой целый набор флажков, объединенных в группу. Группы флажков легче привязывать к источникам данных, поэтому их целесообразнее использовать в случае, если флажки должны отображать данные, находящиеся в БД, либо с помощью них данные должны вводиться в базу данных, либо если флажки логически связаны между собой.
Для получения значений элементов управления CheckBox и RadioButton необходимо использовать свойство Checked. Например, в следующем коде осуществляется проверка значения флажка, которое выводится на экран:
protected void Button1_Click(object sender, EventArgs e)
{ Response.Write("Флажок установлен в значение "+CheckBox1.Checked.ToString()); }

При необходимости использования элементов RadioButton, необходимо установить одинаковые значения свойства GroupName элементов, которым необходимо взаимодействовать друг с другом. В противном случае, все элементы будут работать независимо друг от друга.
Для получения и установки значений элементов управления RadioButtonList и CheckBoxList необходимо последовательно опрашивать все элементы управления списка проверяя их значения. Для этого очень удобно использовать цикл For Each.
В следующем примере последовательно проверяются значения всех флажков элемента CheckBoxList1. Если флажок выбран, на экран выводится соответствующее сообщение: protected void Button1_Click(object sender, EventArgs e)
{ foreach (ListItem l in CheckBoxList1.Items)
{ if (l.Selected)
Response.Write("выбран " + l.Text + "<br/>"); } }

Следует обратить внимание на тот факт, что элемент управления CheckBoxList, как и RadioButtonList содержит элементы управления ListControl, а не CheckBox или RadioButton, как можно было бы предположить.

Аналогичным образом производятся проверки и для элемента RadioButtonList.

BulletedList является аналогом HTML элементов, предназначенных для организации упорядоченных и неупорядоченных списков с помощью тэгов <ul> и <ol> соответственно, однако позволяет обращаться к списку программно. Для установки элементов, отображаемых в списке, необходимо ввести их с помощью средств, аналогичных рассмотренным ранее для CheckBoxList и RadioButtonList. Особенностью BulletedList является возможность настройки внешнего вида и типа элементов списка. Основные свойства этого элемента управления показаны в табл. 1.7.
таблица
При использовании LinkButton в качестве элемента списка становится возможным программное определение того элемента, по которому был произведен щелчок пользователем, как показано в следующем примере:
protected void BulletedList1_Click(object sender, BulletedListEventArgs e) { Response.Write("Вы щелкнули по элементу списка "+BulletedList1.Items[e.Index].ToString()); }

1.3.3. Использование Image, ImageButton

Отображение графики на Веб-странице является абсолютно необходимым условием. ASP.NET предоставляет несколько возможностей отображения графики:
1. Как фон, заполняющий всю страницу, для этого можно воспользоваться свойством Background Веб-формы. Можно также использовать свойство BackImageUrl элемента Panel.
2. На переднем плане. Для этого используется элемент управления Image.
3. На кнопке, способной реагировать на действия пользователя. Для этого используется элемент управления ImageButton.
4. С помощью карты изображений, реализуемой посредством элемента управления ImageMap.

Элемент управления Image позволяет отображать графические изображения. При этом он неспособен реагировать на действия пользователя, однако способен отображать
графические элементы в зависимости от действий, выполненных над другими элементами управления.
В следующем примере при нажатии на соответствующую кнопку отображается изображение машины, мотоцикла либо велосипеда (рис. 1.7):
protected void buttonCar_Click(object sender, EventArgs e) { Image1.ImageUrl = "~//Images//car.jpg"; }
protected void buttonBike_Click(object sender, EventArgs e) { Image1.ImageUrl = "~//Images//bike.jpg"; }
protected void buttonCycle_Click(object sender, EventArgs e) { Image1.ImageUrl = "~//Images//cycle.jpg"; }
таблица
Рис. 1.7. Смена выводимого на экран изображения при нажатии на соответствующую кнопку
Элемент управления ImageButton имеет встроенную возможность реагирования на события, совершаемые пользователем. При этом в обработчик события щелчка левой кнопкой мыши по нему отправляется специальный объект ImageClickEventArgs, предоставляющий свойства X и Y, которые определяют место изображения, на котором был совершен щелчок. Используя эти свойства, можно создать карту изображения. Ниже
показан код, который отображает координаты точки, в которой был произведен щелчок мыши, а также определяет, в пределах какой фигуры он был произведен (рис. 1.8):
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{ string strClickFigure="";
if (!(e.X <= 380 && e.X >= 20 && e.Y <= 380 && e.Y >= 20)) strClickFigure = "рамка";
if (e.X>=60 && e.X<=210 && e.Y>=60 && e.Y<=210) strClickFigure="квадрат";
if ((e.Y>=495-e.X) && (e.Y>=e.X-45) && e.Y<=332) strClickFigure="треугольник";
Label1.Text = "Вы щелкнули в точке Х="+e.X.ToString()+"; Y="+e.Y.ToString()+" это "+strClickFigure; }
таблица
Рис. 1.8. Пример использования элемента ImageButton

1.3.4. Использование Literal и HiddenField

Элемент управления Literal представляет собой один из способов вывода информации на экран. Literal можно использовать в качестве контейнера для размещения HTML элементов на странице. Чаще всего его используют для динамического добавления текста. Схожие возможности по добавлению текста предоставляет элемент Label, Literal отличается от него тем, что не добавляет дополнительных HTML элементов к тексту. Label, например, размещает текст внутри тэга <span>, Panel – внутри <div> и т.д. Размещение элементов внутри тэгов создает возможность для поддержки ими стилей оформления, Literal же, не имеет такой возможности. Рекомендуется использовать элемент Literal в том случае, когда необходимо размещать текст на странице без использования дополнительной разметки, либо в том случае, когда существует HTML текст (например, хранящийся в файле или базе данных), содержащий форматирование с использованием тэгов, и его необходимо вывести на экран.
Самым важным свойством элемента управления Literal является Mode. Возможны три значения этого свойства (табл. 1.8). Таблица 1.8. Значения свойства Mode элемента управления Literal
таблица
Например, при использовании следующего примера элемента Literal могут быть получены различные результаты.
При использовании значения Mode=PassThrough, как показано в следующем фрагменте исходного кода:
private string s =
"<input id='Button1' type='button' value='Добавить' /><br/>
<table border='1' cellpadding='1' cellspacing='0'>
<tr>
<td>Идентификатор</td>
<td>наименование</td>
<td>кол-во</td>
</tr>
<tr>
<td>1</td>
<td>Велосипед горный</td>
<td>10</td>
</tr>
<tr>
<td>2</td>
<td>Велосипед дорожный</td>
<td>50</td>
</tr>
</table>";
protected void Page_Load(object sender, EventArgs e)
{ Literal1.Mode = LiteralMode.PassThrough; Literal1.Text = s; }

будет получен результат, изображенный на рис. 1.9.
таблица
таблица
Рис. 1.10. Использование Literal для отображения информации в режиме Encode.
Элемент управления HiddenField целесообразно использовать в том случае, когда на странице необходимо сохранить какие-то данные, но не отображать их. Например, это может быть какая-нибудь информация о пользователе, которая необходима для выполнения сервисных функций.
У элемента HiddenField существует лишь одно свойство, заслуживающее внимания. Это Value, посредством которого ему и присваивается значение.
При использовании элемента управления HiddenField необходимо помнить о безопасности, т.к., несмотря на то, что информация, хранящаяся в данном элементе, не отображается на экране, ее легко можно увидеть, просмотрев исходный код страницы. Более того, пользователь может изменить данную информацию перед инициированием postback и отправкой ее на сервер. Поэтому не рекомендуется хранить какие-либо конфиденциальные данные, а также данные, критичные для выполнения приложения на сервере в данном элементе управления.


1.3.5. Использование Panel

Элемент управления Panel (при рендеренге страницы заменяется на div ) используется для группирования элементов управления. При этом он выступает в качестве контейнера, способного вмещать в себя различные другие элементы управления, манипулирование которыми становится возможным как единым целым. Например, возможно скрытие или показ элемента Panel со всеми входящими в него элементами путем задания значения свойства Visible равным true или false.
При размещении внутри Panel элементов для ввода текста и кнопок, становится возможным определение кнопки, используемой по умолчанию. Это означает, что при вводе текста в элементы управления, размещенные внутри Panel, пользователь имеет возможность нажать кнопку Enter, что будет равносильно щелчку левой кнопки мыши по кнопке, указанной в свойстве DefaultButton элемента Panel. Это позволяет создавать более эффективные пользовательские формы для ввода данных.
Panel облегчает размещение динамически создаваемых элементов управления на форме. И, наконец, с помощью этого элемента управления становится возможным создание областей в рамках страницы, обладающих собственными свойствами поведения и внешнего вида. Это выражается в следующем:
1. С помощью Panel можно создать область, содержащую полосы прокрутки. Для этого достаточно установить соответствующее значение свойства ScrollBars, а также установить необходимые значения свойств Height и Width.
2. С помощью Panel можно создать область группы с заголовком. Для этого необходимо ввести в свойство GroupingText строку заголовка группы. Пример изображения группы, получаемой в этом случае, приведен на рис. 1.11.
таблица
Рис. 1.11. Пример изображения группы элементов
Следует отметить, что при установке свойства GroupingText становится невозможным использование полос прокрутки.
3. С помощью Panel можно создать область страницы, имеющей отдельно заданные свойства, такие как цвет фона, рамка и т.д.

1.3.7. Использование LinkButton

Элемент управления LinkButton представляет собой кнопку, которая выглядит как гиперссылка, но имеет поведение кнопки. Этот элемент управления внедряет в HTML код страницы элементы JavaScript, необходимые для обработки событий кнопки, поэтому необходимо, чтобы клиентский браузер поддерживал JavaScript.
LinkButton может быть двух разновидностей: командная кнопка и кнопка перенаправления. Кнопка перенаправления не содержит сопоставленного с ней обработчика события и просто инициирует событие postback. Командная кнопка ведет себя как обычная кнопка и может иметь несколько обработчиков событий, сопоставленных с ней. Как и обычная кнопка, она может реагировать на щелчок левой кнопки мыши с помощью события LinkButton_Click, кроме того, возможна обработка события LinkButton_Command. В качестве аргументов, обработчику события Command передаются значения свойств CommandName и CommandArgument. С помощью этого события становится возможным определение того, какая из нескольких, расположенных на странице кнопок была нажата.
В следующем примере на странице размещены два элемента LinkButton:
<asp:LinkButton ID="LinkButton1" runat="server" CommandName="Открыть" CommandArgument="c:\1.txt" OnCommand="LinkButton_Command"> Открыть
</asp:LinkButton>
<asp:LinkButton ID="LinkButton2" runat="server" CommandArgument= "http://www.yandex.ru" CommandName="Перейти" OnCommand="LinkButton_Command"> Перейти</asp:LinkButton>

Процедура LinkButton_Command выводит на экран сообщение, в котором указаны аргументы, передаваемые обеими кнопками в случае их нажатия:
protected void LinkButton_Command(object sender, CommandEventArgs e) { Response.Write("Команда: " + e.CommandName + ", параметр: " + e.CommandArgument); }

1.4. Краткие итоги

Платформа .NET Framework – это интегрированный компонент Windows, который поддерживает создание и выполнение нового поколения приложений и Веб-служб XML.
Среда CLR управляет памятью, выполнением потоков, выполнением кода, проверкой безопасности кода, компиляцией и другими системными службами.
Библиотека классов FCL (Framework Class Library) открывает доступ к системным функциям, включая и те, что прежде были доступны только через API Windows, а также к прикладным функциям для Веб-разработки ( ASP.NET ), для доступа к данным (ADO.NET), обеспечения безопасности и удаленного управления.
ASP.NET – это платформа для создания Веб-приложений и Веб-сервисов, работающих под управлением IIS.
При выполнении страницы ASP.NET осуществляется ее жизненный цикл, во время которого исполняется ряд шагов обработки, такие как: инициализация, определение элементов управления, восстановление и поддержание рабочего состояния, выполнение кода обработчика событий, а также отрисовка.
На каждом этапе жизненного цикла страницы она вызывает события, которые могут быть использованы для управления выполнением собственного кода.
Отдельные серверные элементы управления ASP.NET обладают собственным жизненным циклом, сходным с жизненным циклом страницы.
Возврат информации серверу осуществляется с помощью механизма состояний просмотра (состояние вида, ViewState ).
Существует несколько способов сохранения состояния просмотра:
  • строка запроса в URL-адресе;
  • cookie;
  • состояние сеанса (Session).
Основной сложностью при разработке пользовательского интерфейса Веб-приложения является позиционирование его элементов.
Для создания пользовательского интерфейса Веб-приложения возможно использование как серверных, так и HTML элементов управления.
Одной из наиболее часто возникающих задач при создании Веб-приложения, является работа с текстом.
В ряде случаев необходимо принимать от пользователя булевые значения, для этих целей применяются элементы CheckBox, CheckBoxList, RadioButton и RadioButtonList.
ASP.NET предоставляет несколько возможностей отображения графики. Элемент управления Literal представляет собой один из способов вывода информации на экран.
Элемент управления HiddenField целесообразно использовать в том случае, когда на странице необходимо сохранить какие-то данные, но не отображать их.
Элемент управления Panel используется для группирования элементов управления.
Элемент управления LinkButton представляет собой кнопку, которая выглядит как гиперссылка, но имеет поведение кнопки.

ТЕМА 2. Использование MasterPage

Обычно, при создании страниц используются уже готовые шаблоны и компоненты, либо таковые создаются в процессе разработки Веб-страниц приложения. Это связано с тем, что страницы Веб-приложения составляют некое целое, объединенное едиными требованиями к оформлению, содержанию, расположению элементов управления и т.д. Таким образом, пользователь попадает в некую среду, которая должна быть максимально удобна для удовлетворения всех потребностей пользователя.
Одним из средств решения подобных задач являются мастер страницы (master pages). Они реализуют простую модель создания шаблонов форм с возможностью их повторного использования.
Для реализации данного механизма, в ASP.NET введены такие типы страниц, как мастер страницы (master pages) и страницы содержимого (content pages). Мастер страница представляет собой шаблон страницы, при этом, она может содержать любые элементы, допустимые для обычной страницы, а также программный код. Страница содержимого содержит допустимые элементы управления, с помощью которых определяет содержимое, которым заполняются специальные области мастер страниц. Каждая страница содержимого ссылается на одну мастер страницу, от которой получает элементы и их расположение.
Обычно, мастер страница содержит фиксированные элементы, одинаковые для всех страниц, и заполнитель содержимого для остальной части страницы. Наиболее типичными фиксированными элементами являются верхний и нижний колонтитулы, панель навигации, панель меню и т.д. Страница содержимого получает от мастера страницы фиксированные элементы и предоставляет дополнительное содержимое.
Для демонстрации возможностей мастер страниц рассмотрим пример создания простой мастер страницы и страницы содержимого.
Схематично структура мастер страницы показана на рис. 2.1.
таблица
Такая структура характерна для очень большого числа Веб-сайтов. Изображенные на рис. 2.1 верхний колонтитул, нижний колонтитул и панель навигации являются общими для всех страниц элементами, содержимое которые постоянно и не меняется. Содержимое страницы – та ее часть, которая меняется в зависимости от действий пользователя, именно в ней отображается полезная для пользователя информация, и именно здесь будет размещаться область, в которой будет отображаться страница содержимого.
Мастер страниц создается так же, как и обычные страницы в ASP.NET. Отличие заключается в том, что Веб-страницы начинаются с директивы Page, а мастер страница – с директивы Master:
<%--Обычная страница ASP--%>
<%@ Page Title="" Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%--Мастер страниц ASP--%>
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="MainMasterPage.master.cs" Inherits="MainMasterPage" %>

Еще одним важным отличием является то, что мастер страниц должен содержать элемент управления ContentPlaceHolder, который не имеет каких-либо примечательных свойств и предназначен для определения области, в которую страница содержимого может вставлять содержимое. При создании новой мастер страницы, элемент ContentPlaceHolder создается по умолчанию, хотя его можно удалить или добавить еще один или несколько. На рис. 2.2. показана созданная мастер страница.
таблица
Рис. 2.2. Редактирование мастер страницы в режиме дизайна
Добавим на страницу таблицу, которая будет схематично отображать шаблон сайта, состоящий из верхнего и нижнего колонтитула, меню и основной области:
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="WebApplication1.Site" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server"> </asp:ContentPlaceHolder>
<style type="text/css">
.style1
{ width: 100%; height: 100%; border-width:3px; border-color:Gray; } .style2
{ width: 254px; }
</style>
</head>
<body>
<form id="form1" runat="server" style="height:100%;">
<table class="style1" border="3">
<tr>
<td class="style2" colspan="2">Верхний колонтитул</td>
</tr>
<tr>
<td class="style2">Меню</td>
<td>
<asp:ContentPlaceHolder ID="MainPlaceHolder" runat ="server"> Основная область
</asp:ContentPlaceHolder>
</td>
</tr>
<tr>
<td class="style2" colspan="2">Нижний колонтитул</td>
</tr>
</table>
</form>
</body>
</html>
Как видно, в результате данной операции была добавлена обычная HTML-таблица, для которой были установлены значения ширины и высоты некоторых ячеек. В режиме разработки дизайна страница будет выглядеть так, как показано на рис. 2.3.
таблица
Рис. 2.3. Редактирование добавленной таблицы
Создадим страницу, основанную на созданном мастере страниц. Для примера, возьмем одну из страниц, рассмотренных на предыдущей лекции. В качестве страницы содержимого используем страницу Default.aspx, добавленную к проекту Веб-приложения по умолчанию. Для того чтобы превратить обычную страницу в страницу содержимого, необходимо в качестве значения свойства MasterPageFile страницы, указать имя мастер страницы, а также добавить на страницу элемент управления <asp:Content>.
Исходный код страницы Default.aspx в результате проделанных операций, а также ввода текста "это начальная страница Default.aspx", будет выглядеть следующим образом.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" MasterPageFile="~/Site.Master" %>
<asp:Content ContentPlaceHolderID="MainPlaceHolder" ID="Content1" runat="server">
<asp:Literal ID="Literal1" runat="server">
</asp:Literal> </asp:Content>
Результат работы программы изображен на рис. 2.4.
таблица
Рис. 2.4. Результат работы Веб-приложения на основе мастер страниц

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

2.2. Динамическое создание элементов управления

Иногда в процессе работы над приложением возникает необходимость создания динамического интерфейса. Это становится особенно актуально в случае, когда интерфейс приложения должен меняться в зависимости от действий пользователя. В этом случае удобным инструментом реализации динамического интерфейса становится возможность динамического создания и отображения на странице элементов управления. Для создания элемента управления необходимо создать объект соответствующего класса, присвоить его атрибутам необходимые значения и добавить его к коллекции элементов управления страницы. При этом следует помнить о том, что, так как в момент исполнения программного кода, создающего объект и добавляющего его к коллекции элементов управления, страница уже создана, то добавление будет всегда происходить в конец коллекции. Это означает, что элемент будет добавляться после последнего элемента управления страницы.
Для получения большего контроля над расположением динамически создаваемого элемента управления, можно воспользоваться специально предназначенным для этого элементом PlaceHolder. Данный элемент управления предназначен для размещения других элементов внутри себя и может быть размещен в любом месте страницы. При этом если внутри PlaceHolder отсутствует содержимое, это никак не повлияет на содержимое страницы.
При использовании динамически создаваемых элементов управления необходимо помнить, что они существуют только до очередной обратной отсылки. Если после обратной отсылки динамически созданный элемент управления необходимо по-прежнему отображать на странице, необходимо создавать элемент управления в обработчике события Page.Load. При создании элемента управления в обработчике
события Page.Load ASP.NET использует любую информацию о состоянии вида по завершении этого обработчика события.
Для возможности программного взаимодействия с динамически созданными элементом управления, последнему необходимо присвоить уникальный идентификатор ( ID ), являющийся аналогом ID любого другого элемента управления. В дальнейшем этот идентификатор можно использовать для того, чтобы найти данный элемент управления в коллекции элементов управления страницы с помощью метода Page.FindControl() и использовать в программном коде.

Расширим предыдущее приложение, переписав страницу следующим образом:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" MasterPageFile="~/Site.Master" %>
<asp:Content ContentPlaceHolderID="MainPlaceHolder" ID="Content1" runat="server">
<asp:Button ID="ButtonAdd" runat="server" Text="Отобразить изображение" OnClick="OnClick" />
<asp:Literal ID="Literal1" runat="server"></asp:Literal>
<asp:Panel runat="server" ID="ImagePanel">
</asp:Panel>
</asp:Content>

Теперь появилась кнопка, к которой можно привязать обработчик события нажатия кнопки мышкой OnClick. Когда пользователь нажмет кнопку, произойдет postback страницы. Как уже отмечалось раньше, страница на сервере восстановится, после чего будут вызваны все обработчики событий, в данном случае OnClick:
protected void OnClick(object sender, EventArgs e) { Image img = new Image(); img.ImageUrl = "~/Black_racer02_F_large.gif"; ImagePanel.Controls.Add(img); }

Этот код создает новый объект Image (в разметке это <asp:Image> ), у которого будет задано лишь одно свойство – ImageUrl. После этого этот компонент будет добавлен с коллекцию Controls панели ImagePanel. Теперь, на этапе Render страницы, в разметку будет добавлен новый элемент img с указанным изображением: Результат работы программы изображен на 2.5.
таблица
Рис. 2.5. Результат использования динамически созданного элемента управления
Такой динамически созданный компонент не будет обрабатывать события, так как при следующем postback' е он не будет восстановлен. Более того, если бы на странице был еще какой-либо объект, вызывающий postback, то после отправки запроса на сервер изображение пропало бы. Для того чтобы динамически созданные элементы управления могли обрабатывать события, необходимо создавать эти компоненты во время Page.Load или переопределив метод CreateChildControls. При этом чтобы предыдущий пример работал, необходимо во ViewState или в состоянии сеанса сохранить информацию о том, что изображение необходимо добавлять на страницу.
Иногда возникает необходимость изменять содержимое таблицы на основе производимых пользователем действий. В этом случае обойтись статическими элементами, вводимыми в таблицу на этапе разработки приложения невозможно. Решить данную задачу можно воспользовавшись механизмом добавления элементов в таблицу во время выполнения. Здесь следует отметить, что элемент управления Table не сохраняет те элементы, которые добавляются в него во время выполнения приложения. Это приводит к тому, что таблицу необходимо заново создавать на основе данных, сохраненных в переменной состояния.
Еще раз доработаем пример. Пусть теперь на странице расположена таблица, у которой установлена строка заголовка и первая строка содержимого. Пользователь имеет возможность добавлять новые строки. Для этого он должен внести содержимое новой строки в поле ввода, разделяя значения ячеек запятыми. После нажатия на кнопку "Добавить" новая строка добавляется к уже существующим строкам таблицы.
Перепишем разметку страницы:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" MasterPageFile="~/Site.Master" %>
<asp:Content ContentPlaceHolderID="MainPlaceHolder" ID="Content1" runat="server">
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="ButtonAdd" runat="server" Text="Отобразить изображение" OnClick="OnClick" />
<asp:Table runat="server" ID="Table1">
<asp:TableHeaderRow>
<asp:TableHeaderCell>
Идентификатор </asp:TableHeaderCell>
<asp:TableHeaderCell>
Наименование </asp:TableHeaderCell>
<asp:TableHeaderCell>
Количество </asp:TableHeaderCell>
</asp:TableHeaderRow> <asp:TableRow> <asp:TableCell>1</asp:TableCell> <asp:TableCell>Велосипед</asp:TableCell> <asp:TableCell>10</asp:TableCell>
</asp:TableRow>
</asp:Table>
</asp:Content>

Теперь таблица представлена компонентом <asp:Table>, который при отрисовке страницы будет заменен элементом table. Также добавлено текстовое поле TextBox1, в которое пользователь будет вводить данные. Исходный код серверных обработчиков страницы с комментариями представлен ниже:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebApplication1
{ public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void OnClick(object sender, EventArgs e) {
//Записать текст в состояние отображения страницы,
//причем новые данные будут сохранены под индексом ViewState. //Count, чтобы не потерять предыдущее данные
ViewState.Add(ViewState.Count.ToString(), TextBox1.Text); CreateTable(); }
private void CreateTable() {
//массив слов string[] arrWords;
//строка, состоящая из значений ячеек строки таблицы string strWords;
TableRow newRow;
TableCell newCell;
//цикл для каждого элемента ViewState for (int i = 0; i < ViewState.Count; i++) {
//символ-разделитель значений полей таблицы char[] c = { ',' };
//создать новую строку
newRow = new TableRow();
//извлечь из ViewState очередной элемент
strWords = ViewState[i.ToString()].ToString();
//преобразовать строку в массив используя разделитель arrWords = strWords.Split(c);
//цикл для каждого элемента массива слов for (int j = 0; j <= arrWords.GetUpperBound(0); j++) {
//создать новую ячейку таблицы newCell = new TableCell();
//установить текст в созданную ячейку newCell.Text = arrWords[j];
//добавить ячейку к набору ячеек строки таблицы newRow.Cells.Add(newCell); }
//добавить строку к таблице Table1.Rows.Add(newRow); } } } }
Результат работы кода страницы представлен на рис. 2.6.
таблица
Рис. 2.6. Окно динамического добавления строк таблицы

2.3. Навигация по сайту

Любое Веб-приложение представляет собой достаточно сложную совокупность взаимосвязанных страниц [5]. Хорошо продуманное и спроектированное Веб-приложение обладает не только красивым и эргономичным дизайном, но и хорошей системой навигации, позволяющей легко переходить от одного раздела к другому, а также решать другие задачи. ASP.NET обладает достаточно большими возможностями, позволяющими реализовывать сложные системы навигации. Для реализации систем навигации используется целый ряд элементов управления, предназначенных для решения отдельных задач. Рассмотрим наиболее важные и распространенные из них.

2.3.1. Карта сайта

Карты сайта целесообразно использовать в случае, когда Веб-приложение содержит большое количество страниц. Карты сайта предлагают удобный механизм определения структуры страниц приложения, а также ее отображение с помощью нескольких элементов управления.
Основных элементов управления три – SiteMapPath, Menu, TreeView. Все эти элементы предназначены для решения одной и той же задачи – предоставления возможности пользователю Веб-приложения осуществлять навигацию по страницам. Различие между ними заключается в способах отображения ссылок на соответствующие страницы. Для использования любого их перечисленных компонентов, необходимо определить структуру приложения, которая хранится отдельно. В качестве хранилища структуры обычно выступает XML файл. В Visual Studio существует уже определенная структура XML файла, предназначенная для хранения структуры приложения, это файлы типа .sitemap. Содержимое данного файла достаточно простое, что позволяет легко вносить данные о структуре приложения. Разделение элементов, отвечающих за отображение данных, и элементов, содержащих эти данные, позволяет значительно упростить редактирование приложения – для изменения
дизайна достаточно изменить настройки визуальных компонентов, для внесения дополнений – добавить данные в XML файл.
В качестве примера добавим несколько новых страниц в предыдущий пример и рассмотрим добавление навигации по страницам Веб-приложения.
Прежде всего, добавим XML файл, и введем данные о структуре приложения (рис. 2.7).
таблица
Рис. 2.7. Добавление карты сайта

В результате, будет создан файл Web.sitemap, содержащий заготовки для ввода структуры Веб-приложения:
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="" title="" description="">
<siteMapNode url="" title="" description="" />
<siteMapNode url="" title="" description="" />
</siteMapNode>
</siteMap>
Как видно из исходного кода, карта сайта должна начинаться с корневого узла <siteMap>. Элементы структуры описываются в тэгах <siteMapNode>. С помощью этих тэгов можно указывать иерархию элементов Веб-приложения. Для указания вложенных элементов их просто необходимо расположить внутри соответствующего тэга <siteMapNode>. Свойства каждого тэга необходимы для задания соответствующих значений. В примере выше видно, что каждому элементу соответствует три свойства: url, title, description. Их назначение очевидно – url используется для указания интернет адреса страницы, которой соответствует этот элемент, title задает наименование элемента, отображаемое элементом
управления, description – описание элемента, которое отображается в виде всплывающей подсказки при наведении указателя мыши на соответствующий элемент.
В качестве примера простейшей карты сайта создадим иерархию страниц, состоящую из шести позиций. Самым верхним элементом иерархии будет домашняя страница, ссылающаяся на файл Default.aspx. Все остальные элементы будут вложены в него. Кроме того, в элемент "Страница 4" должны быть вложены еще два элемента. Пример карты сайта, описывающей данную структуру, приведен ниже. <?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="Default.aspx" title="Домашняя" description=""> <siteMapNode url="Default2.aspx" title="Страница 2" description="Перейти к странице 2" />
<siteMapNode url="Default3.aspx" title="Страница 3" description="" />
<siteMapNode url="Default4.aspx" title="Страница 4">
<siteMapNode url="Default5.aspx" title="Страница 5"/> <siteMapNode url="Default6.aspx" title="Страница 6"/> </siteMapNode>
</siteMapNode>
</siteMap>

2.3.2. Использование элементов управления Menu и SiteMapPath

После того, как карта сайта определена, становится возможным использование элементов управления, связанных с ней, для отображения данных о структуре приложения. Для этого возможно использование таких элементов управления как Menu, SiteMapPath. Элемент Menu предназначен для вывода элементов структуры приложения на экран. Элемент SiteMapPath предназначен для отображения текущего положения пользователя в иерархии Веб-приложения и позволяет ему переходить вверх по иерархии на более высокий уровень. Рассмотрим примеры использования элементов управления SiteMapPath и Menu.

2.3.2.1. Использование Menu

Обратимся к предыдущему примеру, использующему мастер страницы. В соответствии с описанием карты сайта, создадим шесть файлов aspx и добавим их в проект. В результате добавления файлов, Веб-приложение должно содержать файлы Default.aspx, Default2.aspx, Default3.aspx, Default6.aspx.
Проект в окне Solution Explorer выглядит так, как показано на рис. 2.8.
таблица
таблица
Исходный код источника данных выглядит следующим образом: <asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" /> Аналогичным образом можно настроить и внешний вид меню, указав одну из имеющихся тем. В результате будет сгенерирован следующий код:
<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1" Width="103px" BackColor="#B5C7DE" DynamicHorizontalOffset="2" Font-Names="Verdana" Font-Size="0.8em" ForeColor="#284E98" StaticSubMenuIndent="10px">
<StaticSelectedStyle BackColor="#507CD1" />
<StaticMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" />
<DynamicHoverStyle BackColor="#284E98" ForeColor="White" /> <DynamicMenuStyle BackColor="#B5C7DE" />
<DynamicSelectedStyle BackColor="#507CD1" /> <DynamicMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" />
<StaticHoverStyle BackColor="#284E98" ForeColor="White" /> </asp:Menu>
После запуска приложения, его окно будет выглядеть следующим образом (рис. 2.12). Для перехода к соответствующей странице можно воспользоваться любым элементом меню, либо дерева.
таблица
Рис. 2.12. Окно Веб-приложения после добавления элементов TreeView и Menu Элемент управления Menu обладают дополнительными свойствами, с помощью которых возможно изменить их внешний вид, в соответствии с дизайном Веб-приложения.

2.3.2.2. Использование SiteMapPath

В отличие от Menu, SiteMapPath отображает только текущее положение пользователя в иерархии страниц Веб-приложения с возможностью перехода к верхнему уровню иерархии. Добавим в пример элемент SiteMapPath.
Для этого необходимо добавить еще одну строку между заголовком и содержимым мастер страницы и просто поместить в нее элемент SiteMapPath. Результат представлен на рис. 2.13.
таблица
Рис. 2.13. Добавление в приложение элемента SiteMapPath

2.4. Использование компонент для отображения данных

Одна из основных задач почти всех веб-приложений заключается в отображении различных данных. Примером таких данных могут служить и товары, продаваемые в магазине, сотрудники, работающие в организации, итоги футбольных матчей, проведенных в рамках какого-либо соревнования. В большинстве случаев эти данные имеют табличный вид, и, соответственно, отображать их пользователю также лучше в табличном виде. Однако пользоваться классом Table в данном случае неудобно, так как:
  • необходимо написать код, который будет пробегаться по все строчкам и колонкам и генерировать ячейки таблицы;
  • как правило, пользователю требуется не только просматривать данные, но также иметь возможность выполнять над ними различные манипуляции, такие как сортировка, фильтрация или выбор.
Обычная таблица такие возможности не предоставляет.

Для этих целей ASP.NET представляет сразу несколько визуальных компонент, среди которых выделим GridView и DataList.

2.4.1. Компонент GridView

Элемент управления GridView можно использовать для выполнения следующих задач:
1. автоматическая привязка и отображение данных из элемента управления источника данных;
2. выбирать, сортировать, пролистывать, изменять и удалять данные из элемента управления источника данных. Помимо этого, внешний вид и поведение элемента управления GridView можно изменять следующими способами:
  • определять настраиваемые столбцы и стили;
  • использовать шаблоны для создания настраиваемых элементов интерфейса пользователя ( UI );
  • вводить пользовательский код в функциональность элемента управления GridView с помощью обработчиков событий.
7.4.1.1. Привязка данных
Элемент управления GridView допускает два способа привязки к данным:
  • Привязка данных с использованием свойства DataSourceID, позволяющего привязать элемент управления GridView к элементу управления источника данных. Этот подход является предпочтительным, поскольку он позволяет элементу управления GridView использовать возможности элемента управления источника данных и предоставить встроенную функциональность для сортировки, разбиения по страницам и обновления данных.
  • Привязка данных с использованием свойства DataSource, позволяющего выполнять привязку к различным объектам, включая наборы данных и модули чтения данных ADO.NET. При использовании этого подхода код реализации дополнительной функциональности наподобие сортировки, разбиения по страницам и обновления данных требуется писать самостоятельно.
При выполнении привязки к источнику данных с использованием свойства DataSourceID элемент управления GridView поддерживает двустороннюю привязку данных. Помимо того, что элемент управления будет отображать возвращенные данные, можно включить в элементе управления автоматическую поддержку операций обновления и удаления привязанных данных.

2.4.1.2. Форматирование отображаемых данных

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

2.4.1.3. Изменение и удаление данных

По умолчанию элемент управления GridView отображает данные в режиме "только для чтения". Тем не менее, элемент управления также поддерживает режим редактирования, в котором строка отображается с помощью таких элементов управления, допускающих редактирование, как TextBox или CheckBox.
Элемент управления GridView также можно настроить на отображение кнопки Delete, которая позволяет удалить соответствующую запись из источника данных. Элемент управления GridView способен автоматически выполнять операции изменения и удаления данных над источником данных, к которому он привязан, что позволяет обеспечить возможность редактирования без необходимости написания дополнительного кода. Наряду с этим процесс изменения и удаления данных можно контролировать программным способом, например, при привязке элемента управления GridView к элементу управления источника данных, доступному только для чтения.
Элементы управления ввода данных, используемые при отображении строки в режиме редактирования, можно настроить с помощью шаблона.

2.4.1.4. Шаблоны столбцов

Элемент управления GridView может автоматически создавать столбцы из полей, предоставляемых источником данных. Кроме того, вместо автоматического создания столбцов можно самостоятельно создавать коллекцию столбцов для отображения. Однако может встретиться ситуация, в которой будет необходимо настроить отображение отдельного столбца. В таком случае можно создать TemplateField для задания структуры пользовательского столбца.
Объект TemplateField разрешает задавать шаблоны, содержащие разметку и элементы управления для настройки структуры и поведения столбца в элементе управления GridView. С помощью шаблона ItemTemplate можно указать структуру, которая должна использоваться, когда GridView отображает данные в столбце. Чтобы задать настраиваемую структуру для редактирования данных в столбце пользователями, можно создать EditItemTemplate.
Шаблон может содержать разметку, серверные веб-элементы управления и кнопки команд.
В шаблоне можно привязать элементы управления к данным с помощью методов Eval и Bind. Метод Eval используется, когда элемент управления будет только отображать значения. Метод Bind используется, когда пользователи могут изменять значения данных, т. е. для сценариев обновления данных. Можно использовать метод Eval в любом из шаблонов для отображения данных. Метод Bind используется в шаблоне с элементами управления, в которых пользователи могут изменять значения, например в элементах управления TextBox и CheckBox, или в шаблоне, позволяющем удаление записи.
В следующем примере показана коллекция Columns. Эта коллекция содержит объект TemplateField, который в свою очередь содержит объект ItemTemplate. Для отображения даты в объект ItemTemplate включен элемент управления Label, использующий метод Eval. Для редактирования даты остальные шаблоны используют элемент управления Calendar, который в свою очередь использует метод Bind.
<Columns> <asp:BoundField DataField="EmployeeID" HeaderText="Employee ID" ReadOnly="true"/> <asp:BoundField DataField="FirstName" HeaderText="First Name"/> <asp:BoundField DataField="LastName" HeaderText="Last Name"/> <asp:TemplateField HeaderText="Birth Date"> <ItemTemplate> <asp:Label ID="BirthDateLabel" Runat="Server" Text='<%# Eval("BirthDate", "{0:d}") %>' /> </ItemTemplate> <EditItemTemplate> <asp:Calendar ID="EditBirthDateCalendar" Runat="Server" VisibleDate='<%# Eval("BirthDate") %>' SelectedDate='<%# Bind("BirthDate") %>' /> </EditItemTemplate> </asp:TemplateField> <asp:HyperLinkField Text="Show Detail" DataNavigateUrlFormatString="~/ShowEmployeeDetail.aspx?EmployeeID={0}" DataNavigateUrlFields="EmployeeID" /> </Columns>

2.4.1.5. Сортировка

Элемент управления GridView поддерживает сортировку по одиночному столбцу без создания дополнительного кода. Функциональность сортировки элемента управления GridView можно расширить, используя событие сортировки и задавая выражение сортировки. Элемент управления GridView не выполняет собственную сортировку столбцов, а использует элемент управления источником данных для выполнения сортировки. Элемент управления обеспечивает пользовательский интерфейс сортировки, такой как элементы управления LinkButton, отображаемые в верхней части каждого столбца сетки. Однако элемент управления GridView использует функции сортировки данных элемента управления источника данных, к которому он привязан. Если связанный элемент управления источником данных может использоваться для сортировки данных, то элемент управления GridView может взаимодействовать с элементом управления источником данных и запрашивать сортированные данные, передавая SortExpression источнику данных при выборе данных. Не все элементы управления источником данных поддерживают функцию сортировки (например, элемент управления XmlDataSource ее не поддерживает). Однако если элемент управления источником данных поддерживает сортировку, GridView может ее использовать. 2.4.1.5.1. Процесс сортировки GridView Можно включить сортировку по умолчанию в элементе управления GridView, присвоив его свойству AllowSorting значение true. При присвоении этому свойству значения true элемент управления GridView отображает элемент управления LinkButton в заголовках столбца. Элемент управления также неявно присваивает свойству SortExpression каждого столбца имя поля данных, к которому он привязан. Например, если таблица содержит столбец, отображающий столбец City таблицы Employees, свойству SortExpression этого столбца присваивается значение City.
Во время выполнения пользователи могут щелкать элемент управления LinkButton в заголовке столбца для сортировки по этому столбцу. При щелчке по этой ссылке страница выполняет обратную передачу и создает событие Sorting элемента управления GridView. Выражение сортировки передается как часть аргумента события. По умолчанию для события Sorting элемент управления GridView передает выражение сортировки элементу управления источником данных. После выполнения запроса создается событие Sorted. Это событие позволяет выполнять действия, следующие после запроса (например, отобразить сообщение о состоянии). И, наконец, элемент управления источником данных повторно выполняет привязку элемента управления GridView к результатам повторно сортированного запроса. Элемент управления GridView не выполняет проверку того, поддерживает ли элемент управления источником данных сортировку. Он всегда передает выражение сортировки источнику данных. Если элемент управления источником данных не поддерживает сортировку и операция сортировки выполняется в элементе управления GridView, элемент управления GridView создает исключение NotSupportedException. Можно перехватить это исключение в обработчике для события Sorting и определить, поддерживает ли источник данных сортировку или для нее надо использовать собственную логику сортировки. Задание свойства AllowSorting сетки позволяет сортировать столбцы по умолчанию. Можно отключить сортировку для отдельных полей (например, для поля BoundField или TemplateField ), указав в качестве значения свойства SortExpression отдельного столбца пустую строку ( "" ).
Если сортировка по умолчанию не соответствует требованиям, можно настроить процедуру пользовательской сортировки. Для выполнения пользовательской сортировки обычно обрабатывают событие Sorting. В обработчике можно выполнить следующую процедуру:
  • Настройка выражения сортировки, передаваемое элементу управления источником данных. По умолчанию выражение сортировки – это имя отдельного столбца. Можно изменить выражение сортировки в обработчике событий. Например, чтобы выполнить сортировку по двум столбцам, можно создать выражение сортировки, содержащее оба столбца. Затем можно передать измененное выражение сортировки элементу управления источником данных.
  • Создание собственной логики сортировки. Например, при работе с источником данных, не поддерживающим сортировку, можно выполнить сортировку и помощью собственного кода, а затем привязать к компоненту отсортированные данные.

2.4.1.6. Разбиение по страницам

Элемент управления GridView обладает базовой функциональностью разбиения по страницам. Функциональность разбиения по страницам элемента управления GridView можно расширить с помощью свойства PagerTemplate элемента управления GridView.

2.4.1.7. События

GridView Функциональность элемента управления GridView можно расширять с помощью обработчиков событий. Элемент управления GridView предоставляет события, происходящие перед операциями перехода и изменения и после них. Рассмотрим некоторые события элемента управления GridView.
  • RowCommand – происходит при нажатии кнопки в элементе управления GridView. Данное событие часто используется для выполнения задачи при нажатии кнопки в элементе управления.
  • PageIndexChanging – происходит при нажатии кнопки страничного навигатора, но перед тем, как элемент управления GridView выполнит операцию разбиения по страницам. Это событие часто используется для отмены операции разбиения по страницам.
  • PageIndexChanged – происходит при нажатии кнопки страничного навигатора, но после того, как элемент управления GridView выполнит операцию разбиения по страницам. Данное событие обычно обрабатывается при необходимости выполнения задачи после перехода пользователя на другую страницу в элементе управления.
  • SelectedIndexChanging – происходит при нажатии кнопки строки Select (кнопка, для которой свойство CommandName имеет значение "Select" ) в элементе управления GridView, но прежде, чем элемент управления GridView выполнит операцию выбора. Данное событие часто обрабатывается для отмены операции выбора.
  • SelectedIndexChanged – происходит при нажатии кнопки строки Select в элементе управления GridView, но после того, как элемент управления GridView выполнит операцию выбора. Данное событие часто обрабатывается для выполнения задачи после выбора строки в элементе управления.
  • RowDeleting – происходит при нажатии кнопки строки Delete (кнопка, для которой свойство CommandName имеет значение "Delete" ) в элементе управления GridView, но прежде, чем элемент управления GridView удалит запись из источника данных. Данное событие часто обрабатывается для отмены операции удаления.
  • RowDeleted – происходит при нажатии кнопки строки Delete в элементе управления GridView, но после того, как элемент управления GridView удалит запись из источника данных. Это событие часто используется для проверки результатов операции удаления.
  • RowEditing – происходит при нажатии кнопки строки Edit (кнопка, для которой свойство CommandName имеет значение "Edit" ) в элементе управления GridView, но прежде, чем элемент управления GridView выполнит переключение в режим редактирования. Данное событие часто обрабатывается для отмены операции редактирования.
  • DataBound – это событие наследуется от элемента управления BaseDataBoundControl и происходит после завершения операции привязки к источнику данных, выполняемой элементом управления GridView.
Дополнительная литература :
обложка книги
Книгу можно скачать на этом сайте:
avidreaders.ru
3 МОДУЛЬ

Оптимизация
web-приложений. 

ТЕМА 1. Функции, определяемые пользователем

Для чего нужны функции? Чтобы ответить на этот вопрос, нужно понять, что вообще представляют собой функции. В программировании, как и в математике, функция есть отображение множества ее аргументов на множество ее значений. То есть функция для каждого набора значений аргумента возвращает какие-то значения, являющиеся результатом ее работы. Зачем нужны функции, попытаемся объяснить на примере. Классический пример функции в программировании – это функция, вычисляющая значение факториала числа. То есть мы задаем ей число, а она возвращает нам его факториал. При этом не нужно для каждого числа, факториал которого мы хотим получить, повторять один и тот же код – достаточно просто вызвать функцию с аргументом, равным этому числу.
Функция вычисления факториала натурального числа
<?php function fact($n){ if ($n==0) return 1; else return $fact = $n * fact($n-1); } echo fact(3);
// можно было бы написать echo (3*2);
// но если число большое, echo fact(50);
// то удобнее пользоваться функцией,
// чем писать echo (50*49*48*...*3*2); ?>
Таким образом, когда мы осуществляем действия, в которых прослеживается зависимость от каких-то данных, и при этом, возможно, нам понадобится выполнять такие же действия, но с другими исходными данными, удобно использовать механизм функций – оформить блок действий в виде тела функции, а меняющиеся данные – в качестве ее параметров.
Посмотрим, как в общем виде выглядит задание (объявление) функции. Функция может быть определена с помощью следующего синтаксиса: function Имя_функции (параметр1, параметр2, ... параметрN)
{ Блок_действий return "значение, возвращаемое функцией"; }

Если прямо так написать в php-программе, то работать ничего не будет. Во-первых, Имя_функции и имена параметров функции ( параметр1, параметр2 и т.д.) должны соответствовать правилам наименования в PHP (и русских символов в них лучше не использовать). Имена функций нечувствительны к регистру. Во-вторых, параметры функции – это переменные языка, поэтому перед названием каждого из них должен стоять знак $. Никаких многоточий ставить в списке параметров нельзя. В-третьих, вместо слов блок_действий в теле функции должен находиться любой правильный PHP-код (не обязательно зависящий от параметров). И наконец, после ключевого слова return должно идти корректное php-выражение (что-либо, что имеет значение). Кроме того, у функции может и не быть параметров, как и возвращаемого значения. Пример правильного объявления функции – функция вычисления факториала, приведенная выше.

Как происходит вызов функции? Указывается имя функции и в круглых скобках список значений ее параметров, если таковые имеются:
<?php Имя_функции ("значение_для_параметра1", "значение_для_параметра2",...);
// пример вызова функции – вызов функции
// вычисления факториала приведен выше,
// там для вычисления факториала числа 3
// мы писали: fact(3);
// где fact – имя вызываемой функции,
// а 3 – значение ее параметра с именем $n ?>

Когда можно вызывать функцию? Казалось бы, странный вопрос. Функцию можно вызвать после ее определения, т.е. в любой строке программы ниже блока function f_name(){...}. В PHP3 это было действительно так. Но уже в PHP4 такого требования нет. Все дело в том, как интерпретатор обрабатывает получаемый код. Единственное исключение составляют функции, определяемые условно (внутри условных операторов или других функций). Когда функция определяется таким образом, ее определение должно предшествовать ее вызову.
<?php $make = true;
/* здесь нельзя вызвать Make_event(); потому что она еще не существует, но можно вызвать Save_info() */ Save_info("Вася","Иванов", "Я выбрал курс по PHP"); if ($make){ // определение функции Make_event() function Make_event(){ echo "<p>Хочу изучать Python<br>"; } }
// теперь можно вызывать Make_event() Make_event();
// определение функции Save_info function Save_info($first, $last, $message)
{ echo "<br>$message<br>"; echo "Имя: ". $first . " ". $last . "<br>"; } Save_info("Федя","Федоров", "А я выбрал Lisp");
// Save_info можно вызывать и здесь ?>
Пример 5.1. Определение функции внутри условного оператора

Если функция однажды определена в программе, то переопределить или удалить ее позже нельзя. Несмотря на то, что имена функций нечувствительны к регистру, лучше вызывать функцию по тому же имени, каким она была задана в определении.
<?php
/* нельзя сохранить данные, т.е. вызвать функцию DataSave() до того, как выполнена проверка их правильности, т.е. вызвана функция DataCheck() */
DataCheck();
DataSave();
function DataCheck(){ // проверка правильности данных function DataSave(){ // сохраняем данные } } ?>
Пример 5.2. Определение функции внутри функции

Рассмотрим подробнее аргументы функций, их назначение и использование.

Аргументы функций

У каждой функции может быть, как мы уже говорили, список аргументов. С помощью этих аргументов в функцию передается различная информация (например, значение числа, факториал которого надо подсчитать). Каждый аргумент представляет собой переменную или константу.
С помощью аргументов данные в функцию можно передавать тремя различными способами. Это передача аргументов по значению (используется по умолчанию), по ссылке и задание значения аргументов по умолчанию. Рассмотрим эти способы подробнее.
Когда аргумент передается в функцию по значению, изменение значения аргумента внутри функции не влияет на его значение вне функции. Чтобы позволить функции изменять ее аргументы, их нужно передавать по ссылке. Для этого в определении функции перед именем аргумента следует написать знак амперсанд "&".
<?php
// напишем функцию, которая бы добавляла
// к строке слово checked function add_label(&$data_str){ $data_str .= "checked"; } $str = "<input type=radio name=article ";
// пусть имеется такая строка echo $str ."<br>";
// выведет элемент формы –
// не отмеченную радио кнопку
add_label($str);
// вызовем функцию echo $str ."><br>";
// это выведет уже отмеченную // радио кнопку ?>
Пример 5.3. Передача аргументов по ссылке

В функции можно определять значения аргументов, используемые по умолчанию. Само значение по умолчанию должно быть константным выражением, а не переменной и не представителем класса или вызовом другой функции.
У нас есть функция, создающая информационное сообщение, подпись к которому меняется в зависимости от значения переданного ей параметра. Если значение параметра не задано, то используется подпись "Оргкомитет.".
<?php function Message($sign="Оргкомитет."){
// здесь параметр sign имеет по умолчанию значение "Оргкомитет" echo "Следующее собрание состоится завтра.<br>"; echo $sign . "<br>"; } Message();
// вызываем функцию без параметра.
// В этом случае подпись – это Оргкомитет Message("С уважением, Вася.");
// В этом случае подпись
// будет "С уважением, Вася." ?>
Пример 5.4. Значения аргументов по умолчанию

Результатом работы этого скрипта будет:

Следующее собрание состоится завтра. Оргкомитет. Следующее собрание состоится завтра. С уважением, Вася.

Если у функции несколько параметров, то те аргументы, для которых задаются значения по умолчанию, должны быть записаны после всех остальных аргументов в определении функции. В противном случае появится ошибка, если эти аргументы будут опущены при вызове функции.
Например, мы хотим внести описание статьи в каталог. Пользователь должен ввести такие характеристики статьи, как ее название, автора и краткое описание. Если пользователь не вводит имя автора статьи, считаем, что это Иванов Иван.
<?php function Add_article($title, $description, $author="Иванов Иван"){ echo "Заносим в каталог статью: $title,"; echo "автор $author";
echo "<br>Краткое описание: "; echo "$description <br>"; } Add_article("Информатика и мы", "Это статья про информатику ...", "Петров Петр"); Add_article("Кто такие хакеры", "Это статья про хакеров ..."); ?>
В результате работы скрипта получим следующее
Заносим в каталог статью: Информатика и мы, автор Петров Петр. Краткое описание: Это статья про информатику...
Заносим в каталог статью: Кто такие хакеры, автор Иванов Иван. Краткое описание: Это статья про хакеров...


Если же мы напишем вот так:
<?php function Add_article($author="Иванов Иван", $title, $description){ // ...действия как в предыдущем примере } Add_article("Кто такие хакеры", "Это статья про хакеров..."); ?>
То в результате получим:
Warning: Missing argument 3 for add_article() in c:\users\nina\tasks\func\def_bad.php on line 2

Списки аргументов переменной длины

В PHP4 можно создавать функции с переменным числом аргументов. То есть мы создаем функцию, не зная заранее, со сколькими аргументами ее вызовут. Для написания такой функции никакого специального синтаксиса не требуется. Все делается с помощью встроенных функций func_num_args(), func_get_arg(), func_get_args().
Функция func_num_args() возвращает число аргументов, переданных в текущую функцию. Эта функция может использоваться только внутри определения пользовательской функции. Если она появится вне функции, то интерпретатор выдаст предупреждение.

<?php function DataCheck()
{ $n = func_num_args(); echo "Число аргументов функции $n"; } DataCheck();
// выведет строку
// "Число аргументов функции 0" DataCheck(1,2,3); // выведет строку // "Число аргументов функции 3" ?>
Пример 5.5. Использование функции func_num_args()

Функция func_get_arg (целое номер_аргумента ) возвращает аргумент из списка переданных в функцию аргументов, порядковый номер которого задан параметром номер_аргумента. Аргументы функции считаются начиная с нуля. Как и func_num_args(), эта функция может использоваться только внутри определения какой-либо функции. Номер_аргумента не может превышать число аргументов, переданных в функцию. Иначе будет сгенерировано предупреждение, и функция func_get_arg() возвратит False.
Создадим функцию для проверки типа данных ее аргументов. Считаем, что проверка прошла успешно, если первый аргумент функции – целое число, второй – строка.
<? function DataCheck()
{ $check = true; $n = func_num_args();
// число аргументов,
// переданных в функцию
/* проверяем, является ли первый переданный аргумент целым числом */
if ($n>=1) if (!is_int(func_get_arg(0))) $check = false; /* проверяем, является ли второй переданный аргумент строкой */
if ($n>=2) if (!is_string(func_get_arg(1))) $check = false; return $check; } if (DataCheck(123,"text")) echo "Проверка прошла успешно<br>";
else echo "Данные не удовлетворяют условиям<br>";
if (DataCheck(324)) echo "Проверка прошла успешно<br>";
else echo "Данные не удовлетворяют условиям<br>";
?>
Пример 5.6. Функция для проверки типа данных ее аргументов

Результатом работы будет следующее.
Проверка прошла успешно
Проверка прошла успешно

Функция func_get_args() возвращает массив, состоящий из списка аргументов, переданных функции. Каждый элемент массива соответствует аргументу, переданному функции. Если функция используется вне определения пользовательской функции, то генерируется предупреждение.
Перепишем предыдущий пример, используя эту функцию. Будем проверять, является ли целым числом каждый четный аргумент, передаваемый функции:
<?
function DataCheck(){ $check = true; $n = func_num_args();
// число аргументов,
// переданных в функцию $args = func_get_args();
// массив аргументов функции for ($i=0;$i<$n;$i++){ $v = $args[$i];
if ($i % 2 == 0){ if (!is_int($v)) $check = false;
// проверяем,
// является ли четный аргумент целым } } return $check; }
if (DataCheck("text", 324)) echo "Проверка прошла успешно<br>"; else echo "Данные не удовлетворяют условиям<br>"; ?>

Как видим, комбинации
функций func_num_args(), func_get_arg() и func_get_args() используется для того, чтобы функции могли иметь переменный список аргументов. Эти функции были добавлены только в PHP 4. В PHP3 для того, чтобы добиться подобного эффекта, можно использовать в качестве аргумента функции массив. Например, вот так можно написать скрипт, проверяющий, является ли каждый нечетный параметр функции целым числом:
<? function DataCheck($params)
{ $check =true; $n = count($params);
// число аргументов,
// переданных в функцию for ($i=0;$i<$n;$i++){ $v = $params[$i]; if ($i % 2 != 0){
// проверяем, является ли нечетный
// аргумент целым if (!is_int($v)) $check = false; } } return $check; }
if (DataCheck("text", 324)) echo "Проверка прошла успешно<br>"; else echo "Данные не удовлетворяют условиям<br>"; ?>

Использование переменных внутри функции
Глобальные переменные

Чтобы использовать внутри функции переменные, заданные вне ее, эти переменные нужно объявить как глобальные. Для этого в теле функции следует перечислить их имена после ключевого слова global:
global $var1, $var2; <? $a=1; function Test_g()
{ global $a; $a = $a*2; echo 'в результате работы функции $a=',$a; } echo 'вне функции $a=',$a,', '; Test_g(); echo "<br>";
echo 'вне функции $a=',$a,', '; Test_g(); ?>
Пример 5.7. Глобальные переменные
В результате работы этого скрипта получим:
вне функции $a=1, в результате работы функции $a=2 вне функции $a=2, в результате работы функции $a=4
Когда переменная объявляется как глобальная, фактически создается ссылка на глобальную переменную. Поэтому такая запись эквивалентна следующей
(массив $GLOBALS содержит все переменные, глобальные относительно текущей области видимости):
$var1 = &$GLOBALS["var1"];
$var2 = &$GLOBALS["var2"];

Это значит, например, что удаление переменной $var1 не удаляет глобальной переменной $GLOBALS["var1"].

Статические переменные

Чтобы использовать переменные только внутри функции, при этом сохраняя их значения и после выхода из функции, нужно объявить эти переменные как статические. Статические переменные видны только внутри функции и не теряют своего значения, если выполнение программы выходит за пределы функции. Объявление таких переменных производится с помощью ключевого слова static:
static $var1, $var2;
Статической переменной может быть присвоено любое значение, но не ссылка.
<? function Test_s(){ static $a = 1; // нельзя присваивать выражение или ссылку $a = $a*2; echo $a; } Test_s(); // выведет 2 echo $a; // ничего не выведет, так как // $a доступна только // внутри функции Test_s(); // внутри функции $a=2, поэтому // результатом работы функции // будет число 4 ?>
Пример 5.8. Использование статической переменной

Возвращаемые значения

Все функции, приведенные выше в качестве примеров, выполняли какие-либо действия. Кроме подобных действий, любая функция может возвращать как результат своей работы какое-нибудь значение. Это делается с помощью утверждения return. Возвращаемое значение может быть любого типа, включая списки и объекты. Когда интерпретатор встречает команду return в теле функции, он немедленно прекращает ее исполнение и переходит на ту строку, из которой была вызвана функция.
Например, составим функцию, которая возвращает возраст человека. Если человек не умер, то возраст считается относительно текущего года.
<?php /* если второй параметр вычисляется
как true, то он рассматривается как дата смерти, */ function Age($birth, $is_dead){ if ($is_dead) return $is_dead-$birth; else return date("Y")-$birth; } echo Age(1971, false); // для 2009 года выведет 38 echo Age(1971, 2001); // выведет 30 ?>
В этом примере можно было и не использовать функцию return, а просто заменить ее функцией вывода echo. Однако если мы все же делаем так, что функция возвращает какое-то значение (в данном случае возраст человека), то в программе мы можем присвоить любой переменной значение этой функции:
$an_age = Age(1981, 2004);
В результате работы функции может быть возвращено только одно значение. Несколько значений можно получить, если возвращать список значений (одномерный массив). Допустим, мы хотим получить полный возраст человека с точностью до дня.
<?php function Full_age($b_day, $b_month, $b_year) { $y = date("Y"); $m = intval(date("m")); $d = intval(date("d")); $b_month = intval($b_month); $b_day = intval($b_day); $b_year = intval($b_year); $day = ($b_day > $d ? 30 - $b_day + $d : $d - $b_day); $tmpMonth = ($b_day > $d ? -1 : 0); $month = ($b_month > $m + $tmpMonth ? 12 - $b_month + $tmpMonth + $m : $m+$tmpMonth - $b_month); $tmpYear = ($b_month > $m + $tmpMonth ? -1 : 0); if ($b_year > $y + $tmpYear) { $year = 0; $month = 0; $day = 0; } else { $year = $y + $tmpYear - $b_year; } return array ($day,$month,$year); } $age = Full_age("29","06","1986"); echo "Вам $age[2] лет, $age[1] месяцев и $age[0] дней"; ?>

Когда функция возвращает несколько значений для их обработки в программе, удобно использовать языковую конструкцию list (), которая позволяет одним действием присвоить значения сразу нескольким переменным. Например, в предыдущем примере, оставив без изменения функцию, обработать возвращаемые ей значения можно было так:
<? // задание функции Full_age() list($day,$month,$year) = Full_age("07", "08","1974"); echo "Вам $year лет, $month месяцев и $day дней"; ?>
Вообще конструкцию list () можно использовать для присвоения переменным значений элементов любого массива.
<? $arr = array("first","second"); list($a,$b) = $arr; // переменной $a присваивается первое // значение массива, $b – второе echo $a," ",$b; // выведет строку "first second" ?>
Пример 5.9. Использование list()

Возвращение ссылки

В результате своей работы функция также может возвращать ссылку на какую-либо переменную. Это может пригодиться, если требуется использовать функцию для того, чтобы определить, какой переменной должна быть присвоена ссылка. Чтобы получить из функции ссылку, нужно при объявлении перед ее именем написать знак амперсанд ( & ) и каждый раз при вызове функции перед ее именем тоже писать амперсанд ( & ). Обычно функция возвращает ссылку на какую-либо глобальную переменную (или ее часть – ссылку на элемент глобального массива), ссылку на статическую переменную (или ее часть) или ссылку на один из аргументов, если он был также передан по ссылке.
<? $a = 3; $b = 2; function & ref($par){ global $a, $b; if ($par % 2 == 0) return $b; else return $a; } $var =& ref(4); echo $var, " и ", $b,"<br>"; //выведет 2 и 2 $b = 10; echo $var, " и ", $b,"<br>"; // выведет 10 и 10 ?> Пример 5.10. Возвращение ссылки

При использовании синтаксиса ссылок в переменную $var нашего примера не копируется значение переменной $b возвращенной функцией $ref, а создается ссылка на эту переменную. То есть теперь переменные $var и $b идентичны и будут изменяться одновременно.

Переменные функции

PHP поддерживает концепцию переменных функций. Это значит, что если имя переменной заканчивается круглыми скобками, то PHP ищет функцию с таким же именем значения и пытается ее выполнить.
<? /* создадим две простые функции: Add_sign – добавляет подпись к строке и Show_text – выводит строку текста */ function Add_sign($string, $sign="С уважением, Петр"){ echo $string ." ".$sign; } function Show_text(){ echo "Отправить сообщение по почте<br>"; } $func = "Show_text"; // создаем переменную со значением, // равным имени функции Show_text $func(); // это вызовет функцию Show_text $func = "Add_sign"; // создаем переменную со значением, // равным имени функции Add_sign $func("Привет всем <br>"); // это вызовет функцию // Add_sign с параметром "Привет всем" ?>
Пример 5.11. Использование переменных функций

В этом примере функция Show_text просто выводит строку текста. Казалось бы, зачем для этого создавать отдельную функцию, если существует специальная функция echo(). Дело в том, что такие функции, как echo(), print(), unset(), include() и т.п. нельзя использовать в качестве переменных функций. То есть если мы напишем:
<? $func = "echo "; $func("TEXT"); ?>
то интерпретатор выведет ошибку:
Fatal error: Call to undefined function: echo() in c:\users\nina\tasks\func\var_f.php on line 2
Поэтому для того, чтобы использовать любую из перечисленных выше функций как переменную функцию, нужно создать собственную функцию, что мы и сделали в предыдущем примере.

Внутренние (встроенные) функции

Говоря о функциях, определяемых пользователем, все же нельзя не сказать пару слов о встроенных функциях. С некоторыми из встроенных функций, такими как echo(), print(), date(), include(), мы уже познакомились. На самом деле все перечисленные функции, кроме date(), являются языковыми конструкциями. Они входят в ядро PHP и не требуют никаких дополнительных настроек и модулей. Функция date() тоже входит в состав ядра PHP и не требует настроек. Но есть и функции, для работы с которыми нужно установить различные библиотеки и подключить соответствующий модуль. Например, для использования функций работы с базой данных MySql следует скомпилировать PHP с поддержкой этого расширения. В последнее время наиболее распространенные расширения и соответственно их функции изначально включают в состав PHP так, чтобы с ними можно работать без каких бы то ни было дополнительных настроек интерпретатора.

Решение задачи

Напомним, в чем состоит задача. Мы хотим написать интерфейс, который позволял бы создавать html-формы. Пользователь выбирает, какие элементы и в каком количестве нужно создать, придумывает им названия, а наша программа сама генерирует требуемую форму. Разобьем задачу на несколько подзадач: выбор типов элементов ввода и их количества, создание названий элементов ввода и обработка полученных данных, т.е. непосредственно генерация формы. Первая задача достаточно проста: нужно написать соответствующую форму, например подобную приведенной ниже ():
<form action="ask_names.php">
Создать элемент "строка ввода текста": <input type=checkbox name=types[] value=string><br>
Количество элементов: <input type=text name=numbers[string] size=3><br> <br>
Создать элемент "текстовая область": <input type=checkbox name=types[] value=text><br>
Количество элементов: <input type=text name=numbers[text] size=3><br> <input type=submit value="Создать"> </form>
Листинг 5.12. task_form.html
Когда мы пишем в имени элемента формы, например types[], это значит, что его имя – следующий элемент массива types. То есть у нас первый элемент формы ( "строка ввода текста" )
будет иметь имя types[0], а второй (текстовая область) – types[1]. В браузере task_form.html будет выглядеть примерно так:
таблица
Рис. 5.1. Форма для выбора создаваемых элементов и их количества

После отправки данных этой формы мы получим информацию о том, какие элементы и сколько элементов каждого типа нужно создать. Следующий скрипт запрашивает названия для этих элементов:
<? $file = "task.php";
/* файл, который будет обрабатывать сгенерированную этим скриптом форму */ function Ask_names(){
// функция генерирует форму для
// ввода названий элементов ввода global $file;
//объявляем, что хотим использовать эту
// переменную, заданную вне функции if (isset($_GET["types"])){ $st = '<form action="'.$file.'">'; foreach ($_GET["types"] as $k => $type){ /* перебираем все типы элементов, которые нужно создать */
$num = $_GET["numbers"][$type];
// сколько элементов каждого типа нужно for ($i=1;$i<=$num;$i++){
// создаем $num строк для ввода $st.= "Введите имя $i-го элемента типа $type: "; $st.= "<input type=text name=names[$type][]><br>"; }
// сохраняем тип и число необходимых
// элементов ввода этого типа
$st.= "<input type=hidden name=types[] value=$type>";
$st.= "<input type=hidden name=numbers[] value=$num><br>"; }
$st .= "<input type=submit name=send value=send></form>"; return $st; // в переменной $st содержится код формы // для запроса имен
} else echo "Select type"; } echo Ask_names();
// вызываем функцию и выводим
// результаты ее работы ?>
Листинг 5.13. ask_names.php
Допустим, нужно создать два элемента типа "текстовая строка" и один элемент типа "текстовая область", как и отмечено в форме выше. Тогда скрипт ask_names.php обработает ее таким образом, что мы получим такую форму:
таблица
Рис. 5.2. Форма для ввода названий создаваемых элементов

Введем в эту форму, например, строки "Название", "Автор" и "Краткое содержание". Эти данные будет обрабатывать скрипт task.php.
<? $show_file = "task_show.php";
/* файл, который будет обрабатывать данные созданной этим файлом формы */
function Create_element($type,$name){
// функция создает элемент ввода
// по типу и названию $str=""; switch($type){ case "string":
$str .= "$name: <input type=text name=string[]><br>"; break; case "text": $str .= "$name: <textarea name=text[]></textarea><br>"; break; } return $str; } function Create_form(){
// функция создает форму
// с нужными элементами global $show_file; $str = '<form action="'.$show_file.'">'; foreach ($_GET["types"] as $k => $type){
// перебираем типы элементов $num = $_GET["numbers"][$k];
// число элементов этого типа for ($i=1;$i<=$num;$i++){ $arr = $_GET["names"][$type][$i-1];
// имя создаваемого элемента $str .= Create_element($type,$arr);
// вызываем функцию для
// создания элемента } } $str .= "<input type=submit value=send></form>"; echo $str; } $crt = "Create_form"; $crt();
// вызываем функцию создания
// формы Create_form ?>
Листинг 5.14. task.php
Результатом работы этого скрипта с входными данными, приведенными выше, будет следующая форма:
таблица
Рис. 5.3. Пример формы, сгенерированной нашей программой

Заключение

Подведем итоги. В этой лекции мы изучили функции, определяемые пользователем, их синтаксис и семантику, способы передачи их аргументов и возвращаемых значений. Кроме того, обсуждались способы задания и работы с функциями, имеющими переменное число аргументов и альтернативный способ вызова функции (с помощью переменной, значение которой есть имя функции). В следующей лекции будет рассмотрена объектная модель языка PHP.

Классы и объекты

Начнем с основных понятий объектно-ориентированного программирования – класса и объекта. Существует множество определений этих понятий. Мы дадим следующее: объект – это структурированная переменная, содержащая всю информацию о некотором физическом предмете или реализуемом в программе понятии, класс – это описание таких объектов и действий, которые можно с ними выполнять.
В PHP класс определяется с помощью следующего синтаксиса:
class Имя_класса
{ var $имя_свойства; /*список свойств*/ function имя_метода( ){ /* определение метода */ } /*список методов*/ }
Имена свойств объектов класса объявляются с помощью ключевого слова var, методы, применимые к объектам данного класса, описываются функциями. Внутри определения класса можно использовать ключевое слово this для обращения к текущему представителю класса.
Например, нам нужно создать класс, описывающий категорию статей. У каждой статьи имеются такие свойства, как название, автор и краткое содержание. Какие действия мы хотим совершать со статьями? Возможно, нам понадобится задавать значения перечисленным свойствам статьи, отображать статью в браузере. Тогда определение этого класса может выглядеть следующим образом:
<? class Articles { // Создаем класс Статей var $title; var $author; var $description; // метод, который присваивает значения // атрибутам класса function make_article($t, $a, $d){ $this->title = $t; $this->author = $a; $this->description = $d; } //метод для отображения экземпляров класса function show_article(){ $art = $this->title . "<br>" . $this->description . "<br>Автор: " . $this->author; echo $art; } } ?>

Итак, для описания физических объектов типа "статья" мы создали класс с именем Articles, состоящий из трех переменных, содержащих характеристики статьи, и двух функций для создания конкретной статьи и для ее отображения.
Как известно, работая с PHP, можно периодически переключаться в режим HTML. В этом случае программа состоит из нескольких кусков (блоков) кода. Определение класса нельзя разносить по разным блокам php-кода и тем более по разным файлам. То есть если написать: <?php
class Articles { // Начало описания класса var $title; ?> <?php // продолжение описания класса function show_article(){ // содержание метода } } // конец описания класса ?>
то программа не будет работать корректно.
Несколько замечаний по поводу имен классов. Имя класса должно удовлетворять правилам именования объектов в языке PHP, но есть ряд имен, которые зарезервированы разработчиками для своих целей. В первую очередь это имена, начинающиеся с символа подчеркивания "_". Для создания классов и функций нельзя использовать такие имена. Кроме того, зарезервировано имя stdClass, поскольку оно используется внутри движка PHP.

Инициализация переменных

Часто некоторым атрибутам класса бывает необходимо присваивать значения сразу после создания представителя класса. Когда мы создавали класс статей, для присваивания значений атрибутам ( свойствам ) класса мы использовали специальную функцию make_article(). Вообще говоря, мы поступили не совсем верно, потому что занялись изобретением велосипеда. Специально для задания начальных значений атрибутам класса существует два стандартных метода. В PHP4 можно инициализировать значения с помощью оператора var или с помощью функции конструктора. С помощью var можно инициализировать только константные значения. Для задания не константных значений используют функцию конструктор, которая вызывается автоматически, когда объект конструируется из класса. Функция- конструктор должна иметь имя, совпадающее с именем всего класса, в котором она определена.
Приведем пример. Допустим, при создании объекта "статья" мы хотим установить его свойства следующим образом: автора – равным строке "Иванов", название и краткое содержание – соответствующим элементам глобального массива $_POST, а дату публикации статьи – текущей дате. Тогда следующее описание класса не является корректным в PHP4:
<? class Articles { // Создаем класс Статей var $title= $_POST["title"]; var $author = "Иванов"; var $description = $_POST["description"]; var $published = date("Y-m-d"); // метод, который присваивает значения // атрибутам класса } ?>
А вот такое описание класса в PHP4 будет работать так, как нужно:
<? class Articles { // Создаем класс Статей var $title; var $author = "Иванов"; var $description; var $published; // метод, который присваивает значения // атрибутам класса function Articles(){ $this->title = $_POST["title"]; $this->description = $_POST["description"]; $this ->published = date("Y-m-d"); } //метод для отображения экземпляров класса function show_article(){ $art = $this->title . "<br>" . $this->description . "<br>Автор: " . $this->author; echo $art; } } ?>

Отметим, что в PHP3 и PHP4 конструкторы работают по-разному. В PHP3 функция становилась конструктором, если она имела то же имя, что и класс, а в PHP4 – если она имеет то же имя, что и класс, в котором она определена. Разница в подходах видна, когда один класс расширяет другой и происходит наследование свойств и методов базового класса. Но об этом мы поговорим чуть позже. В PHP5 конструктор класса именуется __construct. Кроме того, в PHP5 появились и деструкторы – функции, которые вызываются автоматически перед уничтожением объекта. В PHP5 функция-деструктор должна быть названа __destruct.
ТЕМА 2. Объекты

В одной из первых лекций мы упоминали о существовании в PHP такого типа данных, как объект. Класс – это описание данных одного типа, данных типа объект. Классы являются как бы шаблонами для реальных переменных. Переменная нужного типа создается из класса с помощью оператора new. Создав объект, мы можем применять к нему все методы и получать все свойства, определенные в описании класса .
Для этого используют такой синтаксис:
$имя_объекта->название_свойства или $имя_объекта->название_метода(список аргументов). Заметим, что перед названием свойства или метода знак $ не ставят.
<?php $art = new Articles; // создаем объект $art echo ($art ->title); // выводим название объекта $art $another_art = new Articles; // создаем объект $another_art $another_art->show_article(); // вызываем метод для
// отображения объекта в браузер ?>
Пример 6.1. Доступ к методам и свойствам объекта

Каждый из объектов класса имеет одни и те же свойства и методы. Так, у объекта $art и у объекта $another_art есть свойства title, description, author и методы Articles(), show_article(). Но это два разных объекта. Представим себе объект как директорию в файловой системе, а его характеристики – как файлы в этой директории. Очевидно, что в каждой директории могут лежать одинаковые файлы, но тем не менее они считаются различными, поскольку хранятся в разных директориях. Точно так же свойства и методы считаются различными, если они применяются к разным объектам. Чтобы получить нужный файл из директории верхнего уровня, мы пишем полный путь к этому файлу. При работе с классами нужно указывать полное имя функции, которую мы хотим вызвать. Директорией верхнего уровня в PHP будет пространство глобальных переменных, а путь указывается с помощью разделителя ->. Таким образом, имена $art->title и $another_art->title обозначают две разные переменные. Переменная в PHP имеет только один знак доллара перед именем, поэтому нельзя писать $art->$title. Эта конструкция будет рассмотрена не как обращение к свойству title объекта $art, а как обращение к свойству, имя которого задано переменной $title (например, $art->"" ).
<?php $art->title = "Введение в Internet"; // так можно установить // значение свойства объекта $art->$title = "Введение в Internet"; // так нельзя установить // значение свойства объекта $property = "title"; $art->$property = "Введение в Internet"; // так можно установить значение // свойства объекта ?>
Пример 6.2. Установка значений свойств

Создавая класс, мы не можем знать, какое имя будет иметь объект этого класса, тем более что объектов может быть много и все могут иметь разные имена. Соответственно мы не знаем, как обращаться к объекту внутри определения класса. Для того чтобы иметь доступ к функциям и переменным внутри определения класса, нужно использовать псевдопеременную $this. Например, $this->title возвращает значение свойства title у текущего объекта данного класса. Иногда эту переменную предлагают читать как "мое собственное" (к примеру, по отношению к свойству ).

Наследование
extends

Механизм наследования – очень важная часть всего объектно-ориентированного подхода. Попытаемся объяснить его суть на примере. Допустим, мы создаем описание человека. Очевидно, что сделать это мы можем по-разному, в зависимости от того, для чего нужно это описание. Можно описать человека как программиста: он знает такие-то языки программирования, операционные системы, участвовал в стольких-то проектах. Однако если человек программист, то он не перестает быть человеком вообще, т.е. он имеет имя, фамилию, место жительства и т.п. Если перевести наши рассуждения в термины
объектно-ориентированного программирования, то можно сказать, что мы описали два класса – класс людей и класс программистов, каждый со своими свойствами и методами. Причем класс программистов, очевидно, обладает всеми свойствами класса людей и при этом имеет свои специфические характеристики, т.е. класс программистов является подклассом класса людей. Так, если у человека вообще есть имя, то у программиста оно тоже должно быть, но не наоборот. Кроме программистов можно выделить еще множество классов по профессиональной принадлежности людей. И все они будут подклассами класса людей. Часто на практике удобно определять общий класс, который может использоваться сразу в нескольких проектах (например, класс людей или личностей), и адаптировать его для специфических нужд каждого проекта (например, как класс программистов). Как это можно реализовать? С помощью механизма расширений. Любой класс может быть расширением другого класса. Расширяющий (или производный) класс, кроме тех свойств и методов, которые описаны в его определении, имеет все функции и свойства основного ( базового класса ). В нашем примере класс программистов – расширяющий, а класс всех людей – базовый. Из класса нельзя удалить никакие существующие свойства и функции, класс можно только расширить. Расширяющий класс в PHP4 всегда зависит только от одного базового класса, поскольку множественное наследование в PHP не поддерживается. Расширяются классы в PHP с помощью ключевого слова extends.
<?php class Person { // определяем класс Личности var $first_name; // имя личности var $last_name; // фамилия личности function make_person($t,$a){ // метод устанавливает // значения имени и фамилии объекта $this->first_name = $t; $this->last_name = $a; } function show_person(){ // метод отображает информацию о личности echo ("<h2>" . $this->first_name . " " . $this->last_name . "</h2>"); } } class Programmer extends Person{ // определяем класс // Programmer, расширяющий Person var $langs = array ("Lisp"); // константным массивом // задать переменную в var можно function set_lang($new_lang){ // метод добавляет еще // один язык к списку известных $this->langs[] = $new_lang; } } ?>
Пример 6.3. Использование механизма наследования

Класс Programmer имеет те же переменные и функции, что и класс Person, плюс переменную $langs, в которой содержится список изученных программистом языков, и функцию set_lang для добавления еще одного языка к списку изученных. Создать представителя класса программистов можно обычным способом с помощью конструкции new. После этого можно устанавливать и получать список языков, которые знает программист, и в то же время можно использовать функции, заданные для класса Person, т.е. устанавливать и получать имя и фамилию программиста и отображать сведения о нем в браузере:
<?php $progr = new Programmer; $progr->set_lang("PHP"); // методы, определенные для // класса Programmer print_r ($progr->langs); // методы, определенные для класса Person $progr->make_person("Bill","Gates"); $progr->show_person(); ?>
Отношения, в которых состоят созданные нами классы Person и Programmer, называют также отношениями родитель–потомок. Класс Person – родитель, а его потомки, такие как класс Programmer, создаются, основываясь на нем, с помощью расширений. Любой класс может стать родительским и соответственно породить потомков. Порядок определения классов имеет значение. Нельзя сначала определить класс Programmer, расширяющий класс Person, а уже потом сам класс Person. Класс должен быть определен перед тем, как он будет использоваться (расширяться).

Конструкторы

Теперь, после знакомства с механизмом наследования в PHP, мы можем прокомментировать различие между конструкторами PHP4 и PHP3 и более подробно рассказать о конструкторах вообще. Напомним, что в PHP3 конструктор – это функция, имя которой совпадает с именем класса. А в PHP4 – функция, имя которой совпадает с именем класса, в котором она определена.
<?php class Programmer extends Person{ // определяем класс // Programmer, расширяющий Person var $langs = array ("Lisp"); function Programmer(){ // этот конструктор будет // работать и в PHP3, и в PHP4 $this->make_person("Иван","Петров"); } } ?>
Пример 6.4. Использование конструктора

Здесь функция Programmer() является конструктором, т.е. выполняется сразу после создания любого представителя класса Programmer, задавая ему имя "Иван" и фамилию "Петров". Конструкторы, как и любые другие функции, могут иметь аргументы. В этом случае, создавая представителя класса, нужно указать значения этих параметров. Аргументы конструктора могут иметь и значения по умолчанию. Если все аргументы имеют значения по умолчанию, тогда можно создавать экземпляр класса без параметров.
<?php class Programmer extends Person{ // определяем класс // Programmer, расширяющий Person var $langs = array ("Lisp"); function Programmer($n = "Иван", $f = "Петров"){ // это конструктор $this->make_person($n,$f); } } $default_progr = new Programmer(); // создаст программиста Ивана Петрова $new_progr = new Programmer("Вася", "Сидоров"); // создаст программиста Васю Сидорова print_r($new_progr); /* выведет информацию о переменной $new_progr, т.е. свойства объекта и их значения */ ?>
Пример 6.5. Использование конструктора

Приведенные примеры будут работать и в PHP3, и в PHP4, конечно если дописать в них определение базового класса Person. Допустим, ситуация немного другая: конструктор имеется только у базового класса Person:
<?php class Person { // определяем класс Личности var $first_name; var $last_name; function Person($t,$a){ // конструктор $this->first_name = $t; $this->last_name = $a; } /* ... */ } class Programmer extends Person{ // определяем класс // Programmer, расширяющий Person var $langs = array ("Lisp"); function set_lang($new_lang){ $this->langs[] = $new_lang; } }
$new_progr = new Programmer("Вася", "Сидоров"); ?>
Что произойдет в этом случае при создании объекта класса Programmer, будет ли автоматически вызвана какая-либо функция? В PHP3 ничего не произойдет, поскольку в этом классе нет функции с именем Programmer() (здесь конструктор – это функция, имя которой совпадает с именем класса ). В PHP4 будет вызван конструктор базового класса, если он существует, т.е. вызовется функция Person() из класса Person (здесь конструктор – функция, имя которой совпадает с именем класса, в котором она определена).
Еще одна ситуация – в базовом классе есть функция, имя которой совпадает с именем расширяющего класса, а в расширяющем классе нет конструктора.
<?php class Person { // определяем класс Личности var $first_name; var $last_name; function Person($t,$a){ // конструктор $this->first_name = $t; $this->last_name = $a; } function Programmer($new_lang){ echo "Я – программист"; } } class Programmer extends Person{ // определяем класс // Programmer, расширяющий Person var $langs = array ("Lisp"); function set_lang($new_lang){ $this->langs[] = $new_lang; } } $new_progr = new Programmer("Вася", "Сидоров"); ?>
В этом случае PHP3 вызовет в качестве конструктора функцию Programmer() из описания класса Person. Поскольку конструктор – это функция, у которой то же имя, что и у класса. И неважно, определена ли эта функция в самом классе или она наследуется из базового класса. В PHP4 класс Programmer не будет иметь своего конструктора, поэтому вызовется конструктор базового класса.
Ни в PHP 3, ни в PHP 4 конструктор базового класса не вызывается автоматически из конструктора порожденного класса.

Оператор ::

Иногда внутри описания класса возникает необходимость сослаться на функции или переменные из базового класса. Бывает, что нужно ссылаться на функции в классе, ни
один представитель которого еще не создан. Как быть в таком случае? В PHP4 для этого существует специальный оператор "::"

Например, вот так можно вызвать в описании класса Programmer функцию show_name() из базового класса Person и функцию say_hello(), заданную в описании класса Programmer, когда ни один объект этого класса еще не был создан:
<?php class Person { // определяем класс Личности var $first_name; var $last_name; function Person($t,$a){ // конструктор $this->first_name = $t; $this->last_name = $a; } function show_name(){ // метод отображает информацию о личности echo ("Меня зовут, " . $this->first_name . " " . $this->last_name . "!<br>"); } } class Programmer extends Person{ // определяем класс // Programmer, расширяющий Person function set_lang($new_lang){ // метод добавляет еще // один язык к списку известных $this->langs[] = $new_lang; Person::show_name(); // вызываем функцию из базового класса echo "И я знаю теперь еще и " . $new_lang; } function show_name(){ echo ("Я программист, " . $this->first_name . " " . $this->last_name . "!<br>"); } function say_hello(){ echo "Привет!<br>"; } } Programmer::say_hello(); // вызываем функцию, когда ни // один объект ее класса еще не создан $new_progr = new Programmer("Вася","Сидоров"); $new_progr->set_lang("PHP"); ?>

В результате работы этой программы получим следующее:

Привет! Меня зовут Вася Сидоров!
И я знаю теперь еще и PHP

С помощью команды Programmer::say_hello(); мы вызываем функцию say_hello класса Programmer как таковую, а не как метод, применяемый к объекту данного класса. В этот момент переменных класса нет. Поэтому функции, вызываемые до создания объекта, не могут пользоваться переменными класса и конструкцией this, но могут пользоваться локальными и глобальными переменными.
В определении класса Programmer мы переопределили функцию show_name(), поэтому вызвать функцию show_name() из базового класса Person можно только с помощью оператора "::" Вообще говоря, внутри определения класса мы можем вызывать любые методы и свойства, заданные в его базовом классе с помощью обычного $this, если только порожденный класс не переопределяет эти свойства и методы, как в нашем примере.

Оператор parent

В приведенном выше примере, обращаясь к базовому классу, мы использовали его имя (мы писали Person::show_name() ). Это не совсем удобно, потому что имя класса или иерархия классов может измениться, и тогда придется переписывать код описаний всех классов с тем, чтобы привести используемые в них имена в соответствие с новой иерархией. Чтобы избежать подобной ситуации, вместо имени базового класса нужно использовать ключевое слово parent (например, parent::show_name() ). Parent ссылается на класс, прописанный после extends в объявлении вашего класса. Поэтому если вдруг иерархия классов изменится, то достаточно будет внести изменения в имена, указанные после extends в описаниях классов.

Объектная модель PHP5

Кроме нового названия для конструкторов и появления деструкторов в PHP5 произошло еще достаточно много изменений. Мы не будем обсуждать их подробно, только опишем в общих чертах. Основное изменение – это передача значений параметров класса по ссылке и присвоение объектов по ссылке, а не по значению, как это было в PHP4. В PHP5 если создаются две равные переменные типа объект, то они указывают на одно значение и изменяются одновременно (мы приводили похожий пример с переменными строкового типа). В связи с этим появился новый механизм для создания копий объектов – так называемое клонирование. В PHP4 все методы и переменные класса доступны извне, т.е. они всегда являются открытыми. В PHP5 переменные и методы можно делать открытыми (доступными отовсюду), закрытыми (доступными только внутри класса ) и защищенными (доступными внутри класса и в его производных классах ). Кроме того, появилась возможность создавать интерфейсы и абстрактные классы и многое другое. В целом объектная модель в PHP5 значительно усовершенствована для более точного соответствия объектно-ориентированной парадигме программирования.

Решение задачи

Итак, мы хотели по выбору пользователя генерировать форму для ввода описания статьи или человека и отображать данные, введенные в эту форму. Попробуем решить эту задачу, используя объектно-ориентированный подход. Для начала создадим форму, где
пользователь выбирает, что он хочет создать, – описание статьи или человека (точнее, это будут две формы):
<form action="task1.php"> Создать описание статьи: <input type=submit name=art_create value="Create Article"> </form> <form action="task1.php"> Создать описание личности: <input type=submit name=pers_create value="Create Person"> </form>
Теперь напишем файл для обработки этих форм. В нем создадим два класса – статьи и личности. У каждого класса имеется метод для инициализации его переменных и метод для отображения объектов данного класса. При решении задачи будут использованы две функции, встроенные в PHP для работы с классами и объектами. Это функция get_class (объект), возвращающая имя класса, экземпляром которого является объект, переданный ей в качестве параметра. И функция get_class_vars (имя класса ), которая возвращает массив всех свойств класса и их значений по умолчанию. Аналогично можно получить массив имен всех методов класса: get_class_methods (имя класса )
<?php // Создаем классы Статей и Личностей. // Статья имеет заголовок, автора и // описание. Личность имеет имя, фамилию // и e-mail class Article { var $title; var $author; var $description; // метод, который присваивает значения // атрибутам класса function Article($t="Название отсутствует", $a="Автор отсутствует", $d="Описание отсутствует"){ $this->title = $t; $this->author = $a; $this->description = $d; } //метод для отображения экземпляров класса function show(){ $art = "<h2>$this->title</h2><font size=-1>$this->description</font><p>Автор: $this->author</p>"; echo $art; } } // Определение класса Личностей class Person {
var $first_name; var $last_name; var $email; //метод, который присваивает значения атрибутам класса function Person($t="Имя не введено", $a="Фамилия не введена",$d="Email не указан"){ $this->first_name = $t; $this->last_name = $a; $this->email = $d; } //метод для отображения экземпляров класса function show(){ $art = "<h2>$this->first_name</h2><font size=-1>$this->last_name</font><p>e-mail: $this->email</p>"; echo $art; } } // Далее следует собственно создание и отображение // экземпляров выбранного класса if (isset($_GET["art_create"])){ //Если была выбрана статья $art = new Article; // создаем представителя класса статей $art_vars = get_class_vars(get_class($art)); //какие // аргументы этого класса нужно задать Make_form($art,$art_vars,"art_create"); //вызов функции // создания формы if (isset($_GET["create_real"])){ Show_($art_vars); } // если данные этой формы отправлены, то вызываем // функцию показа } //то же самое, если была выбрана личность if (isset($_GET["pers_create"])){ $art = new Person; $art_vars = get_class_vars(get_class($art)); Make_form($art,$art_vars,"pers_create"); if (isset($_GET["create_real"])){ Show_($art_vars); } } // функция создания формы function Make_form($art,$art_vars,$glob){ $str = "<form>"; // html код формы записывается // в строку $str //перебираем список переменных класса объекта $art foreach ($art_vars as $var_name => $var_value){ $str .="$var_name<input type=text name=$var_name><br>"; //создаем элемент формы с именем свойства класса } $str .= "<input type=hidden name=$glob>"; // чтобы не // забыть, что мы создаем $str .= "<input type=submit name=create_real value='Create and Show'></form>"; echo "$str"; // выводим форму }
// функция показа объекта function Show_($art_vars){ global $art; //используется глобальное имя объекта $k = count($art_vars); //число свойств класса // (переменных в форме) $p=0; //вспомогательная переменная foreach ($art_vars as $name => $value){ $p++; if ($_GET["$name"]=="") $val= $art->$name; else $val = $_GET["$name"]; if ($p<>$k) $par .='"'. $val.'",'; else $par .='"'. $val.'"'; } $const=get_class($art); $par = '$art->'.$const ."(" .$par.");"; // теперь $par представляет собой php-код для вызова // метода класса $art, изначально // записанного в $par // например, // $art->Person('Vasia','Petrov','vas@mail.ru'); eval($par); // функция eval выполняет код, // содержащийся в $par $art->show(); } ?> Листинг 6.6. Использование объектно-ориентированного подхода
ТЕМА 3. Массивы

В одной из первых лекций мы рассказывали о том, как можно создать массив данных. Напомним, что массив можно создать двумя способами: 1. С помощью конструкции array
2. $array_name = array("key1"=>"value1", "key2"=>"value2");
3. Непосредственно задавая значения элементам массива $array_name["key1"] = value1;
Например, нам нужно хранить список документов, которые будут удалены из базы данных. Естественно хранить его в виде массива, ключом в котором будет идентификатор документа (его уникальный номер), а значением – название документа. Этот массив можно создать таким образом:
<? $del_items = array("10"=>"Наука и жизнь", "12"=>"Информатика"); $del_items["13"] = "Программирование на Php"; // добавляем элемент в массив ?>

Операции с массивами

Массив – это тип данных, с данными этого типа должны быть определены операции. Какие же операции можно производить с массивами? Массивы можно складывать и сравнивать.
Складывают массивы с помощью стандартного оператора " + ". Вообще говоря, эту операцию по отношению к массивам точнее назвать объединением. Если у нас есть два массива, $a и $b, то результатом их сложения (объединения) будет массив $c, состоящий из элементов $a, к которым справа дописаны элементы массива $b. Причем, если встречаются совпадающие ключи, то в результирующий массив включается элемент из первого массива, т.е. из $a. Таким образом, если складываются массивы в языке PHP, от перемены мест слагаемых сумма меняется.
<? $a = array("и"=>"Информатика", "м"=>"Математика"); $b = array("и"=>"История","м"=>"Биология", "ф"=>"Физика"); $c = $a + $b; $d = $b + $a; print_r($c); /* получим: Array([и]=>Информатика [м]=>Математика [ф]=>Физика) */ print_r($d); /* получим: Array([и]=>История [м]=>Биология [ф]=>Физика) */ ?>
Пример 7.1. Сложение массивов

Сравнивать массивы можно, проверяя их равенство или неравенство либо эквивалентность или неэквивалентность. Равенство массивов – это когда совпадают все пары ключ / значение элементов массивов. Эквивалентность – когда кроме равенства значений и ключей элементов требуется еще, чтобы элементы в обоих массивах были записаны в одном и том же порядке. Равенство значений в PHP обозначается символом " == ", а эквивалентность – символом " === ".
<? $a = array("и"=>"Информатика", "м"=>"Математика"); $b = array("м"=>"Математика", "и"=>"Информатика"); if ($a == $b) echo "Массивы равны и"; else echo "Массивы НЕ равны и "; if ($a === $b) echo " эквивалентны"; else echo " НЕ эквивалентны"; // получим echo "Массивы равны и НЕ эквивалентны" ?>
Пример 7.2. Сравнение массивов

Далее рассмотрим еще одну важную операцию с массивом – подсчет количества его элементов. Для ее реализации в PHP есть специальная функция.

Функция count

Не раз уже мы использовали функцию count() , чтобы вычислить количество элементов массива. На самом деле эта функция вычисляет число элементов в переменной вообще. Если применить ее к любой другой переменной, она возвратит 1. Исключение составляет переменная типа NULL – count(NULL) есть 0. Кроме того, применяя эту функцию к многомерному массиву, чтобы получить число его элементов, нужно использовать дополнительный параметр COUNT_RECURSIVE.
<? $del_items = array("langs" => array( "10"=>"Python", "12"=>"Lisp"), "other"=>"Информатика"); echo count($del_items) . "<br>"; // выведет 2 echo count($del_items,COUNT_RECURSIVE); // выведет 4 ?>
Пример 7.3. Применение функции count()

Мы не будем повторять все, что было сказано о массивах в предыдущих лекциях. В этой лекции мы рассмотрим некоторые встроенные функции для работы с массивами. И начнем мы с функций для поиска значений в массиве.
Функция in_array
in_array("искомое значение","массив",
["ограничение на тип"]);
позволяет установить, содержится ли в заданном массиве искомое значение. Если третий аргумент задан как true, то в массиве нужно найти элемент, совпадающий с искомым не только по значению, но и по типу. Если искомое значение – строка, то сравнение чувствительно к регистру.
Например, имеется массив неизученных нами языков программирования. Мы хотим узнать, содержится ли в этом массиве язык PHP. Напишем следующую программу:
<?php $langs = array("Lisp","Python","Java", "PHP","Perl"); if (in_array("PHP",$langs,true)) echo "Надо бы изучить PHP<br>"; // выведет сообщение "Надо бы изучить PHP" if (in_array("php",$langs)) echo "Надо бы изучить php<br>"; // ничего не выведет, поскольку в массиве // есть строка "PHP", а не "php" ?>
В качестве искомого значения этой функции может выступать и массив. Правда, это свойство было добавлено только начиная с PHP 4.2.0. Например:
<?php $langs = array("Lisp","Python",array("PHP","Java"),"Perl"); if (in_array(array("PHP","Java"),$langs)) echo "Надо бы изучить PHP и Java<br>"; ?>

Функция array_search

Это еще одна функция для поиска значения в массиве. В отличие от in_array в результате работы array_search возвращает значение ключа, если элемент найден, и ложь – в противном случае. А вот синтаксис у этих функций одинаковый:
array_search("искомое значение","массив", ["ограничение на тип"]);

Сравнение строк чувствительно к регистру, а если указан опциональный аргумент, то сравниваются еще и типы значений. До PHP 4.2.0, если искомое значение не было найдено, эта функция возвращала ошибку или пустое значение NULL.

Пример 7.4. Теперь, наоборот, пусть у нас есть массив языков программирования, которые мы знаем. Причем ключом каждого элемента является номер, указывающий, каким по счету был изучен этот язык.
<?php $langs = array("","Lisp","Python","Java", "PHP","Perl"); if (!array_search("PHP",$langs)) echo "Надо бы изучить PHP<br>"; else { $k = array_search("PHP",$langs); echo "PHP я изучила ".$k."-м"; } ?>
Пример 7.4. Применение функции array_search()
В результате мы получим строчку:
PHP я изучила 4-м
Очевидно, что эта функция более функциональна, чем in_array , поскольку мы не только получаем информацию о том, что искомый элемент в массиве есть, но и узнаем, где именно в массиве он находится. А что будет, если искомых элементов в массиве несколько? В таком случае функция array_search() вернет ключ первого из найденных элементов. Чтобы получить ключи всех элементов, нужно воспользоваться функцией array_keys() .

Функция array_keys

Функция array_keys() выбирает все ключи массива. Но у нее имеется дополнительный аргумент, с помощью которого можно получить список ключей элементов с конкретным значением. Синтаксис этой функции таков:
array_keys ("массив", ["значение для поиска"])
Функция array_keys() возвращает как строковые, так и числовые ключи массива, организуя все значения в виде нового массива с числовыми индексами.

Пример 7.5. Мы записали массив языков, которые изучили. Список был длинным, и некоторые языки были записаны несколько раз. У нас возникло подозрение, что один из таких языков – Lisp. Давайте это проверим:
<?php $langs = array("Lisp","Python","Java","PHP", "Perl","Lisp"); $lisp_keys = array_keys($langs,"Lisp"); echo "Lisp входит в массив ". count($lisp_keys) ." раза:<br>"; foreach ($lisp_keys as $val){ echo "под номером $val <br>"; } ?> Пример 7.5. Применение функции array_keys()
В результате получим:
Lisp входит в массив 2 раза:
под номером 0
под номером 5
Функция array_keys() , как и две предыдущие, зависит от регистра, т.е. элементов LISP в массиве она не обнаружит. array_keys() появилась только в PHP4. В PHP3 для реализации ее функциональности нужно придумывать свою функцию.
Если есть функция для получения всех ключей массива, то можно предположить, что существует и функция для получения всех значений массива. Действительно, она существует. Это функция array_values(массив). Все значения переданного ей массива записываются в новый массив, проиндексированный целыми числами, т.е. все ключи массива теряются, остаются только значения. Но вернемся к нашему примеру.
Итак, мы выяснили, что язык Lisp случайно упомянут в нашем массиве дважды. Поскольку изучить один язык дважды нельзя ("учил, но забыл" не считается), то нужно как-то избавиться от повторяющихся языков. Сделать это довольно просто с помощью функции array_unique() .


Функция array_unique

Функция array_unique(массив) возвращает новый массив, в котором повторяющиеся элементы фигурируют в одном экземпляре. Таким образом, вместо нескольких одинаковых значений и их ключей мы имеем одно значение. Какой у него будет ключ? Как из нескольких ключей одинаковых элементов выбирается тот, который будет сохранен в новом массиве? Происходит следующее. Все элементы массива преобразуются в строки и сортируются. Затем обработчик запоминает первый ключ для каждого значения, а остальные ключи игнорирует.

Попробуем избавиться от повторяющихся языков в списке изученных. <?php $langs = array("Lisp","Java","Python","Java", "PHP","Perl","Lisp"); print_r(array_unique($langs)); ?>
Получим следующее:
Array ( [0] => Lisp [1] => Java [2] => Python [3] => PHP [4] => Perl ) Далее рассмотрим задачу сортировки массива.

Сортировка массивов

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

Функция sort

Функция sort имеет следующий синтаксис
sort (массив [, флаги])
и сортирует массив, т.е. упорядочивает его значения по возрастанию. Эта функция удаляет все существовавшие в массиве ключи, заменяя их числовыми индексами, соответствующими новому порядку элементов. В случае успешного завершения работы она возвращает true, иначе – false.

Пример 7.6. Пусть у нас есть два массива: цены товаров – их названия и, наоборот, названия товаров – их цены. Упорядочим эти массивы по возрастанию:
<? $items = array(10 => "хлеб", 20 => "молоко", 30 => "бутерброд"); sort($items); // строки сортируются в алфавитном
// порядке, ключи теряются print_r($items); $rev_items = array("хлеб" => 10, "бутерброд" => 30, "молоко" => 20); sort($rev_items); // числа сортируются по возрастанию, // ключи теряются print_r($rev_items); ?> Пример 7.6. Применение функции sort()
Получим:
Array ( [0] => бутерброд [1] => молоко [2] => хлеб ) Array ( [0] => 10 [1] => 20 [2] => 30 )
В качестве дополнительного аргумента может использоваться одна из следующих констант:
  • SORT_REGULAR – автоматический выбор метода;
  • SORT_NUMERIC – сравнивать элементы массива как числа;
  • SORT_STRING – сравнивать элементы массива как строки.
Функции asort, rsort, arsort

Если требуется сохранять индексы элементов массива после сортировки, то нужно использовать функцию asort (массив [, флаги]) . Если необходимо отсортировать массив в обратном порядке, т.е. от наибольшего значения к наименьшему, то можно задействовать функцию rsort (массив [, флаги]) . А если при этом нужно еще и сохранить значения ключей, то следует использовать функцию arsort(массив [, флаги]) . Как вы, наверное, заметили синтаксис у этих функций абсолютно такой же, как у функции sort . Соответственно и значения флагов могут быть такими же, как у sort : SORT_REGULAR , SORT_NUMERIC , SORT_STRING . Кстати говоря, флаг SORT_NUMERIC появился только в PHP4.
<?php $books = array("Пушкин"=>"Руслан и Людмила", "Толстой"=>"Война и мир", "Лермонтов"=>"Герой нашего времени"); asort($books); // сортируем массив, // сохраняя значения ключей print_r($books); echo "<br>"; rsort($books); // сортируем массив в обратном порядке, // ключи будут заменены print_r($books); ?> Пример 7.7. Применение функций asort, rsort, arsort
В результате работы этого скрипта получим:
Array ( [Толстой] => Война и мир [Лермонтов] => Герой нашего времени [Пушкин] => Руслан и Людмила ) Array ( [0] => Руслан и Людмила [1] => Герой нашего времени [2] => Война и мир )

Пример 7.8. Допустим, мы создаем каталог описаний документов. У каждого документа есть автор, название, дата публикации и краткое содержание. Мы уже не раз отображали описания, составленные из этих характеристик. Каждый раз порядок отображения этих элементов зависел от созданной нами программы. Теперь же мы хотим иметь возможность изменять порядок отображения элементов по желанию пользователя. Составим для этого следующую форму:
<form action=task.php> <table border=1> <tr><td>Название </td><td><input type=text name=title size=5> </td></tr> <tr><td>Краткое содержание </td><td><input type=text name=description size=5> </td></tr> <tr><td>Автор </td><td><input type=text name=author size=5> </td></tr> <tr><td>Дата публикации </td><td><input type=text name=published size=5></td></tr> </table> <input type=submit value="Отправить"> </form>
Пример 7.8a. Форма для примера 7.8

Будем упорядочивать данные, переданные этой формой, по убыванию их значений, сохраняя при этом значения ключей. Для этого удобно воспользоваться функцией arsort() . Поскольку нам важен только новый порядок элементов, сохраним в новом массиве ключи исходного массива в нужном порядке. Мы сохраняем ключи исходного массива, поскольку они являются именами элементов, из которых конструируется описание документа, а помнить их важно. Итак, получаем такой скрипт: <?php print_r($_GET); echo "<br>"; arsort ($_GET); // сортируем массив в обратном порядке, // сохраняя ключи print_r($_GET); echo "<br>"; $ordered_names = array_keys($_GET); // составляем новый массив foreach($ordered_names as $key => $val) echo "$key :$val <br>"; // выводим элементы нового массива ?>
Пример 7.8b. Программа обработки формы из примера 7.8

Сортировка массива по ключам

Очевидно, что может возникнуть необходимость в сортировке массива по значениям ключей. Например, если у нас есть массив данных о книгах, как в приведенном выше примере, то вполне вероятно, что мы захотим отсортировать книги по именам авторов. Для этого в PHP также не нужно писать много строк кода – можно просто воспользоваться функцией ksort() для сортировки по возрастанию (прямой порядок сортировки ) или krsort() – для сортировки по убыванию (обратный порядок сортировки ). Синтаксис этих функций опять же аналогичен синтаксису функции sort() .
<?php $books = array("Пушкин"=>"Руслан и Людмила", "Толстой"=>"Война и мир", "Лермонтов"=>"Герой нашего времени"); ksort($books); // сортируем массив, // сохраняя значения ключей print_r($books); ?> Пример 7.9. Сортировка массива по ключам Получим: Array ( [Лермонтов] => Герой нашего времени [Пушкин] => Руслан и Людмила [Толстой] => Война и мир )

Сортировка с помощью функции, заданной пользователем

Кроме двух простых способов сортировки значений массива (по убыванию или по возрастанию) PHP предлагает пользователю возможность самому задавать критерии для сортировки данных. Критерий задается с помощью функции, имя которой указывается в качестве аргумента для специальных функций сортировки usort() или uksort() . По названиям этих функций можно догадаться, что usort() сортирует значения элементов массива, а uksort() – значения ключей массива с помощью определенной пользователем функции. Обе функции возвращают true, если сортировка прошла успешно, и false – в противном случае. Их синтаксис выглядит следующим образом:
usort (массив , сортирующая функция) uksort (массив , сортирующая функция)
Конечно же, нельзя сортировать массив с помощью любой пользовательской функции. Эта функция должна удовлетворять определенным критериям, позволяющим сравнивать элементы массива. Как должна быть устроена сортирующая функция? Во-первых, она должна иметь два аргумента. В них интерпретатор будет передавать пары значений элементов для функции usort() или ключей массива для функции uksort() . Во-вторых, сортирующая функция должна возвращать:
  • целое число, меньшее нуля, если первый аргумент меньше второго;
  • число, равное нулю, если два аргумента равны;
  • число большее нуля, если первый аргумент больше второго.
Как и для других функций сортировки, для функции usort() существует аналог, не изменяющий значения ключей, – функция uasort() .

Пример 7.10. Допустим, у нас есть массив, содержащий такие сведения о литературных произведениях, как название, автор и год создания. Мы хотим упорядочить книги по дате создания.
<?php // массив выглядит таким образом: $books = array("Герой нашего времени" => array ("Лермонтов", 1840), "Руслан и Людмила" => array("Пушкин",1820), "Война и мир" => array ("Толстой",1863), "Идиот" => array("Достоевский",1868)); /* можно, конечно переписать этот массив по-другому, сделав год издания, например, индексом, но гораздо удобнее написать свою функцию для сортировки */ uasort($books,"cmp"); // сортируем массив с помощью функции cmp foreach ($books as $key => $book) { echo "$book[0]: \"$key\"<br>"; } function cmp($a,$b){ // функция, определяющая способ сортировки if ($a[1] < $b[1]) return -1; elseif ($a[1]==$b[1]) return 0; else return 1; } ?> Пример 7.10. Сортировка с помощью пользовательских функций
В результате получим:
Пушкин: "Руслан и Людмила" Лермонтов: "Герой нашего времени" Толстой: "Война и мир" Достоевский: "Идиот"
Мы применили нашу собственную функцию сортировки ко всем элементам массива. Далее рассмотрим, как применить к элементам массива любую другую пользовательскую функцию.

Применение функции ко всем элементам массива

Функция array_walk(массив, функция [, данные]) применяет созданную пользователем функцию ко всем элементам массива массив и возвращает true в случае успешного выполнения операции и false – в противном случае.
Пользовательская функция, как правило, имеет два аргумента, в которые поочередно передаются значение и ключ каждого элемента массива. Но если при вызове функции array_walk() указан третий аргумент, то он будет рассмотрен как значение третьего аргумента пользовательской функции, смысл которого определяет сам пользователь. Если функция пользователя требует больше аргументов, чем в нее передано, то при каждом вызове array_walk() будет выдаваться предупреждение.
Если необходимо работать с реальными значениями массива, а не с их копиями, следует передавать аргумент в функцию по ссылке. Однако нужно иметь в виду, что нельзя добавлять или удалять элементы массива и производить действия, изменяющие сам массив, поскольку в этом случае результат работы array_walk() считается неопределенным. <?php $books1 = array( "А.С. Пушкин"=>"Руслан и Людмила", "Л.Н. Толстой"=>"Война и мир", "М.Ю. Лермонтов"=>"Герой нашего времени"); // создаем функцию, которую хотим // применить к элементам массива function try_walk($val,$key,$data){ echo "$data \"$val\" написал $key<br>"; } // применяем ко всем элементам массива // $books1 функцию try_walk array_walk($books1,"try_walk","Роман"); ?>
Пример 7.11. Применение функции ко всем элементам массива
В результате работы скрипта получим:
Роман "Руслан и Людмила" написал А.С. Пушкин Роман "Война и мир" написал Л.Н. Толстой Роман "Герой нашего времени" написал М.Ю. Лермонтов
Заметим, что мы не изменили значений у элементов массива. Чтобы их изменить, надо было передавать значения в переменную $val функции try_walk по ссылке.
<?php $books1 = array( "А.С. Пушкин"=>"Руслан и Людмила", "Л.Н. Толстой"=>"Война и мир", "М.Ю. Лермонтов"=>"Герой нашего времени"); // создаем функцию, которую хотим
// применить к элементам массива function try_walk(&$val,$key){ $key = "<p>Автор: " .$key ."<br>"; $val = "Название: \"" . $val ."\"</p>"; echo $key.$val; } // применяем ко всем элементам массива // $book1 функцию try_walk array_walk($books1,"try_walk"); print_r($books1); ?>
Пример 7.12. Применение функции ко всем элементам массива.Вариант 2
В результате работы скрипта получим:
Автор: А.С. Пушкин Название: "Руслан и Людмила" Автор: Л.Н. Толстой Название: "Война и мир" Автор: М.Ю. Лермонтов Название: "Герой нашего времени" Array ( [А.С. Пушкин] => Название: "Руслан и Людмила" [Л.Н. Толстой] => Название: "Война и мир" [М.Ю. Лермонтов] => Название: "Герой нашего времени")
Выделение подмассива

Функция array_slice

Поскольку массив – это набор элементов, вполне вероятно, потребуется выделить из него какой-нибудь поднабор. В PHP для этих целей есть функция array_slice . Ее синтаксис таков:
array_slice (массив, номер_элемента [, длина])
Эта функция выделяет подмассив длины длина в массиве массив, начиная с элемента, номер которого задан параметром номер_элемента. Положительный номер_элемента указывает на порядковый номер элемента относительно начала массива, отрицательный – на номер элемента с конца массива.
<?php $arr = array(1,2,3,4,5); $sub_arr = array_slice($arr,2); print_r($sub_arr); /* выведет Array ( [0] => 3 [1] =>4 [2] => 5 ), т.е. подмассив, состоящий из элементов 3, 4, 5 */
$sub_arr = array_slice($arr,-2); print_r($sub_arr); // выведет Array ( [0] => 4 [1] => 5 ), // т.е. подмассив, из элементов 4, 5 ?>
Пример 7.13. Использование функции array_slice()

Если задать параметр длина при использовании array_slice , то будет выделен подмассив, имеющий ровно столько элементов, сколько задано этим параметром. Длину можно указывать и отрицательную. Если в эту функцию передан отрицательный параметр length, в последовательность войдут все элементы исходного массива, начиная с позиции offset и заканчивая позицией, отстоящей на length элементов от конца array.
<?php $arr = array(1,2,3,4,5); $sub_arr = array_slice($arr, 2, 2); // содержит массив из элементов 3, 4 $sub = array_slice($arr,-3, 2); // тоже содержит массив из элементов 3, 4 $sub1 = array_slice($arr,0, -1); // содержит массив из // элементов 1, 2, 3, 4 $sub2 = array_slice($arr,-4, -2); // содержит массив из элементов 2, 3 ?>
Пример 7.14. Использование функции array_slice(). Вариант 2

Функция array_chunk

Есть еще одна функция, похожая на array_slice() – это array_chunk() . Она разбивает массив на несколько подмассивов заданной длины. Синтаксис ее такой:
array_chunk ( массив, размер [, сохранять_ключи])
В результате работы array_chunk() возвращает многомерный массив, элементы которого представляют собой полученные подмассивы. Если задать параметр сохранять ключи как true, то при разбиении будут сохранены ключи исходного массива. В противном случае ключи элементов заменяются числовыми индексами, которые начинаются с нуля.

Пример 7.15.У нас есть список приглашенных, оформленный в виде массива их фамилий. У нас имеются столики на три персоны. Поэтому нужно распределить всех приглашенных по трое.
<?php $persons = array("Иванов", "Петров", "Сидорова","Зайцева", "Волкова"); $triples = array_chunk($persons,3); // делим массив на подмассивы // по три элемента foreach ($triples as $k => $table){
// выводим полученные тройки echo "За столиком номер $k сидят: <ul>"; foreach ($table as $pers) echo "<li>$pers"; echo "</ul>"; } ?>
Пример 7.15. Использование функции array_chunk()
В результате получим:
за столиком номер 0 сидят:
• Иванов
• Петров
• Сидорова за столиком номер 1 сидят:
• Зайцева
• Волкова

Сумма элементов массива

В этом разделе мы познакомимся с функцией, вычисляющей сумму всех элементов массива. Сама задача вычисления суммы значений массива предельно проста. Но зачем писать лишний раз один и тот же код, если можно воспользоваться специально созданной и всегда доступной функцией. Функция эта называется, как можно догадаться, array_sum() . И в качестве параметра ей передается только имя массива, сумму значений элементов которого нужно вычислить.
В качестве примера использования этой функции приведем решение более сложной задачи, чем просто вычисление суммы элементов. Этот пример также иллюстрирует применение функции array_slice() , которую мы обсуждали чуть раньше.

Пример 7.16. Пусть дан массив натуральных чисел. Нужно найти в нем такое число, что сумма элементов справа от него равна сумме элементов слева от него.
<?php //массив задается функцией array $arr = array(2,1,3,4,5,6,4); // перебираем каждый элемент массива $arr. // Внутри цикла текущий ключ массива // содержится в переменной $k, // текущее значение – в переменной $val foreach ($arr as $k => $val){ $p = $k + 1; // синтаксис array array_slice ( // array array,int offset [,int length]) // array_slice выделяет подмассив // длины length в массиве array, // начиная с элемента offset. $out_next = array_slice($arr,$p); // получаем массив элементов, // идущих после текущего $out_prev = array_slice($arr,0,$k);
// получаем массив элементов, // идущих перед текущим // функция mixed array_sum (array array) // подсчитывает сумму элементов массива array $next_sum = array_sum($out_next); $prev_sum = array_sum($out_prev); // если сумма элементов до текущего равна // сумме элементов после, то выводим // значение текущего элемента if ($next_sum==$prev_sum) echo "value:$val"; // можно посмотреть, что представляют собой // рассмотренные массивы на каждом шаге // print_r($out_next); echo "<br>"; // print_r($out_prev); // echo "$next_sum, $prev_sum<br>"; echo "<hr>"; } ?>
Пример 7.16. Программа поиска числа, такого что сумма элементов справа от него равна сумме элементов слева от него
ТЕМА 4. Строки

Вероятно, читатели примерно представляют, что такое тип данных " строка " и как создать переменную такого типа. В одной из первых лекций мы приводили три способа задания строк: с помощью одинарных кавычек, двойных кавычек и с помощью heredoc –синтаксиса. Отмечали мы и основные различия между этими способами. В основном они касаются обработки переменных и управляющих последовательностей внутри строки.
<?php echo 'В такой строке НЕ обрабатываются переменные и большинство последовательностей'; echo "Здесь переменные и последовательности обрабатываются"; echo <<<EOT Здесь тоже обрабатываются как переменные, так и управляющие последовательности. И кроме того, можно вводить символы кавычек без их экранирования обратным слэшем. EOT; ?>
Пример 8.1. Способы задания строк


Уже не раз, начиная с самой первой лекции, мы использовали функцию echo . На самом деле, echo – не функция, а языковая конструкция, поэтому использовать при ее вызове круглые скобки не обязательно. Echo позволяет выводить на экран строки, переданные ей в качестве параметров. Параметров у echo может быть сколько угодно. Их разделяют запятыми или объединяют с помощью оператора конкатенации и никогда не заключают в круглые скобки.
<? echo "Пришел ", "увидел ", "победил "; // выведет строку "Пришел увидел победил" // многие предпочитают передавать несколько // параметров в echo с помощью конкатенации echo "Пришел " . "увидел " . "победил "; // тоже выведет строку // "Пришел увидел победил" echo ("Пришел ", "увидел ", "победил "); // выдаст ошибку: unexpected ',' ?>
Пример 8.2. Использование функции echo

Существует сокращенный синтаксис для команды echo :
<?=строка_для_вывода?>
Здесь параметр строка_для_вывода содержит строку, заданную любым из известных способов, которая должна быть выведена на экран. Например, такой скрипт выведет на экран красным цветом "Меня зовут Вася":
<? $name="Вася" ?> <font color=red>Меня зовут <?=$name?></font>

Кроме языковой конструкции echo существует ряд функций для вывода строк. Это в первую очередь функция print и ее разновидности printf, sprintf и т.п.
Функция print позволяет выводить на экран только одну строку и, как и echo , не может быть вызвана с помощью переменных функций, поскольку является языковой конструкцией.
Функция print_r не относится к строковым функциям, как можно было бы подумать. Она отображает информацию о переменной в форме, понятной пользователю.
Функции sprintf и printf обрабатывают переданную им строку в соответствии с заданным форматом. Но о них мы говорить не будем. А поговорим о том, как можно осуществлять поиск в тексте, представленном в виде строки.


Поиск элемента в строке

Для того чтобы определить, входит ли данная подстрока в состав строки, используется функция strpos() . Синтаксис strpos() такой:
strpos (исходная строка,строка для поиска [,с какого символа искать])

Она возвращает позицию появления искомой строки в исходной строке или возвращает логическое false, если вхождение не найдено. Дополнительный аргумент позволяет задавать символ, начиная с которого будет производиться поиск. Кроме логического false эта функция может возвращать и другие значения, которые приводятся
к false (например, 0 или ""). Поэтому для того, чтобы проверить, найдена ли искомая строка, рекомендуют использовать оператор эквивалентности " === ".
<? $str = "Идея наносить данные на перфокарты и затем считывать и обрабатывать их автоматически принадлежала Джону Биллингсу, а ее техническое решение осуществил Герман Холлерит. Перфокарта Холлерита оказалась настолько удачной, что без малейших изменений просуществовала до наших дней."; $pos = strpos($str,"Холлерит"); if ($pos !== false) echo "Искомая строка встречена в позиции номер $pos "; else echo "Искомая строка не найдена"; /* заметим, что мы проверяем значение $pos на эквивалентность с false. Иначе строка, находящаяся в первой позиции, не была бы найдена, так как 0 интерпретируется как false. */ ?>
Пример 8.3. Использование функции strpos()

Если значение параметра строка_для_поиска не является строкой, то оно преобразуется к целому типу и рассматривается как ASCII-код символа. Чтобы получить ASCII-код любого символа в PHP, можно воспользоваться функцией ord("символ")
Например, если мы напишем $pos = strpos($str,228); то интерпретатор будет считать, что мы ищем символ " д ". Если добавить эту строчку в приведенный выше пример и вывести результат, то получим сообщение, что искомая строка найдена в позиции 1.
Функция, обратная по смыслу ord, – это chr (код символа) . Она по ASCII-коду выводит символ, соответствующий этому коду.
С помощью функции strpos можно найти номер только первого появления строки в исходной строке. Естественно, есть функции, которые позволяют вычислить номер последнего появления строки в исходной строке. Это функция strrpos() .
Ее синтаксис таков:
strrpos (исходная строка, символ для поиска)

В отличие от strpos() эта функция позволяет найти позицию последнего появления в строке указанного символа.
Бывают ситуации, когда знать позицию, где находится искомая строка, необязательно, а нужно просто получить все символы, которые расположены после вхождения этой строки. Можно, конечно, воспользоваться и приведенными выше функциями strpos() и strrpos() , но можно сделать и проще – выделить подстроку с помощью предназначенных именно для этого функций.
Выделение подстроки

Функция strstr

Говоря о выделении подстроки из искомой строки в языке PHP, в первую очередь стоит отметить функцию strstr() :
strstr (исходная строка, строка для поиска)
Она находит первое появление искомой строки и возвращает подстроку, начиная с этой искомой строки до конца исходной строки. Если строка для поиска не найдена, то функция вернет false. Если строка для поиска не принадлежит строковому типу данных, то она переводится в целое число и рассматривается как код символа. Кроме того, эта функция чувствительна к регистру, т.е. если мы будем параллельно искать вхождения слов "Идея" и "идея", то результаты будут разными. Вместо strstr() можно использовать абсолютно идентичную ей функцию strchr() .
Пример 8.4. Выделим из строки, содержащей название и автора исследования, подстроку, начинающуюся со слова "Название":
<? $str = "Автор: Иванов Иван (<a href=mailto:van@mail.ru>написать письмо</a>), Название: 'Исследование языков программирования' "; echo "<b>Исходная строка: </b>",$str; if (!strstr($str, "Название")) echo "Строка не найдена<br>"; else echo "<p><b>Полученная подстрока: </b>", strstr($str, "Название"); ?>
Пример 8.4. Использование функции strstr()
В результате получим:
Исходная строка: Автор: Иванов Иван (написать письмо), Название: 'Исследование языков программирования' Полученная подстрока: Название: 'Исследование языков программирования'
Для реализации регистронезависимого поиска подстроки существует соответствующий аналог этой функции – функция stristr (исходная строка, искомая строка) . Действует и используется она точно так же, как и strstr() , за исключением того, что регистр, в котором записаны символы искомой строки, не играет роли при поиске.
Очевидно, что функция strstr() не слишком часто используется – на практике редко бывает нужно получить подстроку, начинающуюся с определенного слова или строки. Но в некоторых случаях и она может пригодиться. Кроме того, в PHP есть и более удобные функции для поиска вхождений. Наиболее мощные из них, конечно, связаны с регулярными выражениями. Их мы рассмотрим в одной из последующих лекций.

Функция substr

Иногда мы не знаем, с каких символов начинается искомая строка, но знаем, например, что начинается она с пятого символа и заканчивается за два символа до конца исходной строки. Как выделить подстроку по такому описанию? Очень просто, с помощью функции substr() . Ее синтаксис можно записать следующим образом:
substr (исходная строка, позиция начального символа [, длина])

Эта функция возвращает часть строки длиной, заданной параметром длина, начиная с символа, указанного параметром позиция начального символа. Позиция, с которой начинается выделяемая подстрока, может быть как положительным целым числом, так и отрицательным. В последнем случае отсчет элементов производится с конца строки. Если параметр длина опущен, то substr() возвращает подстроку от указанного символа и до конца исходной строки. Длина выделяемой подстроки тоже может быть задана отрицательным числом. Это означает, что указанное число символов отбрасывается с конца строки.

Пример 8.5. Допустим, у нас есть фраза, выделенная жирным шрифтом с помощью тега <b> языка HTML. Мы хотим получить эту же фразу, но в обычном стиле. Напишем такую программу:
<?php $word = "<b>Hello, world!</b>"; echo $word , "<br>"; $pure_str = substr($word, 3, -4); /* выделяем подстроку, начиная с 3-го символа, не включая 4 символа с конца строки */ echo $pure_str; ?>
Пример 8.5. Использование функции substr()
В результате работы этого скрипта получим:
Hello, world! Hello, world!
На самом деле решить такую задачу можно гораздо проще, с помощью функции strip_tags :
strip_tags (строка [, допустимые теги])
Эта функция возвращает строку, из которой удалены все html и php-теги. С помощью дополнительного аргумента можно задать теги, которые не будут удалены из строки. Список из нескольких тегов вводится без каких-либо знаков разделителей. Функция выдает предупреждение, если встречает неправильные или неполные теги.
<?php $string = "<b>Bold text</b> <i>Italic text</i>"; $str = strip_tags($string);
// удаляем все теги из строки $str1 = strip_tags($string, '<b>'); // удаляем все теги кроме тега <b> $str2 = strip_tags($string, '<i>'); // удаляем все теги кроме тегов <i> echo $str,"<br>",$str1,"<br>", $str2; ?>
Пример 8.6. Использование функции strip_tags()
В результате получим:
Bold text Italic text
Bold text Italic text
Bold text Italic text

Приведем другой пример использования функции substr() . Допустим, у нас есть какое-то сообщение с приветствием и подписью автора. Мы хотим удалить сначала приветствие, а потом и подпись, оставив только содержательную часть сообщения.
<?php $text = "Привет! Сегодня мы изучаем работу со строками. Автор."; $no_hello = substr($text, 8); // убираем приветствие $content = substr($text, 8, 38); // то же самое, что substr($text, 8, -6). // Убираем подпись. echo $text, "<br>", $no_hello, "<br>", $content; ?>
В результате получим:
Привет! Сегодня мы изучаем работу со строками. Автор.
Сегодня мы изучаем работу со строками. Автор.
Сегодня мы изучаем работу со строками.

Если нам нужно получить один конкретный символ из строки, зная его порядковый номер, то не следует задействовать функции типа substr . Можно воспользоваться более простым синтаксисом – записывая номер символа в фигурных скобках после имени строковой переменной. В контексте предыдущего примера букву " р ", расположенную второй по счету, можно получить так:
echo $text{1}; // выведет символ "р"
Заметим, что номером этого символа является число один, а не два, так как нумерация символов строки производится начиная с нуля.
Раз уж мы начали говорить о символах в строке и их нумерации, то невольно возникает вопрос, сколько всего символов в строке и как это вычислить. Число символов в строке – это длина строки . Вычислить длину строки можно с помощью функции strlen (строка) . Например, длина строки "Разработка информационной модели" вычисляется с помощью команды: strlen ("Разработка информационной модели"); и равна 32 символам.
Итак, как выделять и находить подстроки, мы рассмотрели. Теперь научимся заменять строку, входящую в состав исходной строки, на другую строку по нашему выбору.
В дистрибутив PHP входит расширение, содержащее встроенные функции для работы с базой данных MySQL. В этой лекции мы познакомимся с некоторыми основными функциями для работы с MySQL, которые потребуются для решения задач построения web-интерфейсов с целью отображения и наполнения базы данных. Возникает вопрос, зачем строить такие интерфейсы? Для того чтобы вносить информацию в базу данных и просматривать ее содержимое могли люди, не знакомые с языком запросов SQL. При работе с web-интерфейсом для добавления информации в базу данных человеку нужно просто ввести эти данные в html-форму и отправить их на сервер, а наш скрипт сделает все остальное. А для просмотра содержимого таблиц достаточно просто щелкнуть по ссылке и зайти на нужную страницу.
Для наглядности будем строить эти интерфейсы для таблицы Artifacts, в которой содержится информация об экспонатах виртуального музея информатики. В предыдущей лекции мы уже приводили структуру этой коллекции, а также ее связи с коллекциями описания персон (Persons) и изображений (Images). Напомним, что каждый экспонат в коллекции Artifacts описывается с помощью следующих характеристик:
  • название (title);
  • автор (author);
  • описание (description);
  • альтернативное название (alternative);
  • изображение (photo).
Название и альтернативное название являются строками менее чем 255 символов длиной (т.е. имеют тип VARCHAR(255)), описание - текстовое поле (имеет тип TEXT), а в полях "автор" и "изображение" содержатся идентификаторы автора из коллекции Persons и изображения экспоната из коллекции Images соответственно.

Построение интерфейса для добавления информации

Итак, у нас есть какая-то таблица в базе данных. Чтобы построить интерфейс для добавления информации в эту таблицу, нужно ее структуру (т.е. набор ее полей) отобразить в html-форму.
Разобьем эту задачу на следующие подзадачи:
  • установка соединения с БД ;
  • выбор рабочей БД ;
  • получение списка полей таблицы ;
  • отображение полей в html-форму.
После этого данные, введенные в форму, нужно записать в базу данных. Рассмотрим все эти задачи по порядку.

Установка соединения

Итак, первое, что нужно сделать, - это установить соединение с базой данных. Воспользуемся функцией mysql_connect.
Синтаксис mysql_connect
ресурс mysql_connect ( [строка server [, строка username [, строка password [, логическое new_link [, целое client_flags]]]]])
Данная функция устанавливает соединение с сервером MySQL и возвращает указатель на это соединение или FALSE в случае неудачи. Для отсутствующих параметров устанавливаются следующие значения по умолчанию:
server = 'localhost:3306' username = имя пользователя владельца процесса сервера password = пустой пароль
Если функция вызывается дважды с одними и теми же параметрами, то новое соединение не устанавливается, а возвращается ссылка на старое соединение. Чтобы этого избежать, используют параметр new_link, который заставляет в любом случае открыть еще одно соединение.
Параметр client_flags - это комбинация следующих констант: MYSQL_CLIENT_COMPRESS (использовать протокол сжатия), MYSQL_CLIENT_IGNORE_SPACE (позволяет вставлять пробелы после имен функций), MYSQL_CLIENT_INTERACTIVE (ждать interactive_timeout секунд - вместо wait_timeout - до закрытия соединения).
Параметр new_link появился в PHP 4.2.0, а параметр client_flags - в PHP 4.3.0.
Соединение с сервером закрывается при завершении исполнения скрипта, если оно до этого не было закрыто с помощью функции mysql_close().
Итак, устанавливаем соединение с базой данных на локальном сервере для пользователя nina с паролем "123":
<? $conn = mysql_connect( "localhost", "nina","123") or die("Невозможно установить соединение: ". mysql_error()); echo "Соединение установлено"; mysql_close($conn); ?>
Действие mysql_connect равносильно команде
shell>mysql -u nina -p123

Выбор базы данных

После установки соединения нужно выбрать базу данных, с которой будем работать. Наши данные хранятся в базе данных book. В MySQL выбор базы данных осуществляется с помощью команды use:
mysql>use book;
В PHP для этого существует функция mysql_select_db.
Синтаксис mysql_select_db:
логическое mysql_select_db ( строка database_name [, ресурс link_identifier])
Эта функция возвращает TRUE в случае успешного выбора базы данных и FALSE - в противном случае.
Сделаем базу данных book рабочей:
<? $conn = mysql_connect( "localhost","nina","123") or die("Невозможно установить соединение: ". mysql_error()); echo "Соединение установлено"; mysql_select_db("book"); ?>

Получение списка полей таблицы

Теперь можно заняться собственно решением задачи. Как получить список полей таблицы? Очень просто. В PHP и на этот случай есть своя команда - mysql_list_fields.
Синтаксис mysql_list_fields
ресурс mysql_list_fields ( строка database_name, строка table_name [, ресурс link_identifier])
Эта функция возвращает список полей в таблице table_name в базе данных database_name. Получается, что выбирать базу данных нам было необязательно, но это пригодится позже. Как можно заметить, результат работы этой функции - переменная типа ресурс. То есть это не совсем то, что мы хотели получить. Это ссылка, которую можно использовать для получения информации о полях таблицы, включая их названия, типы и флаги.
Функция mysql_field_name возвращает имя поля, полученного в результате выполнения запроса. Функция mysql_field_len возвращает длину поля. Функция mysql_field_type возвращает тип поля, а функция mysql_field_flags возвращает список флагов поля, записанных через пробел. Типы поля могут быть int, real, string, blob и т.д. Флаги могут быть not_null, primary_key, unique_key, blob, auto_increment и т.д.

Синтаксис у всех этих команд одинаков:
строка mysql_field_name ( ресурс result, целое field_offset)
строка mysql_field_type ( ресурс result, целое field_offset)
строка mysql_field_flags ( ресурс result, целое field_offset)
строка mysql_field_len ( ресурс result, целое field_offset)
Здесь result - это идентификатор результата запроса (например, запроса, отправленного функциями mysql_list_fields или mysql_query (о ней будет рассказано позднее)), а field_offset - порядковый номер поля в результате.
Вообще говоря, то, что возвращают функции типа mysql_list_fields или mysql_query, представляет собой таблицу, а точнее, указатель на нее. Чтобы получить из этой таблицы конкретные значения, нужно задействовать специальные функции, которые построчно читают эту таблицу. К таким функциям и относятся mysql_field_name и т.п. Чтобы перебрать все строки в таблице результата выполнения запроса, нужно знать число строк в этой таблице. Команда mysql_num_rows (ресурс result ) возвращает число строк во множестве результатов result.
А теперь попробуем получить список полей таблицы Artifacts (коллекция экспонатов).
<? $conn = mysql_connect( "localhost","nina","123") or die("Невозможно установить соединение: ". mysql_error()); echo "Соединение установлено"; mysql_select_db("book"); $list_f = mysql_list_fields ( "book","Artifacts",$conn); $n = mysql_num_fields($list_f); for($i=0;$i<$n; $i++){ $type = mysql_field_type($list_f, $i); $name_f = mysql_field_name($list_f,$i); $len = mysql_field_len($list_f, $i); $flags_str = mysql_field_flags ( $list_f, $i); echo "<br>Имя поля: ". $name_f; echo "<br>Тип поля: ". $type; echo "<br>Длина поля: ". $len; echo "<br>Строка флагов поля: ".
$flags_str . "<hr>"; } ?>
В результате должно получиться примерно вот что (если в таблице всего два поля, конечно):
Имя поля: id Тип поля: int Длина поля: 11 Строка флагов поля: not_null primary_key auto_increment
_________________________________________________
Имя поля: title
Тип поля: string
Длина поля: 255
Строка флагов поля:

Отображение списка полей в html-форму

Теперь немножко подкорректируем предыдущий пример. Будем не просто выводить информацию о поле, а отображать его в подходящий элемент html-формы. Так, элементы типа BLOB переведем в textarea (заметим, что поле description, которое мы создавали с типом TEXT, отображается как имеющее тип BLOB ), числа и строки отобразим в текстовые строки ввода <input type=text>, а элемент, имеющий метку автоинкремента, вообще не будем отображать, поскольку его значение устанавливается автоматически.
Все это решается довольно просто, за исключением выделения из списка флагов флага auto_increment. Для этого нужно воспользоваться функцией explode.
Синтаксис explode:
массив explode( строка separator, строка string [, int limit])
Эта функция разбивает строку string на части с помощью разделителя separator и возвращает массив полученных строк.
В нашем случае в качестве разделителя нужно взять пробел " ", а в качестве исходной строки для разбиения - строку флагов поля.

Итак, создадим форму для ввода данных в таблицу Artifacts:

<? $conn=mysql_connect("localhost","nina","123"); // устанавливаем соединение $database = "book"; $table_name = "Artifacts"; mysql_select_db($database); // выбираем базу данных для // работы $list_f = mysql_list_fields($database,$table_name);
// получаем список полей в таблице $n = mysql_num_fields($list_f); // число строк в результате // предыдущего запроса (т.е. сколько всего // полей в таблице Artifacts) echo "<form method=post action=insert.php>"; // создаем форму для ввода данных echo "&nbsp;<TABLE BORDER=0 CELLSPACING=0 width=50% ><tr> <TD BGCOLOR='#005533' align=center><font color='#FFFFFF'> <b> Add new row in $table_name</b></font></td></tr><tr><td></td></tr></TABLE>"; echo "<table border=0 CELLSPACING=1 cellpadding=0 width=50% >"; // для каждого поля получаем его имя, тип, длину и флаги for($i=0;$i<$n; $i++){ $type = mysql_field_type($list_f, $i); $name_f = mysql_field_name ($list_f,$i); $len = mysql_field_len($list_f, $i); $flags_str = mysql_field_flags ($list_f, $i); // из строки флагов делаем массив, // где каждый элемент массива - флаг поля $flags = explode(" ", $flags_str); foreach ($flags as $f){ if ($f == 'auto_increment') $key = $name_f; // запоминаем имя автоинкремента } /* для каждого поля, не являющегося автоинкрементом, в зависимости от его типа выводим подходящий элемент формы */ if ($key <> $name_f){ echo "<tr><td align=right bgcolor='#C2E3B6'><font size=2> <b>&nbsp;". $name_f ."</b></font></td>"; switch ($type){ case "string": $w = $len/5; echo "<td><input type=text name=\"$name_f\" size = $w ></td>"; break; case "int": $w = $len/4; echo "<td><input type=text name=\"$name_f\" size = $w ></td>"; break; case "blob": echo "<td><textarea rows=6 cols=60 name=\"$name_f\"></textarea></td>"; break; } } echo "</tr>"; } echo "</table>"; echo "<input type=submit name='add' value='Add'>"; echo "</form>"; ?> Листинг 11.0.1. Форма для ввода данных в таблицу Artifacts

Запись данных в базу данных

Итак, форма создана. Теперь нужно сделать самое главное - отправить данные из этой формы в нашу базу данных. Как вы уже знаете, для того чтобы записать данные в таблицу, используется команда INSERT языка SQL. Например:
mysql> INSERT INTO Artifacts SET title='Петров';
Возникает вопрос, как можно воспользоваться такой командой (или любой другой командой SQL) в PHP скрипте. Для этого существует функция mysql_query().
Синтаксис mysql_query
ресурс mysql_query ( строка query [, ресурс link_identifier])
mysql_query() посылает SQL-запрос активной базе данных MySQL сервера, который определяется с помощью указателя link_identifier (это ссылка на какое-то соединение с сервером MySQL ). Если параметр link_identifier опущен, используется последнее открытое соединение. Если открытые соединения отсутствуют, функция пытается соединиться с СУБД, аналогично функции mysql_connect() без параметров. Результат запроса буферизируется.

Замечание: строка запроса НЕ должна заканчиваться точкой с запятой.

Только для запросов SELECT, SHOW, EXPLAIN, DESCRIBE, mysql_query() возвращает указатель на результат запроса, или FALSE, если запрос не был выполнен. В остальных случаях mysql_query() возвращает TRUE, если запрос выполнен успешно, и FALSE - в случае ошибки. Значение, не равное FALSE, говорит о том, что запрос был выполнен успешно. Оно не говорит о количестве затронутых или возвращенных рядов. Вполне возможна ситуация, когда успешный запрос не затронет ни одного ряда. mysql_query() также считается ошибочным и вернет FALSE, если у пользователя недостаточно прав для работы с указанной в запросе таблицей.
Итак, теперь мы знаем, как отправить запрос на вставку строк в базу данных. Заметим, что в предыдущем примере элементы формы мы назвали именами полей таблицы. Поэтому они будут доступны в скрипте insert.php, обрабатывающем данные формы, как переменные вида $_POST['имя_поля'].
<? $conn=mysql_connect("localhost","nina","123");// устанавливаем // соединение $database = "book"; $table_name = "Artifacts"; mysql_select_db($database); // выбираем базу данных $list_f = mysql_list_fields($database,$table_name); // получаем список полей в таблице $n = mysql_num_fields($list_f); // число строк в результате // предыдущего запроса // составим один запрос сразу для всех полей таблицы $sql = "INSERT INTO $table_name SET "; // начинаем создавать// запрос, перебираем все поля таблицы for($i=0;$i<$n; $i++){ $name_f = mysql_field_name ($list_f,$i); // вычисляем имя поля $value = $_POST[$name_f]; // вычисляем значение поля $j = $i + 1; $sql = $sql . $name_f." = '$value'"; // дописываем в // строку $sql пару имя=значение if ($j <> $n) $sql = $sql . ", "; // если поле не // последнее в списке, то ставим запятую } // перед тем как записывать что-то в базу, // можно посмотреть, какой запрос получился //echo $sql; $result = mysql_query($sql,$conn); // отправляем запрос // выводим сообщение успешно ли выполнен запрос if (!$result) echo " Can't add ($table_name) "; else echo "Success!<br>"; ?> Листинг 11.0.2. insert.php

Итак, задачу добавления данных с помощью web-интерфейса мы решили. Однако тут есть одна тонкость. При решении мы не учитывали тот факт, что значения некоторых полей ( author, photo ) должны браться из других таблиц ( Persons, Images ). Поскольку MySQL с внешними ключами не работает (уже работает - прим. эксперта), этот момент остается на совести разработчиков системы, т.е. на нашей совести. Нужно дописать программу таким образом, чтобы была возможность вводить в такие поля правильные значения. Но мы делать этого не будем, поскольку задача лекции состоит в том, чтобы познакомить читателя с элементами технологии, а не в том, чтобы создать работающую систему. Кроме того, имеющихся у читателя знаний вполне достаточно, чтобы решить эту проблему самостоятельно. Мы же обратимся к другой задаче - отображение данных, хранящихся в базе данных СУБД MySQL.
Отображение данных, хранящихся в MySQL
Чтобы отобразить какие-то данные в браузере с помощью PHP, нужно сначала получить эти данные в виде переменных PHP. При работе с MySQL без посредника (такого, как PHP) выборка данных производится с помощью команды SELECT языка SQL:
mysql> SELECT * FROM Artifacts;

В предыдущей главе мы говорили, что любой запрос, в том числе и на выборку, можно отправить на сервер с помощью функции mysql_query() ; Там у нас стояла немного другая задача - получить данные из формы и отправить их с помощью запроса на вставку в базу данных. Результатом работы mysql_query() там могло быть только одно из выражений, TRUE или FALSE. Теперь же требуется отправить запрос на выбор всех полей, а результат отобразить в браузере. И здесь результат - это целая таблица значений, а точнее, указатель на эту таблицу. Так что нужны какие-то аналоги функции mysql_field_name(), только чтобы они извлекали из результата запроса не имя, а значение поля. Таких функций в PHP несколько. Наиболее популярные - mysql_result() и mysql_fetch_array().


Синтаксис mysql_result
смешанное mysql_result (ресурс result, целое row [, смешанное field]) mysql_result() возвращает значение одной ячейки результата запроса. Аргумент field может быть порядковым номером поля в результате, именем поля или именем поля с именем таблицы через точку tablename.fieldname. Если для имени поля в запросе применялся алиас ('select foo as bar from...'), используйте его вместо реального имени поля.
Работая с большими результатами запросов, следует задействовать одну из функций, обрабатывающих сразу целый ряд результата (например, mysql_fetch_row(), mysql_fetch_array() и т.д.). Так как эти функции возвращают значение нескольких ячеек сразу, они НАМНОГО быстрее mysql_result(). Кроме того, нужно учесть, что указание численного смещения (номера поля) работает намного быстрее, чем указание колонки или колонки и таблицы через точку.
Вызовы функции mysql_result() не должны смешиваться с другими функциями, работающими с результатом запроса.
Синтаксис mysql_fetch_array
массив mysql_fetch_array ( ресурс result [, целое result_type])
Эта функция обрабатывает ряд результата запроса, возвращая массив (ассоциативный, численный или оба) с обработанным рядом результата запроса, или FALSE, если рядов больше нет.
mysql_fetch_array() - это расширенная версия функции mysql_fetch_row(). Помимо хранения значений в массиве с численными индексами, функция возвращает значения в массиве с индексами по названию колонок.
Если несколько колонок в результате будут иметь одинаковые названия, будет возвращена последняя колонка. Чтобы получить доступ к первым, следует использовать численные индексы массива или алиасы в запросе. В случае алиасов именно их вы не сможете использовать в именах колонок, как, например, не сможете использовать "photo" в описанном ниже примере.
select Artifacts.photo as art_image, Persons.photo as pers_image from Artifacts, Persons 11.1. Запрос с дублирующимися именами колонок Важно заметить, что mysql_fetch_array() работает НЕ медленнее, чем mysql_fetch_row(), и предоставляет более удобный доступ к данным. Второй опциональный аргумент result_type в функции mysql_fetch_array() является константой и может принимать следующие значения: MYSQL_ASSOC, MYSQL_NUM и MYSQL_BOTH. Эта возможность добавлена в PHP 3.0.7. Значением по умолчанию является: MYSQL_BOTH.
Используя MYSQL_BOTH, получим массив, состоящий как из ассоциативных индексов, так и из численных. MYSQL_ASSOC вернет только ассоциативные соответствия, а MYSQL_NUM - только численные.
Замечание: имена полей, возвращаемые этой функцией, регистрозависимы.

Теперь отобразим данные из Artifacts в виде таблицы в браузере:

<? / * сначала делаем то же, что и раньше: устанавливаем соединение, выбираем базу и получаем список и число полей в таблице Artifacts */ $conn=mysql_connect("localhost","nina","123"); $database = "book"; $table_name = "Artifacts"; mysql_select_db($database); $list_f = mysql_list_fields($database,$table_name); $n1 = mysql_num_fields($list_f); // сохраним имена полей в массиве $names for($j=0;$j<$n1; $j++){ $names[] = mysql_field_name ($list_f,$j); } $sql = "SELECT * FROM $table_name"; // создаем SQL запрос $q = mysql_query($sql,$conn) or die(); // отправляем // запрос на сервер $n = mysql_num_rows($q); // получаем число строк результата //рисуем HTML-таблицу echo "&nbsp;<TABLE BORDER=0 CELLSPACING=0 width=90% align=center><tr><TD BGCOLOR='#005533' align=center> <font color='#FFFFFF'><b>$table_name</b></font></td> </tr></TABLE>"; echo "<table cellspacing=0 cellpadding=1 border=1 width=90% align=center>"; // отображаем названия полей echo "<tr>"; foreach ($names as $val){ echo "<th ALIGN=CENTER BGCOLOR='#C2E3B6'> <font size=2>$val</font></th>"; } // отображаем значения полей echo "</tr>"; for($i=0;$i<$n; $i++){ // перебираем все строки в // результате запроса на выборку echo "<tr>"; foreach ($names as $val) { // перебираем все // имена полей $value = mysql_result($q,$i,$val); // получаем // значение поля echo "<td><font size=2>&nbsp;$value</font></td>"; // выводим значение поля } echo "</tr>"; }
echo "</table>"; Листинг 11.1.1. Отображение данных из Artifacts в виде таблицы в браузере

Сделаем то же самое с помощью mysql_fetch_array():

<? /* ... начало то же, что и в предыдущем примере */ // отображаем значения полей // получаем значение поля в виде ассоциативного массива while($row = mysql_fetch_array($q, MYSQL_ASSOC)) { echo "<tr>"; foreach ($names as $val){ echo "<td><font size=2>&nbsp;$row[$val]</font></td>"; // выводим значение поля } echo "</tr>"; } echo "</table>"; ?> Листинг 11.1.2. Отображение данных из Artifacts в виде таблицы в браузере. Вариант 2
Дополнительная литература:
обложка книги
Книгу можно скачать на этом сайте:
library-it.com
4 МОДУЛЬ

Обеспечение безопасности web-приложений.

Тема 1. Безопасность базы данных
Основной формой организации информационных массивов в ИС являются базы данных. Базу данных можно определить как совокупность взаимосвязанных хранящихся вместе данных при наличии такой минимальной избыточности, которая допускает их использование оптимальным образом для одного или нескольких приложений. В отличие от файловой системы организации и использования информации, БД существует независимо от конкретной программы и предназначена для совместного использования многими пользователями. Такая централизация и независимость данных в технологии БД потребовали создания соответствующих СУБД - сложных комплексов программ, которые обеспечивают выполнение операций корректного размещения данных, надежного их хранения, поиска, модификации и удаления.
Основные требования по безопасности данных, предъявляемые к БД и СУБД, во многом совпадают с требованиями, предъявляемыми к безопасности данных в компьютерных системах – контроль доступа, криптозащита, проверка целостности, протоколирование и т. д.
Под управлением целостностью в БД понимается защита данных в БД от неверных (в отличие от несанкционированных) изменений и разрушений. Поддержание целостности БД состоит в том, чтобы обеспечить в каждый момент времени корректность (правильность) как самих значений всех элементов данных, так и взаимосвязей между элементами данных в БД. С поддержанием целостности связаны следующие основные требования.
Обеспечение достоверности. В каждый элемент данных информация заносится точно в соответствии с описанием этого элемента. Должны быть предусмотрены механизмы обеспечения устойчивости элементов данных и их логических взаимосвязей к ошибкам или неквалифицированным действиям пользователей.
Управление параллелизмом. Нарушение целостности БД может возникнуть при одновременном выполнении операций над данными, каждая из которых в отдельности не нарушает целостности БД. Поэтому должны быть предусмотрены механизмы управления данными, обеспечивающие поддержание целостности БД при одновременном выполнении нескольких операций.
Восстановление. Хранимые в БД данные должны быть устойчивы по отношению к неблагоприятным физическим воздействиям (аппаратные ошибки, сбои питания и т. п.) и ошибкам в программном обеспечении. Поэтому должны быть предусмотрены механизмы восстановления за предельно короткое время того состояния БД, которое было перед появлением неисправности.
Вопросы управления доступом и поддержания целостности БД тесно соприкасаются между собой, и во многих случаях для их решения используются одни и те же механизмы. Различие между этими аспектами обеспечения безопасности данных в БД состоит в том, что управление доступом связано с предотвращением преднамеренного разрушения БД, а управление целостностью - с предотвращением непреднамеренного внесения ошибки.
Управление доступом
Большинство систем БД представляют собой средство единого централизованного хранения данных. Это значительно сокращает избыточность данных, упрощает доступ к данным и позволяет более эффективно защищать данные. Однако, в технологии БД возникает ряд проблем, связанных, например, с тем, что различные пользователи должны иметь доступ к одним данным и не иметь доступа к другим. Поэтому, не используя специальные средства и методы, обеспечить надежное разделение доступа в БД практически невозможно.
Большинство современных СУБД имеют встроенные средства, позволяющие администратору системы определять права пользователей по доступу к различным частям БД, вплоть до конкретного элемента. При этом имеется возможность не только предоставить доступ тому или иному пользователю, но и указать разрешенный тип доступа. Что именно может делать конкретный пользователь с конкретными данными (читать, модифицировать, удалять и т. п.), вплоть до реорганизации всей БД Таблицы (списки) управления доступом широко используются в компьютерных системах, например, в ОС для управления доступом к файлам. Особенность использования этого средства для защиты БД состоит в том, что в качестве объектов защиты выступают не только отдельные файлы (области в сетевых БД, отношения в реляционных БД), но и другие структурные элементы БД: элемент, поле, запись, набор данных.
Управление целостностью данных
Нарушение целостности данных может быть вызвано рядом причин:
сбои оборудования, физические воздействия или стихийные бедствия;
ошибки санкционированных пользователей или умышленные действия несанкционированных пользователей;
программные ошибки СУБД или ОС;
ошибки в прикладных программах;
совместное выполнение конфликтных запросов пользователей и др.
Нарушение целостности данных возможно и в хорошо отлаженных системах. Поэтому важно не только не допустить нарушения целостности, но и своевременно обнаружить факт нарушения целостности и оперативно восстановить целостность после нарушения.
Управление параллелизмом
Поддержание целостности на основе приведенных выше ограничений целостности представляет собой достаточно сложную проблему в системе БД даже с одним пользователем. В системах, ориентированных на многопользовательский режим работы, возникает целый ряд новых проблем, связанных с параллельным выполнением конфликтующих запросов пользователей. Прежде, чем рассмотреть механизмы защиты БД от ошибок, возникающих в случае конфликта пользовательских запросов, раскроем ряд понятий, связанных с управлением параллелизмом.
Важнейшим средством механизма защиты целостности БД выступает объединение совокупности операций, в результате которых БД из одного целостного состояния переходит в другое целостное состояние, в один логический элемент работы, называемый транзакцией. Суть механизма транзакций состоит в том, что до завершения транзакции все манипуляции с данными проводятся вне БД, а занесение реальных изменений в БД производится лишь после нормального завершения транзакции.
С точки зрения безопасности данных такой механизм отображения изменений в БД очень существенен. Если транзакция была прервана, то специальные встроенные средства СУБД осуществляют так называемый откат - возврат БД в состояние, предшествующее началу выполнения транзакции (на самом деле откат обычно заключается просто в невыполнении изменений, обусловленных ходом транзакции, в физической БД). Если выполнение одной транзакции не нарушает целостности БД, то в результате одновременного выполнения нескольких транзакций целостность БД может быть нарушена. Чтобы избежать подобного рода ошибок, СУБД должна поддерживать механизмы, обеспечивающие захват транзакциями модифицируемых элементов данных до момента завершения модификации, так называемые блокировки. При этом гарантируется, что никто не получит доступа к модифицируемому элементу данных, пока транзакция не освободит его. Применение механизма блокировок приводит к новым проблемам управления параллелизмом, в частности, к возникновению ситуаций клинча двух транзакций. Причем, если некоторая транзакция пытается блокировать объект, который уже блокирован другой транзакцией, то ей придется ждать, пока не будет снята блокировка объекта транзакцией, установившей эту блокировку. Иными словами, блокировку объекта может выполнять только одна транзакция.
Восстановление данных
Как уже отмечалось, возникновение сбоев в аппаратном или программном обеспечении может вызвать необходимость восстановления и быстрого возвращения в состояние, по возможности близкое к тому, которое было перед возникновением сбоя (ошибки). К числу причин, вызывающих необходимость восстановления, зачастую относится и возникновение тупиковой ситуации.
Можно выделить три основных уровня восстановления:
Оперативное восстановление, которое характеризуется возможностью восстановления на уровне отдельных транзакций при ненормальном окончании ситуации манипулирования данными (например, при ошибке в программе).
Промежуточное восстановление. Если возникают аномалии в работе системы (системно-программные ошибки, сбои программного обеспечения, не связанные с разрушением БД), то требуется восстановить состояние всех выполняемых на момент возникновения сбоя транзакций.
Длительное восстановление. При разрушении БД в результате дефекта на диске восстановление осуществляется с помощью копии БД. Затем воспроизводят результаты выполненных с момента снятия копии транзакций и возвращают систему в состояние на момент разрушения.
Транзакция и восстановление
Прекращение выполнения транзакции вследствие появления сбоя нарушает целостность БД. Если результаты такого выполнения транзакции потеряны, то имеется возможность их воспроизведения на момент возникновения сбоя. Таким образом, понятие транзакции играет важную роль при восстановлении. Для восстановления целостности БД транзакции должны удовлетворять следующим требованиям:
необходимо, чтобы транзакция или выполнялась полностью, или не выполнялась совсем;
необходимо, чтобы транзакция допускала возможность возврата в первоначальное состояние, причем, для обеспечения независимого возврата транзакции в начальное состояние монопольную блокировку необходимо осуществлять до момента завершения изменения всех объектов;
необходимо иметь возможность воспроизведения процесса выполнения транзакции, причем, для обеспечения этого требования, совместную блокировку необходимо осуществлять до момента завершения просмотра данных всеми транзакциями.
В процессе выполнения любой транзакции наступает момент ее завершения. При этом все вычисления, сделанные транзакцией в ее рабочей области, должны быть закончены, копия результатов ее выполнения должна быть записана в системный журнал. Подобные действия называют операцией фиксации. При появлении сбоя целесообразнее осуществлять возврат не в начало транзакции, а в некоторое промежуточное положение. Точку, куда происходит такой возврат, называют точкой фиксации (контрольной точкой). Пользователь может установить в процессе выполнения транзакции произвольное количество таких точек. Если в ходе выполнения транзакции достигается точка фиксации, то СУБД автоматически осуществляет указанную выше операцию.
Откат и раскрутка транзакции
Основным средством, используемым при восстановлении, является системный журнал, в котором регистрируются все изменения, вносимые в БД каждой транзакцией. Возврат транзакции в начальное состояние состоит в аннулировании всех изменений, которые осуществлены в процессе выполнения транзакции. Такую операцию называют откатом. Для воспроизведения результатов выполнения транзакции можно, используя системный журнал, восстановить значения проведенных изменений в порядке их возникновения, либо выполнить транзакцию повторно. Воспроизведение результатов выполнения транзакции с использованием системного журнала называется раскруткой. Раскрутка является достаточно сложной, но необходимой операцией механизмов восстановления современных БД.

Тема 2. Безопасность клиентских приложений
Когда речь заходит об обеспечении безопасности пользователей корпоративной сети при доступе в Internet, в первую очередь все вспоминают о средствах защиты периметра — межсетевых экранах (вкупе с подключаемыми антивирусными программами и системами контроля контента) и системах обнаружения атак. Затем задумываются о всевозможных средствах защиты для электронной почты: тех же антивирусах, системах контроля контента и еще каких-либо системах борьбы со спамом.
Бесспорно, это важные элементы защиты, но ограничиваться ими не следует. Ведь данные не только проходят через межсетевой экран, не только аккумулируются на почтовых серверах и кэширующих proxy-серверах. Если средства контроля контента установлены и настроены правильно, с их помощью удастся избежать немалой части угроз, которые может нести в себе HTML-код, составленный неизвестно кем. Но для этого такие средства как минимум должны быть приобретены, а в идеале — безупречно настроены, чтобы можно было извлечь максимум из заложенных в них возможностей.
Между тем в конечном счете и Web-страницы, и письма в формате HTML попадают на компьютеры пользователей и обрабатываются именно там, причем в 95% случаев для отображения данных в формате HTML используется движок Internet Explorer. В основном именно о его настройках и пойдет речь.
Итак, давайте поговорим:
о параметрах отображения HTML-страниц в Internet Explorer (на примере версии 6.0) и писем в формате HTML в Microsoft Outlook (на примере Microsoft Office Outlook 2003);
о различиях в настройке параметров отображения HTML для разных зон и об управлении составом зон;
о лишении пользователей возможности изменять настройки, которые для них установлены централизованно.
Как известно, средством централизованной настройки этих (и многих других) параметров в среде Active Directory являются групповые политики.
Настройка параметров отображения HTML и состава зон:

таблица
Это диалоговое окно, знакомо всем, кто хоть раз просматривал параметры Internet Explorer. Здесь для каждой из предлагаемых зон (Internet, Restricted Sites, Trusted Sites, Local Intranet) можно настраивать параметры отображения страниц: включать и отключать сценарии, cookies, компоненты ActiveX и .NET Framework, Java-апплеты, осуществлять загрузку элементов страницы из других доменов и т. п. Чтобы увидеть весь перечень, достаточно нажать кнопку Custom
таблица
Этот перечень меняется от версии к версии Internet Explorer, но все элементы, которые в нем фигурируют, подробно описаны в специальной литературе, и мы не будем останавливаться на них в данной статье. Есть предопределенные варианты настроек, соответствующие большему или меньшему уровню доверия содержимому страницы, — High, Medium, Medium-low и Low. По умолчанию, эти настройки установлены для зон Restricted Sites, Internet, Trusted Sites и Local Intranet соответственно.
В зону Internet по умолчанию попадают все сайты, которые явным образом не указаны в списках сайтов для зон Restricted Sites (Ограниченные узлы), Trusted Sites (Доверенные узлы) и Local Intranet (местная интрасет).
Мы привыкли устанавливать эти настройки на своем компьютере локально, через Internet Explorer (меню Tools — Internet Options). Но можно установить их централизованно, через групповые политики: ветвь User Configuration — Internet Explorer Maintenance — Security, параметр Security Zones and Content Rating

таблица
Если в данном объекте групповой политики этот параметр задан не был, настройки копируются с того компьютера, на котором запущен редактор групповой политики. После этого можно их изменить: при нажатии кнопки Modify отображается то же самое диалоговое окно настроек. В групповой политике можно указывать и параметры отображения, и списки сайтов (как тех, которым оказано особое доверие, входящих в зоны Trusted Sites и Local Intranet, так и тех, которым выражено явное недоверие, — зона Restricted Sites). Какие настройки для каких зон устанавливать и какие сайты в какие зоны включать, решается в зависимости от ситуации. Что касается настроек отображения, то здесь разумными представляются те соображения, которыми, по-видимому, руководствовались разработчики Windows Server 2003 Internet Explorer Enhanced Security.
Поскольку в зону Internet попадают по умолчанию все сайты, среди них могут оказаться и сайты, об угрозе со стороны которых мы просто не знаем, то есть сайты, чьи страницы могут содержать вредоносный код. Если оставить параметры по умолчанию, этот код запустится: настройки отображения предопределенного уровня Medium допускают отображение и исполнение активных компонентов. А методы социальной инженерии, которые могут применять злоумышленники для того, чтобы заманить пользователя на такую страницу, еще никто не отменял. Поэтому, чтобы застраховаться от подобных ситуаций, разумно для зоны Internet, как и для зоны Restricted Sites, установить настройки отображения предопределенного уровня High, в котором весь активный контент отключен, равно как и любые сценарии.
Точно так же Internet Explorer Enhanced Security чуть меньше доверия по сравнению с параметрами по умолчанию оказывает и тем сайтам, которые мы не считаем чужими и поэтому включили в зоны Trusted Sites и Local Intranet. Для зоны Trusted Sites установлен уровень Medium, а для зоны Local Intranet — Medium Low. Эти настройки позволяют относительно комфортно взаимодействовать с сайтами, содержащими активный контент. Остается решить, какие сайты включать в зоны Restricted Sites, Trusted Sites и Local Intranet.
По поводу зоны Restricted Sites надо сказать, что если и для зоны Internet, и для зоны Restricted Sites параметры отображения одинаково жесткие, то и список сайтов зоны Restricted Sites можно оставить пустым.
К сожалению, разработчики сайтов, в том числе и вполне благонадежных, любят активные компоненты — они позволяют добавлять всевозможные визуальные эффекты, которые Web-мастерам кажутся уместными (и в некоторых случаях так оно и есть). Смотреть такие сайты с параметрами отображения уровня защиты High иногда бывает просто невозможно. Подобные сайты нужно включать в список Trusted Sites. Причем наполнение списка Trusted Sites тоже целесообразно вести централизованно, по заявкам пользователей, разработав соответствующую бюрократическую процедуру. При наследовании групповых политик этот список, равно как и весь набор настроек отображения HTML-страниц, замещается целиком, поэтому для разных пользователей можно составлять различные списки, включив пользователей в разные организационные подразделения (OU) и привязав к этим подразделениям разные объекты групповых политик, где настройки безопасности Internet включают разные списки.
Что касается зоны Local Intranet, то, как видно из названия, задумывалась эта зона для сайтов внутренней сети. Другой вопрос, насколько мы доверяем всем сайтам внутренней сети. А доверять им следует только в той степени, в какой мы в состоянии взаимодействовать с персоналом, поддерживающим данный сайт. В сети небольшой организации, где все друг друга знают, можно спокойно включать все сайты внутренней сети в этот список. В большой же сети такое взаимодействие может быть затруднено в силу организационных проблем. Напр имер, если имеется филиал в другом городе и с персоналом этого филиала можно оперативно общаться только по телефону, электронной почте или через службу мгновенных сообщений. Компьютеры сети филиала могут оказаться заражены вирусом через Internet независимо от сети головного офиса. Зачем же допускать риск подцепить от них этот вирус, если он внедрился на страницы их внутреннего сайта?
Поэтому в настройках Internet для филиала в список Local Intranet следует включить сайты внутренней сети филиала, а для головного офиса в список Local Intranet — сайты внутренней сети головного офиса. Сайты других подразделений можно включить в зону Trusted Sites, если с ними необходимо работать.
Еще раз хочу обратить внимание читателей на тот факт, что весь набор настроек, включая и параметры отображения, и списки сайтов в каждой из зон, хранится в объекте групповой политики как единый параметр, при наследовании групповых политик он замещается целиком. В то же время это один из немногих параметров, которые имеет смысл задавать на уровне групповой политики для сайта, так как в пределах каждой из территориальных локальных сетей, составляющих единую сеть организации, эти параметры, скорее всего, похожи. Все компьютеры территориальной локальной сети соединяются с Internet через один и тот же межсетевой экран.

Настройки отображения для почты
Кроме того, что параметры отображения HTML-страниц используются в Internet Explorer для отображения страниц, эти же параметры применяют Microsoft Outlook и Outlook Express: в их настройках можно указать, параметры какой зоны следует задействовать при отображении писем в HTML-формате (по умолчанию — Restricted Sites). Кроме того, до недавнего времени пользователям Outlook и Outlook Express много хлопот доставляло использование области предварительного просмотра, при отображении которой срабатывали все включенные в документ HTML-сценарии. Теперь этот недостаток устранен, но на случай использования более старых версий программ (и обнаружения новых уязвимых мест в механизме отображения IE новой версии) остаются актуальными две рекомендации: отключить область просмотра и отображать письма в формате HTML как текст. Также следует установить параметры, не подразумевающие автоматического открытия писем (при удалении просматриваемого письма, при открытии и т. п.), — существует возможность настроить программу таким образом, чтобы просто происходил возврат в папку Inbox.
Эти настройки (за исключением области предварительного просмотра) сохраняются в реестре компьютера, в разделе HKEY_CURRENT_USER, значит, их тоже можно настроить через групповые политики, используя административные шаблоны.
Для Office 2003 существует набор готовых административных шаблонов, которые можно применять для централизованного управления самыми разными параметрами входящих в состав пакета приложений, в том числе параметрами отображения в Outlook. Этот набор входит в состав пакета Office 2003 Resource Kit Tools, который можно загрузить с сайта Microsoft, как и аналогичные пакеты для предыдущих версий Office — 2000 и XP.
После установки пакета Office Resource Kit Tools можно, редактируя любой объект групповой политики, добавить в раздел User Configuration — Administrative Templates шаблон Outlk11.adm (для предыдущих версий Office — Outlk10.adm или Outlk9.adm). При этом наряду с другими добавляются параметры:
?User Configuration — Administrative Templates — Microsoft Office Outlook 2003 — Tools | Options... — Preferences — E-mail options — Message Handling: настройка возврата в папку Inbox;
?User Configuration — Administrative Templates — Microsoft Office Outlook 2003 — Tools | Options... — Preferences — E-mail options — Read email as plain text: настройка отображения писем в формате HTML как текста.
Другие параметры, добавляемые в этом административном шаблоне, соответствуют практически всем настройкам, доступным через окна настроек Outlook 2003, за исключением выбора зоны, параметры отображения HTML для которой используются при отображении писем в формате HTML. Этой доброй традиции Microsoft следует начиная с Resource Kit к Office 2000 (для Office 97 я просто не смотрел, да ведь в ту пору не было еще ни групповых политик, ни административных шаблонов). Поэтому для данной настройки требуется создать отдельный шаблон.
После его добавления появится настройка User Configuration — Administrative Templates — MS Outlook 2003 — Render HTML zone settings, в которой можно будет выбрать из списка один из двух вариантов: Internet или Restricted Sites. Несложная модификация этого шаблона позволит задействовать его и с другими версиями Microsoft Office (наименование раздела реестра должно соответствовать версии Office).

Блокировка окон настройки в пользовательском интерфейсе
Если пользователь будет иметь доступ к окнам настроек, он сможет изменить все настройки, которые установлены централизованно, ослабить все те ограничения, которые для него заданы, и тогда все наши централизованно установленные жесткие настройки не будут стоить ломаного гроша. Поскольку все параметры, о которых шла речь, настраиваются именно для пользователей, по умолчанию пользователи имеют доступ к их настройке.
Проще всего обстоит дело с параметрами Outlook, устанавливаемыми через шаблон Outlk11.adm: как только какие-то параметры установлены в групповой политике, они автоматически становятся недоступны для изменения в окне настройки. Это свойственно и предыдущим версиям Outlook, начиная с 2000. Кроме того, можно лишить пользователей и некоторых других возможностей в отношении самостоятельной настройки программы, а также использования отдельных небезопасных функций в ней, с помощью раздела того же административного шаблона Disable Items in User Interface.
Что касается параметра выбора зоны в Outlook 2003, то он в окне настройки остается доступным для изменения, но программа эти изменения игнорирует: при следующем вызове окна программа показывает значение параметра, установленное через групповую политику, а главное — руководствуется настройкой, заданной через групповую политику. Впрочем, такое поведение может прибавить хлопот сотрудникам, которые занимаются поддержкой пользователей и вынуждены объяснять удивленным коллегам причины столь странного поведения почтового клиента.
Если в отношении Outlook все ясно, то в Internet Explorer у пользователей остается возможность менять параметры безопасности и состав сайтов в зонах, добавляя все, что им заблагорассудится, в зону Trusted Sites. Этой возможности нужно пользователей лишить, изменив в групповой политике параметр User Configuration — Administrative Templates — Windows Components — Internet Explorer — Internet Control Panel — Disable the Security Page. Необходимо установить значение параметра Enabled, и в окне настроек Internet Explorer вкладка Security отображаться не будет. В этой же ветви групповой политики можно отключить и остальные вкладки окна настройки Internet Explorer, лишив тем самым пользователей возможности испортить настройки системы.
Заключение
Описанную технику нельзя считать панацеей от возможных действий злоумышленников из внешней сети. Она позволяет настроить только те функции защиты, которые встроены в Internet Explorer. Точно так же не является абсолютной защитой и самый современный межсетевой экран, оснащенный всеми возможностями для анализа контента. Но и пренебрегать данной методикой не стоит — в любом случае, это еще одна линия защиты.
Но как быть пользователям других программ для работы с Internet? Здесь существует несколько вариантов.
Если применяется другой браузер, использующий движок Internet Explorer, например MyIE или FlashPeak, то для него подойдут настройки, установленные так, как было описано выше.
Если используется программа, хранящая настройки в реестре, то для этих настроек придется либо обратиться к разработчикам, чтобы они изготовили соответствующий административный шаблон, либо разработать его своими силами, проведя некое исследование программы: какие настройки, в каком виде и как записываются в реестр.
К сожалению, для других популярных механизмов отображения (Opera и Netscape/Mozilla) данный подход не подойдет, так как эти программы хранят свои настройки не в реестре, а в файлах настроек. Для таких программ можно применить другой подход: распространять заранее подготовленные файлы настроек через сценарии входа пользователей.

Тема 3. Криптографические методы защиты информации

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

Криптография с открытыми ключами

Для решения задач распределения ключей и ЭЦП были использованы идеи асимметричности преобразований и открытого распределения ключей Диффи и Хеллмана. В результате была создана криптография с открытыми ключами, в которой используется не один секретный, а пара ключей: открытый (публичный) ключ и секретный (личный, индивидуальный) ключ, известный только одной взаимодействующей стороне. В отличие от секретного ключа, который должен сохраняться в тайне, открытый ключ может распространяться публично. На Рисунке 1 представлены два свойства систем с открытыми ключами, позволяющие формировать зашифрованные и аутентифицированные сообщения.

Два важных свойства криптографии с открытыми ключами




таблица
Рисунок 1 Два свойства криптографии с открытыми ключами

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

таблица
Рисунок 2 Схема шифрования в криптографии с открытыми ключами.

Реализация схемы ЭЦП связанна с вычислением хэш-функции (дайджеста) данных, которая представляет собой уникальное число, полученное из исходных данных путем его сжатия (свертки) с помощью сложного, но известного алгоритма. Хэш-функция является однонаправленной функцией, т.е. по хэш-значению невозможно восстановить исходные данные. Хэш-функция чувствительна к всевозможным искажениям данных. Кроме того, очень трудно отыскать два набора данных, обладающих одним и тем же значением хэш-функции.

Формирование ЭЦП с хэшированием

Схема формирования подписи ЭД его отправителем включает вычисление хэш-функции ЭД и шифрование этого значения посредством секретного ключа отправителя. Результатом шифрования является значение ЭЦП ЭД (реквизит ЭД), которое пересылается вместе с самим ЭД получателю. При этом получателю сообщения должен быть предварительно передан открытый ключ отправителя сообщения. 

таблица
Рисунок 3 Схема ЭЦП в криптографии с открытыми ключами.

Схема проверки (верификации) ЭЦП, осуществляемая получателем сообщения, состоит из следующих этапов. На первом из них производится расшифрование блока ЭЦП посредством открытого ключа отправителя. Затем вычисляется хэш-функция ЭД. Результат вычисления сравнивается с результатом расшифрования блока ЭЦП. В случае совпадения, принимается решение о соответствии ЭЦП ЭД. Несовпадение результата расшифрования с результатом вычисления хеш-функции ЭД может объясняться следующими причинами:
•    в процессе передачи по каналу связи была потеряна целостность ЭД;
•    при формировании ЭЦП был использован не тот (поддельный) секретный ключ;
•    при проверке ЭЦП был использован не тот открытый ключ (в процессе передачи по каналу связи или при дальнейшем его хранении открытый ключ был модифицирован или подменен).
Реализация криптографических алгоритмов с открытыми ключами (по сравнению с симметричными алгоритмами) требует больших затрат процессорного времени. Поэтому криптография с открытыми ключами обычно используется для решения задач распределения ключей и ЭЦП, а симметричная криптография для шифрования. Широко известна схема комбинированного шифрования, сочетающая высокую безопасность криптосистем с открытым ключом с преимуществами высокой скорости работы симметричных криптосистем. В этой схеме для шифрования используется случайно вырабатываемый симметричный (сеансовый) ключ, который, в свою очередь, зашифровывается посредством открытой криптосистемы для его секретной передачи по каналу в начале сеанса связи.

Комбинированный метод

таблица
Рисунок 4 Схема комбинированного шифрования.
Доверие к открытому ключу и цифровые сертификаты

Центральным вопросом схемы открытого распределения ключей является вопрос доверия к полученному открытому ключу партнера, который в процессе передачи или хранения может быть модифицирован или подменен. 
Для широкого класса практических систем (системы электронного документооборота, системы Клиент-Банк, межбанковские системы электронных расчетов), в которых возможна личная встреча партнеров до начала обмена ЭД, эта задача имеет относительно простое решение - взаимная сертификация открытых ключей.
Эта процедура заключается в том, что каждая сторона при личной встрече удостоверяет подписью уполномоченного лица и печатью бумажный документ - распечатку содержимого открытого ключа другой стороны. Этот бумажный сертификат является, во-первых, обязательством стороны использовать для проверки подписи под входящими сообщениями данный ключ, и, во-вторых, обеспечивает юридическую значимость взаимодействия. Действительно, рассмотренные бумажные сертификаты позволяют однозначно идентифицировать мошенника среди двух партнеров, если один из них захочет подменить ключи.
Таким образом, для реализации юридически значимого электронного взаимодействия двух сторон необходимо заключить договор, предусматривающий обмен сертификатами. Сертификат представляет собой документ, связывающий личностные данные владельца и его открытый ключ. В бумажном виде он должен содержать рукописные подписи уполномоченных лиц и печати.
В системах, где отсутствует возможность предварительного личного контакта партнеров, необходимо использовать цифровые сертификаты, выданные и заверенные ЭЦП доверенного посредника - удостоверяющего или сертификационного центра. 

Взаимодействие клиентов с Центром Сертификации

На предварительном этапе каждый из партнеров лично посещает Центр Сертификации (ЦС) и получает личный сертификат - своеобразный электронный аналог гражданского паспорта.



таблица
Рисунок 5 Сертификат х.509.

После посещения ЦС каждый из партнеров становится обладателем открытого ключа ЦС. Открытый ключ ЦС позволяет его обладателю проверить подлинность открытого ключа партнера путем проверки подлинности ЭЦП удостоверяющего центра под сертификатом открытого ключа партнера. 
В соответствии с законом "Об ЭЦП" цифровой сертификат содержит следующие сведения:

•    Наименование и реквизиты центра сертификации ключей (центрального удостоверяющего органа, удостоверяющего центра)
•    Свидетельство, что сертификат выдан в Узбекистане
•    Уникальный регистрационный номер сертификата ключа
•    Основные данные (реквизиты) подписчика – собственника приватного (открытого) ключа
•    Дата и время начала и окончания срока действия сертификата
•    Открытый ключ
•    Наименование криптографического алгоритма, используемого владельцем открытого ключа
•    Информацию об ограничении использования подписи
•    Усиленный сертификат ключа, кроме обязательных данных, которые содержатся в сертификате ключа, должен иметь признак усиленного сертификата;
•    Другие данные могут вноситься в усиленный сертификат ключа по требованию его владельца.

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

•   проверку доверия эмитенту сертификата и срока его действия;
•   проверку ЭЦП эмитента под сертификатом;
•    проверку аннулирования сертификата.

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

ЦС, обеспечивая безопасность взаимодействия партнеров, выполняет следующие функции:

•    регистрирует ключи ЭЦП
•    создает, по обращению пользователей, закрытые и открытые ключи ЭЦП
•    приостанавливает и возобновляет действие сертификатов ключей подписей, а также аннулирует их
•    ведет реестр сертификатов ключей подписей, обеспечивает актуальность реестра и возможность свободного доступа пользователей к реестру
•    выдает сертификаты ключей подписей на бумажных носителях и в виде электронных документов с информацией об их действительности
•    проводит, по обращениям пользователей, подтверждение подлинности (действительности) подписи в ЭД в отношении зарегистрированных им ЭЦП
В ЦС создаются условия безопасного хранения секретных ключей на дорогом и хорошо защищенном оборудовании, а также условия администрирования доступа к секретным ключам.
Регистрация каждой ЭЦП осуществляется на основе заявления, содержащего сведения, необходимые для выдачи сертификата, а также сведения, необходимые для идентификации ЭЦП обладателя и передачи ему сообщений. Заявление подписывается собственноручной подписью обладателя ЭЦП, содержащиеся в нем сведения подтверждаются предъявлением соответствующих документов. При регистрации проверяется уникальность открытых ключей ЭЦП в реестре и архиве ЦС.
При регистрации в ЦС на бумажных носителях оформляются два экземпляра сертификата ключа подписи, которые заверяются собственноручными подписями обладателя ЭЦП и уполномоченного лица удостоверяющего центра (УЦ) и печатью удостоверяющего центра. Один экземпляр выдается обладателю ЭЦП, второй остается в УЦ.
В реальных системах каждым партнером может использоваться несколько сертификатов, выданных различными ЦС. Различные ЦС могут быть объединены инфраструктурой открытых ключей или PKI (PKI - Public Key Infrastructure). ЦС в рамках PKI обеспечивает не только хранение сертификатов, но и управление ими (выпуск, отзыв, проверку доверия). Наиболее распространенная модель PKI - иерархическая. Фундаментальное преимущество этой модели состоит в том, что проверка сертификатов требует доверия только относительно малому числу корневых ЦС. В то же время эта модель позволяет иметь различное число ЦС, выдающих сертификаты.

5 МОДУЛЬ

Практическое задание.
1. Установить Microsoft Visual Studio
2. Создать страницы ASP.NET
3. Запустить и протестировать разработанную страницу из Visual Studio.

 ИНСТРУКЦИЯ:
таблица и текст
таблица
таблица и текст
таблица и текст
таблица и текст
таблица
 текст
таблица и текст
таблица и текст
 текст
таблица и текст
 текст
таблица и текст
таблица и текст
 текст

ЛИТЕРАТУРА 
для веб-разработчиков

страница учебника
Семикопенко Алексей Алексеевич www.webremeslo.ru


Следующие учебники можно скачать на этом сайте
monster-book.com
обложка книги
обложка книги
обложка книги
обложка книги
обложка книги
обложка книги

ОБНОВЛЕНИЯ КУРСА

в разработке...

СЕРТИФИКАТ 

Заполните форму и получите сертификат за изучение курса " Разрабтчик web-приложений" 

Получить сертификат об окончании курса
"Разработчик web-приложений "

Отправьте заявку на получение сертификата
Ваш email
Ваше имя
Нажимая на кнопку, вы даете согласие на обработку персональных данных и соглашаетесь c политикой конфиденциальности
Made on
Tilda