Скрыть объявление

Дорогой друг! Видимо, ты заинтересован зарабатывать в интернете. Поэтому задача нашего Форума не дать тебе подарить мошенникам твои деньги и научить грамотно ими распоряжаться.
Администрация Форума настоятельно рекомендует тебе начать знакомство с Форумом этой статьёй!
Не рискуй твоими деньгами понапрасну!

С Уважением, Администрация Форума MoneyMaker.team

Приятное Уроки PHP, от чайника до гуру

Форум о Заработке и Инвестициях

Тема в разделе "Вебтехнологии", создана пользователем Gizmo, 25/11/15.

  1. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ВВЕДЕНИЕ​

    Когда-то давно, еще в прошлом веке, для того чтобы сделать сайт "на мировом уровне", достаточно было просто уметь делать web-страницы на HTML и обладать художественным вкусом. Спустя некоторое время требования усложнились: использование JavaScript и Dynamic HTML стало рутинным и дизайн сайта, не имеющего подобных "украшений", считался устаревшим. Ещё по прошествии небольшого времени правилом "хорошего тона" для корпоративного сайта стало применение сложных программ на Perl или C++, а создавать такие сайты стало по силам, пожалуй, лишь коллективам дизайнерских студий.
    Однако простые web-дизайнеры не желали мириться с такой ситуацией, и ответом на их пожелания стало появление РНР - языка программирования, обладающего возможностями сложных скриптовых языков, но в то же время удивительно простого и легкого в изучении и применении. РНР расшифровывается как "PHP: Hypertext Preprocessor" (в названии используется такой прием, как рекурсия: наличествующая в расшифровке аббревиатура "РНР" вновь может быть расшифрована как "РНР: Hypertext Preprocessor" - и так до бесконечности). Этот язык благодаря своей простоте и мощности быстро завоевал огромную популярность среди web-мастеров, и количество сайтов, использующих РНР, увеличивается с каждым днем. Немаловажно и то, что он бесплатен для использования всеми желающими.
    В этой небольшой книге будет рассказано о том, как использовать. РНР для того, чтобы сделать сайт функциональным и удобным, чтобы предоставить его посетителям (да и самому web-мастеру) новые возможности по работе с информацией на сайте. Основной упор в изложении сделан именно на практическое применение - после кратких сведений о синтаксисе и основных командах РНР в брошюре приводятся тексты реальных работающих сценариев, каждый из которых вполне может пригодиться практически на любом сайте. При этом в сценариях комментируется и разбирается каждая строчка кода, что позволяет использовать их тексты еще и в обучающих целях, для изучения структуры языка и принципов написания программ на нем.
    Книгу отнюдь не обязательно читать подряд. Если вы интересуетесь основами РНР, то вам следует ознакомиться с третьей главой. Если же вас интересует тот или иной сценарий - то сразу переходите к описывающей его главе. Поскольку книга предназначена не столько
    для обучения, сколько для непосредственного практического применения, то нужные сведения по синтаксису команд РНР даются в главах по мере необходимости - в зависимости от их использования в рассматриваемом сценарии.

    ГЛАВА 1. НЕМНОГО О WEB-ПРОГРАММИРОВАНИИ
    НЕСКОЛЬКО ТЕРМИНОВ

    Web-программирование - разработка любых программных продуктов, предназначенных для работы на сайтах World Wide Web. Строго говоря, даже разработка web-страниц на чистом HTML является web-программированием, ведь при просмотре страницы браузер фактически исполняет код HTML, форматируя текст согласно инструкциям этого языка. В настоящее время под web-программированием понимают создание CGI-приложений и использование на web-странице технологий JavaScript и VBScript для достижений сложных эффектов.
    Web-сервер - программа, запущенная на узле сети Интернет и выдающая посетителям этого узла web-страницы по запросам. Также web-сервером часто называется узел, на котором эта программа запущена, или даже компьютер, являющийся таким узлом.
    CGI (сокращение от Common Gateway Interface) - технология, позволяющая запускать на web-сервере программы, имеющие возможность получать данные от посетителей сайтов, поддерживаемых этим web-сервером, и в свою очередь выдавать им обработанные данные в виде web-страниц или других файлов. Для использования технологии CGI программа web-сервер должна удовлетворять определенным критериям - "поддерживать CGI". Если программа, запускаемая на web-сервере, представлена не двоичным кодом (т. е. скомпилированным файлом), а текстовым, то для ее выполнения требуется программа-интерпретатор того языка, на котором написана эта программа. Такой интерпретатор включается в состав web-сервера и вызывается им при необходимости заняться выполнением программного кода.
    CGI-сценарий (CGI-скрипт) - программа (в текстовом виде), предназначенная для исполнения на web-сервере. Для создания CGI-скриптов можно использовать любой язык программирования -важно лишь, чтобы на том web-сервере, где предполагается эту программу запускать, имелся интерпретатор этого языка.
    Препроцессор - программа, работающая совместно с web-сервером, которая просматривает все или некоторые файлы, выдаваемые web-сервером посетителям, и выполняет над ними определенные действия в зависимости от содержащихся в этих файлах инструкций. РНР является именно препроцессором, что, собственно, и видно из его названия.

    НЕМНОГО О WEB-ПРОГРАММИРОВАНИИ
    Все языки программирования, используемые при разработке web-сайтов, можно разделить на две большие группы.
    К первой относятся те из них, код которых выполняется на компьютере посетителя сайта, т. е. в браузере, запущенном на компьютере пользователя. Это известные всем JavaScript и VBScript. Программы на этих языках встраиваются в код web-страниц или выносятся в отдельный файл, обращение к которому осуществляется из web-страницы (в этом случае браузер все равно обрабатывает такие «вынесенные» программы таким же образом, как если бы они были встроены в код страницы).
    Во вторую группу включаются те языки, программы на которых выполняются на том компьютере, где расположен web-сервер. Эта группа более обширна - дело в том, что в принципе на web-сервере могут исполняться программы на любом языке, даже командных .bat-файлов MS-DOS, важно лишь, чтобы на нем была установлена программа-интерпретатор этого языка, удовлетворяющая стандарту CGI, которому также должен удовлетворять сам web-сервер.
    РНР относится ко второй группе - программа на РНР исполняется на web-сервере. Однако от других CGI-языков РНР сильно отличается в лучшую сторону прежде всего своей простотой. При создании программы на РНР нет необходимости учитывать все те многочисленные мелочи, которые отравляют жизнь программистам на Perl или C++, - не надо заботиться о правах доступа к файлам сценария, не надо прописывать точные пути к различным модулям, нет необходимости следить за отсутствием в файле скрипта недопустимых символов. Синтаксис языка РНР допускает его легкое освоение как начинающим программистом, так и тем, кто уже использовал ранее какой-либо язык программирования. Можно целиком и полностью сосредоточиться на решаемой задаче и не думать о мелочах. Именно это и делает РНР подходящим выбором для web-дизайнера, который, начав его использовать, может вообще забыть о каких-либо других CGI-языках. (Впрочем, если исходить из механизма действия, то РНР более правильно называть не "CGI-языком", а препроцессором - что, собственно, отражено даже в его названии. В то время как CGI-приложение просто выдает некие данные в браузер посетителя, препроцессор просматривает все или некоторые файлы, выдаваемые web-сервером посетителю, и ищет в них определенные команды, которые и выполняет. Именно такой способ работы и позволяет указывать код программ на РНР непосредственно в тексте web-страниц.)
    Одним из наиболее заметных достоинств РНР является возможность без особых затруднений работать с серверами баз данных. Ранее, до появления этого языка, задание, выражающееся словами "приделать базу данных к web-странице", было довольно трудным и малодоступным для начинающих web-дизайнеров. Приходилось либо самостоятельно разрабатывать хитроумные скрипты, взаимодействующие как с программой управления базой данных, так и с web-страницами сайта, либо закупать их у фирм-разработчиков. С помощью же РНР использование базы данных на сайте стало едва ли не элементарным. Для работы с подавляющим большинством типов баз данных в РНР есть встроенные функции, поэтому теперь достаточно лишь установить на web-сервере программу работы с базой данных (наиболее часто используется бесплатная MySQL - mysql.com) и включить в текст PHP-сценария команды работы с нею (их список приведен в описании языка вместе с примерами использования).
    Возможности РНР можно весьма серьезно расширить с помощью дополнительных модулей, содержащих различные функции. Эти модули при необходимости размещаются на web-сервере, на котором установлен PHP-интерпретатор. Большое количество готовых модулей можно загрузить с адреса php.net, там же в разделе документации приведено и полное их описание. (В том web-сервере с установленным РНР, который распространяется с сайта php.spb.ru, никаких дополнительных модулей нет для уменьшения размера дистрибутива.) Например, модуль Zlib позволяет работать из программы на РНР с архивами в формате Gzip, а модуль libswf - с Flash-презентациями, создавая и редактируя их прямо из программы на РНР.
     

    Вложения:

    • 1.gif
      1.gif
      Размер файла:
      72.4 КБ
      Просмотров:
      355
    Последнее редактирование модератором: 25/11/15
  2. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ГЛАВА 2. РНР: ИСТОРИЯ. МЕСТА. ИСТОЧНИКИ
    PHP: ИСТОРИЯ. МЕСТА. ИСТОЧНИКИ

    В отличие от многих других языков программирования, РНР был создан не какой-либо корпорацией или гением-программистом, а обычным пользователем, Расмусом Лердорфом, в далеком 1994 году. Цель разработки языка была проста - сделать домашнюю страничку Расмуса более интерактивной, а значит, и более привлекательной для посетителей. Расмус разработал базовый синтаксис и написал первый интерпретатор своего языка, получившего название Personal Home Page Tools - т. е. РНР. Этот интерпретатор мог обрабатывать лишь несколько основных команд, однако начало было положено.
    В 1995 году Расмус доработал интерпретатор РНР, соединив его с другой своей программой, умевшей обрабатывать HTML-формы (именовавшейся FI - от "Form Interpretator"), а также сделал так, что интерпретатор, получивший название PHP/ FI Version 2, мог становиться частью web-сервера. Это новшество позволило программам на РНР исполняться очень быстро. Кроме того, в том же 1995 году интерпретатор РНР был дополнен возможностями1 обработки новых команд, в частности, команд для работы с серверами баз данных и автоматического создания gif-файлов (последнее, к примеру, может быть использовано для генерации кнопок-счетчиков посещений). PHP/ FI был размещен в Сети для всеобщего использования, и началось его повсеместное распространение. К концу 1997 года РНР использовался более чем на пятидесяти тысячах сайтов.
    Web-мастера быстро оценили достоинства нового языка web-программирования, такие как легкость освоения и богатство возможностей, и вскоре традиционные Perl и С стали сдавать свои позиции. Так как исходный код интерпретатора был открыт (а сам интерпретатор, понятно, бесплатен), то энтузиасты стали заниматься его доработкой, и летом 1998 года появился на свет РНРЗ - детище Зива Сураски и Энди Гутманса (Zeev Suraski and Andi Gutmans). РНРЗ был создан практически "с нуля", так как его авторы сочли код предыдущих версий недостаточно эффективным. Кроме того, РНРЗ стал весьма легко расширяемым продуктом. Любой, создавший на основе определенных стандартов модуль расширения РНР, позволяющий, скажем, работать с архивами какого-либо типа, мог этот модуль интегрировать с программными файлами РНР без каких-либо серьезных затрат времени и сил. Уже к концу 1999 года число сайтов, построенных на основе РНР, перевалило за миллион. Весьма важным достоинством РНР также являлось то, что программы, позволявшие обрабатывать команды РНР, были созданы практически для всех операционных систем, от Windows до Unix и Linux.
    В 2000-м году вышла разработанная компанией Zend Technologies четвертая версия интерпретатора РНР, дополненная множеством новых функций. В настоящее время именно она является наиболее распространенной - РНР используется более чем на 20% сайтов Сети. Сейчас готовится уже пятая версия данного языка.


    С чего начать?

    Основным источником сведений по РНР является официальный сайт его разработчиков - php.net. Именно на этом сайте представлены дистрибутивы различных версий РНР для различных платформ. Также на php.net размещаются руководства по РНР на разных языках, а, кроме того, - списки сайтов, посвященных программированию на РНР.
    Однако тем, кто желает разработать сайт с применением РНР, возможно, лучше посетить прежде всего русский сайт "РНР по-русски", расположенный по адресу php. spb.ru, и загрузить с него два файла - полное описание РНР на русском языке (перевод руководства по РНР с сайта www. php.net) и web-сервер Apache с РНР-мо-дулем, сконфигурированным для немедленного использования. Оба файла подготовил и разместил в Сети ведущий этого сайта Дмитрий Бородин.
    Первым делом установите на своем компьютере web-сервер Apache из загруженного файла (этот процесс подробно описан на сайте Дмитрия Бородина, в статье по адресу php.spb .ru/php/ install_module .html) и освойте его использование. В последнем нет ничего сложного - достаточно внимательно прочитать статью Дмитрия и файлы Readme из дистрибутива. После этого вы сможете полноценно работать с программами на РНР на своем компьютере, не выходя в Интернет, например, тестировать разработанные с использованием РНР сайты. (Версия РНР на сайте Дмитрия на момент написания этого текста была 4.0.6, в руководстве же рассматривается третья версия языка. Однако подавляющее большинство функций в третьей и четвертой версиях языка одинаковые, заметные различия есть разве что в технологии использования некоторых глобальных переменных и в наличии в 4-й версии механизма сессий - об этом будет рассказано в последующих главах.)
    Ну а затем приступайте к изучению языка. В нескольких следующих главах изложены самые основные его понятия и описаны базовые команды, с помощью которых можно создать неплохие РНР-программы. За остальной информацией обращайтесь к описанию языка, тем более что оно переведено на русский язык и снабжено массой примеров кода. Только помните, что в том дистрибутиве web-сервера, о котором говорилось выше, отсутствуют модули, расширяющие возможности РНР, так что некоторые разделы описания будут неактуальны. Впрочем, ничего не мешает вам загрузить нужные модули отдельно и установить их (на сайте php.spb.ru описано, как это сделать), однако первое время такая необходимость у вас вряд ли появится.
    Русскую версию учебника по РНР для версий 4.0 и выше вы можете загрузить как с сайта разработчиков РНР, так и с некоторых русских сайтов, например, с ресурса Александра Пирамидина - pyramidin.narod .ru.
    Готовый к использованию web-сервер вместе с интерпретатором РНР, а также системой управления базами данных MySQL вы также можете найти на сайте проекта "Денвер", расположенном по адресу dklab. ru/chicken/web. В отличие от вышеупомянутого ресурса "РНР по-русски", ведущие проекта "Денвер" Дмитрий Котеров, Дмитрий Короленко, Игорь Светликов и Андрей Любченко регулярно обновляют свой проект, постоянно размещая на нем свежие версии web-сервера с набором компонентов. Однако установка "Денвера" более автоматизирована, нежели набора с сайта "РНР по-русски", и предусматривает значительно меньшую ее "управляемость".
    "Денвер" можно порекомендовать тем, кто предпочитает автоматически получить на своем компьютере готовый к использованию web-сервер в целях изучения языка РНР и создания на нем программ, а "РНР по-русски" понравится тому, кто привык все, что ему надо, настраивать сам. Тем более что последнее будет весьма легко - достаточно внимательно прочитать комментарий Дмитрия с сайта и файлы Readme из дистрибутива.
    Для написания кода на РНР подходит любой текстовый редактор -от "Блокнота" до "Script Editor" из пакета Microsoft Office, здесь выбор зависит от вашего личного вкуса и желания.
     

    Вложения:

    • 1.gif
      1.gif
      Размер файла:
      66.6 КБ
      Просмотров:
      342
    • 2.gif
      2.gif
      Размер файла:
      59.5 КБ
      Просмотров:
      338
    • 3.gif
      3.gif
      Размер файла:
      51.3 КБ
      Просмотров:
      339
    Последнее редактирование модератором: 25/11/15
  3. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ГЛАВА 3. РНР: ОСНОВЫ


    PHP: ОСНОВЫ

    Синтаксис PHP довольно простой. Программы на РНР встраиваются в текст web-страницы так же, как и сценарии на JavaScript, VBScript, при помощи окаймляющих угловых скобок с вопросительными знаками и указанием языка:

    <?php
    ...
    текст программы
    ...
    ?>

    Команды РНР обязательно разделяются символом точки с запятой - ";" (символ конца абзаца или конца строки не учитывается никак), после последней в программе команды его можно не ставить. Также символ ";'' не ставится после условных операторов (if, switch) и операторов цикла (for, while и других).

    Как и во всех языках программирования, в РНР есть возможность работать с переменными - некими объектами, имеющими имя и могущими принимать различные значения. Однако работа с переменными в РНР, пожалуй, самая легкая из всех возможных. Переменные не надо заранее объявлять (если не знаете, что это такое - то пока и не надо), разве что за исключением использования их в функциях. Для введения новой переменной достаточно просто присвоить ей какое-либо значение, а для помещения значения переменной в строку текста, имени файла или параметра команды, нужно просто написать ее имя в том месте, где должно быть ее значение. Чтобы РНР мог отличать переменные от строк или команд, имя переменной должно начинаться со знака доллара - ("$") и не должно содержать пробелов, знаков апострофа и некоторых других символов. При анализе программного кода интерпретатор РНР считает именем переменной все, что содержится между $ и ближайшим к нему символом, недопустимым в имени переменной.
    В качестве имен переменных можно также использовать другие переменные - для этого другую переменную следует просто указать на месте имени первой: $$а.
    Переменные в РНР могут быть четырех типов - число (целое и дробное), строка текста, массив и объект1. Интерпретатор РНР автоматически определяет тип переменной на основании анализа ее содержимого. Подробнее о типах данных вы можете узнать в руководстве по РНР (например, в том, что доступно с сайта "РНР по-русски"), там же рассказано и об особенностях работы с массивами (и вообще объяснено, что это такое, если вы еще не знаете).
    Для включения числовой или строковой переменной в строку текста достаточно просто поместить переменную туда, где она должна стоять в этой строке. Например, в итоге выполнения кода $а="птица певчая"; $b="Дятел - $а"; переменной $b будет присвоено значение "Дятел - птица певчая".
    Помните, что в РНР нельзя для сложения строковых переменных использовать символ "+" - он пригоден лишь для числовых выражений. Поэтому необходимо помещать переменные в строки или использовать команду конкатенации (точку): $с = $а. $b.

    Есть еще два типа переменных - PDF-документ и PDF-инфо, но они применяются только при работе с файлами PDF (и при установленном модуле поддержки PDF).

    Довольно часто используются сокращенные обозначения арифметических действий над переменными и действий по присваиванию им каких-либо значений. Например, команда $а+=3 означает, что переменную $а надо увеличить на 3, что и будет сделано, если она имеет числовой формат. Точно так же команда $а- = 3 уменьшает переменную $ а на 3, а команды $а*=2 и $а/=2 соответственно умножают и делят на два переменную $а. Команда $а.=" строка" эквивалентна команде $а="$а строка".
    В РНР применяются также операции инкремента и декремента -т.е. изменения значения переменной на 1. Так, команды $а++ и $а-- соответственно увеличивают и уменьшают значение переменной $а на единицу. То же самое делают и команды ++$а, --$а, однако, в том случае, если подобная команда используется в выражении, они, в отличие от предыдущих, сначала изменяют значение переменной, а потом выдают его в выражение. Иными словами, если переменная $а равна 2, то после выполнения команды $b=$а++; ее значение достигнет 3, а $b будет установлена в 2. В то же время команда $b= + + $а; установит обе переменные в 3.
    Массив - это совокупность под одним именем перенумерованных переменных. Имя каждой переменной в массиве состоит из имени этого массива и индекса переменной - нечто вроде номера переменной в массиве или ее имени в нем. Индекс переменной может быть цифровым или символьным - т. е. представлять собой либо номер переменной в массиве, либо ее имя в нем.
    Например, вот массив с числовыми индексами (нумерация индексов начинается с нуля, а не единицы!):

    $а[0]=100; $а[1]=101; $а[2]=102;

    а вот с символьными:

    $а['first']=100; $а['second']=101; $а['third']=102;

    (Массив с числовыми индексами называется еще "скалярным", а с символьными - "ассоциативным".)
    Зачем нужны массивы? А для того чтобы можно было к ним обращаться как к чему-то целому, тем самым получая возможность возможность совершать автоматические действия со всеми элементами массива или с частью этих элементов, не указывая имени каждого их элемента.
    Иными словами - скажем, в какие-то переменные записали имена клиентов и теперь желаем вывести их. Как это сделать? Естественно, только перебрав все эти переменные, для чего нам понадобятся имена этих переменных, которые придется жестко задать в программе. А если заранее неизвестно, сколько будет клиентов, как тогда быть? Если же имена клиентов поместить в массив, то все их можно перебрать специальной командой, добавить же новое имя тоже нетрудно.
    В РНР добавлять элементы в массив можно как явно указывая индекс элемента (например, $а [100] = "Андрей";), так и просто упоминая, в какой массив этот элемент добавляется - $а [ ] ="Андрей" ;. В последнем случае добавляемый элемент становится последним в массиве.
    Ниже перечислены некоторые основные команды РНР, которых вполне хватит для реализации несложных проектов. Для более полного ознакомления с командами РНР можно изучить Руководство по этому языку, доступное, например, с адреса php.spb.ru, или другие публикации.
    include "имя файла" - команда для включения содержимого одного файла в другой. Содержимое файла, имя которого указывается в команде, целиком и полностью вставляется на то место, где располагается эта команда, при этом все коды РНР, содержащиеся во вставляемом файле, исполняются так же, как если бы они были на месте этой команды. (Помните, что файл именно вставляется - т. е., например, пути к картинкам, которые должны присутствовать во вставляемом файле, следует указывать от местонахождения того файла, в котором находилась команда include.)
    Если файл, включаемый в страницу при помощи команды include, отсутствует, то вместо него размещается уведомление об этом, а программа на РНР выполняется дальше. (При необходимости завершения обработки и выдачи web-страницы в случае отсутствия включаемого файла, вместо команды include следует использовать команду require.)
    mail ("Кому", "Тема", "Текст сообщения", "Дополнительные заголовки") - отправка почтового сообщения. При выполнении данной команды на сервере в соответствии с указанными параметрами формируется электронное письмо и отправляется с помощью установленной на сервере почтовой программы. В качестве параметра "Кому" может выступать набор адресов, разделенных запятыми. "Дополнительные заголовки" могут быть любые (естественно, допустимые почтовыми протоколами!), разделяться они должны должны комбинацией символов /п, которая в РНР означает перевод строки. (Если среди "Дополнительных заголовков" не указано поле From, то оно заполняется по умолчанию почтовой программой web-сервера, например, именем "Unprivileged User".)
    echo ("текст") - вывод на web-страницу какого-либо текста. Чтобы вывести на web-страницу значение какой-либо переменной, достаточно просто написать ее имя внутри выводимой строки: команда echo "это цифра $а" выведет в web-страницу текст "это цифра 1", если ранее переменной $а было присвоено значение, равное единице. В случае необходимости использовать в выводимой строке кавычки или иные специальные символы перед этими символами следует ставить символ " \".
    if (условие) {...команды, которые должны выполняться, если условие верно...;} else {...команды, которые должны выполняться, если условие неверно...} -команда, позволяющая выполнить то или иное действие в зависимости от истинности верности или ложности того или иного условия. В фигурных скобках может располагаться несколько команд, разделенных точкой с запятой. В качестве условия может быть оператор сравнения "равно" - ("==") (именно два-знака равенства!), "больше" -(">"), "меньше" - ("<") и их комбинации, скажем, "< = " - ("меньше или равно"). Можно использовать и несколько условий, взяв каждое из них, а также все вместе в скобки и разделяя знаками "&&" - ("и") или "| |" -("или").
    Для того чтобы выполнять различные команды в зависимости от условия, которое может принимать три или больше значений, следует использовать оператор switch (описание смотрите ниже) - аналог оператора case в VBA и некоторых других языках.
    for (начальное значение счетчика, условие продолжения цикла, изменение счетчика на каждом цикле) { . . . команды. . . ;} - цикл, т. е. повторение указанных в нем команд столько раз, сколько позволит условие изменения счетчика цикла (т. с. переменной, специально выделенной для подсчета числа выполнений команд цикла). К примеру цикл for ($i = 1; $i <= 10; $i + +) {echo $i;} выводит в web-страницу числа с 1 до 10, так как в нем изначально устанавливается значение счетчика в 1 - ($i = l), каждый цикл его значение увеличивается на 1 - ($i ++), а продолжаться он будет до тех пор, пока значение счетчика не превысит 10 (т. е. пока $i< = 10).
    while (условие) { . . .команды. . . } - цикл с условием. Команды в фигурных скобках выполняются до тех пор, пока выполняется условие в заголовке цикла. Для того чтобы цикл прервался, нужно, чтобы условие выполняться перестало - поэтому внутри цикла необходимо предусмотреть возможность влиять на это условие. Скажем, цикл while ($i<=10) { . . .команды. . . ; $i++; } будет выполняться до тех пор, пока значение переменной $i не превысит 10 -если изначально оно было равно 1, то цикл выполнится 10 раз.
    Цикл do {. . .команды. . . } while (условие) работает так же, однако команды, указанные в фигурных скобках, будут выполнены по меньшей мере один раз - даже если условие выполняться не будет.
    Прервать выполнение любого цикла можно оператором break -дальнейшее выполнение программы пойдет с команды, следующей после закрывающей фигурной скобки. Оператор же continue прерывает текущую стадию выполнения цикла, т. е. после этого оператора дальнейшее выполнение программы начнется с очередной проверки условия заголовка цикла.
    switch (выражение) {case значение: ... команды...; break; case другое значение: ... команды...; break;}
    - оператор выбора. При его работе содержимое, заключённое в фигурные скобки, просматривается сверху вниз. Как только будет найден оператор case со значением, совпадающим со значением выражения, РНР начнёт выполнять весь код, следующий за этим оператором case до последней фигурной скобки оператора switch или до первого оператора break, в зависимости от того, что появится раньше. (Обратите внимание, что если команду break не указать в конце кода, относящегося к одному варианту значения выражения в заголовке оператора switch, PHP будет выполнять код дальше - т. е. тот, который принадлежит уже следующему оператору case! Это - одно из отличий данного оператора от аналогичных в других языках программирования.)
    В конце оператора switch можно указать оператор default. Код, стоящий после него, выполнится в том случае, если значение выражения в заголовке оператора не совпадет ни с одним из значений после операторов case.
    foreach (переменная as массив) { . . .команды. .. ;} - поочередное считывание всех элементов массива. Foreach считывает в указанную в его параметрах переменную поочередно все элементы указанного в них же массива, выполняя каждый раз указанный в фигурных скобках код, в котором может использоваться указанная переменная. (Значения элементов массива этим оператором только считываются, их модификация при помощи команды f oreach невозможна.) Оператор f oreach может быть использован только в РНР версии 4.0 и выше.
    Программа на РНР может прерываться кодом web-страницы - для этого достаточно вставить закрывающий тэг до этого кода и открывающий - после. Все, что находится между ними, будет выдаваться в браузер без какой-либо обработки, рассматриваясь как выводимое с помощью команды echo. Иными словами, код

    <?php if ($a==l) { ?><р>Переменная а равна 1</p><?php> }?>

    эквивалентен коду

    <?php if ($a==l) {echo "<p> Переменная а равна
    1</p>";}?>

    однако, первый вариант меньше нагружает процессор компьютера, на котором расположен интерпретатор РНР.
    Из сказанного также следует, что все программы на РНР, расположенные на одной web-странице, представляют собой одну большую программу, несмотря на то, что они разделяются блоками обычного текста страницы. Именно поэтому переменная, объявленная в расположенном в начале страницы коде, сохраняет свое значение не только до ее конца, но и во всех присоединяемых с помощью команды include файлах.
    В РНР можно создавать функции - подпрограммы, которые можно вызывать по своим именам, при необходимости передавая им определенную информацию. Необходимы они в том случае, когда один и тот же код нужно выполнять несколько раз для разных данных, особенно если требуемое количество выполнений заранее неизвестно. Создать функцию на РНР можно, вставив в программу инструкцию function имя (переменные, в которые записываются передаваемые параметры, и их тип) {...команды функции . . . }, а вызвать - простым указанием имени этой функции и параметров.

    Помните, что переменные, созданные в функции, по умолчанию имеют установленное значение только внутри функции. Кроме того, также по умолчанию переменные, объявленные вне функции, в ней самой никакого значения не имеют, а если надо, чтобы имели, то вначале функции их следует "подключить" командой global <пе-ременная>; - и лишь после этого они станут доступными в функции. Подробнее о функциях и о переменных в них читайте в руководстве по РНР, например, с того же сайта php.spb.ru.
    Обычно web-сервер настраивается так, что на предмет наличия программ на РНР просматриваются файлы, имеющие расширение .php, .php3, .phtml, остальные же файлы передаются в браузер пользователя без поиска в них команд РНР. Делается так для более быстрой работы сервера, а также для обеспечения возможности установки на сервере разных интерпретаторов (например, SSI - Server Side Includes, технологии, в какой-то мере предшествовавшей РНР), так как тогда каждому из интерпретаторов назначаются свои расширения для обработки соответствующих файлов.
    Так как РНР-код полностью исполняется на web-сервере, то в страницах, выдаваемых браузеру, он будет отсутствовать, и если кто заинтересуется вашим опытом программирования, то вам придется отправлять ему этот код по почте, так как при просмотре сайта каким-нибудь образом узнать исходный PHP-код его страниц нельзя.


    РАБОТА С ФОРМАМИ

    Значения переменных можно передавать между различными страницами сайта - с помощью использования форм. Формой называется конструкция, состоящая из поименованных элементов особых типов, заключенных между HTML-тэгами <form...> n</form>. В качестве элементов формы могут выступать поля ввода текста, кнопки, выпадающие меню, переключатели, квадратики для отметки галочкой -checkbox'bi, а также картинки формата jpg или gif. Каждый элемент формы может иметь свое имя.
    Наиболее важным свойством формы является то, что в ее заголовке в открывающем тэге <f orm...> можно указать адрес какого-либо файла. В этом случае при загрузке этого файла в программный код, если он будет там присутствовать, передадутся значения всех переменных, установленных в этой форме, в частности, значения всех элементов формы, как если бы эти значения были установлены в программе, расположенной в самом загружаемом файле. Таким образом можно передавать значения переменных между различными web-страницами, используя их в программном коде.
    Во всех версиях РНР имена передаваемых переменных соответствуют тем именам, которые были даны элементам формы в их тэгах, а значения - соответственно значениям этих элементов (если в конфигурационном файле РНР - php.ini - параметр regis-ter_globals установлен в on.): для поля ввода текста - введенному тексту, для переключателя или checkbox'a - True при отмеченном и False при неотмеченном, для рисунка - координаты указателя мыши относительно верхнего левого угла изображения, для выпадающего меню (элемент <select пате="имя"><орtion value="textl">text</option>...</select>) - значение параметра value выбранного пункта option.
    Кроме того, переменные, передаваемые через форму, помещаются в ассоциативные массивы $HTTP_POST_VARS и $HTTP_GET_VARS (если в конфигурагцюнном файле РНР - php.ini - параметр track_vars установлен в on) с именами элементов, соответствующими именам переменных (т. е. содержимое поля ввода текста <input type=text name=qwerty size=3 0> окажется в элементе $HTTP_POST_VARS['qwerty']). SHTTPPOSTVARS содержит переменные, переданные с помощью метода POST (метод указывается в заголовке формы), а $HTTP_GET_VARS - метода GET. Различие между методами состоит в том, что при передаче данных методом GET эти данные отображаются в адресной строке браузера, а при использовании метода POST - нет.
    Начиная с РНР версии 4.1, передаваемые через форму переменные помещаются еще и в массивы SPOST и SGET. Отличие этих массивов от предыдущих состоит в том, что их переменные доступны еще и во всех функциях, расположенных в программе РНР, т. е. они являются глобальными.

    РАБОТА С ФОРМАМИ

    Значения переменных можно передавать между различными страницами сайта - с помощью использования форм. Формой называется конструкция, состоящая из поименованных элементов особых типов, заключенных между HTML-тэгами <form...> n</form>. В качестве элементов формы могут выступать поля ввода текста, кнопки, выпадающие меню, переключатели, квадратики для отметки галочкой -checkbox'bi, а также картинки формата jpg или gif. Каждый элемент формы может иметь свое имя.
    Наиболее важным свойством формы является то, что в ее заголовке в открывающем тэге <f orm...> можно указать адрес какого-либо файла. В этом случае при загрузке этого файла в программный код, если он будет там присутствовать, передадутся значения всех переменных, установленных в этой форме, в частности, значения всех элементов формы, как если бы эти значения были установлены в программе, расположенной в самом загружаемом файле. Таким образом можно передавать значения переменных между различными web-страницами, используя их в программном коде.
    Во всех версиях РНР имена передаваемых переменных соответствуют тем именам, которые были даны элементам формы в их тэгах, а значения - соответственно значениям этих элементов (если в конфигурационном файле РНР - php.ini - параметр regis-ter_globals установлен в on.): для поля ввода текста - введенному тексту, для переключателя или checkbox'a - True при отмеченном и False при неотмеченном, для рисунка - координаты указателя мыши относительно верхнего левого угла изображения, для выпадающего меню (элемент <select пате="имя"><орtion value="textl">text</option>...</select>) - значение параметра value выбранного пункта option.
    Кроме того, переменные, передаваемые через форму, помещаются в ассоциативные массивы $HTTP_POST_VARS и $HTTP_GET_VARS (если в конфигурагцюнном файле РНР - php.ini - параметр track_vars установлен в on) с именами элементов, соответствующими именам переменных (т. е. содержимое поля ввода текста <input type=text name=qwerty size=3 0> окажется в элементе $HTTP_POST_VARS['qwerty']). SHTTPPOSTVARS содержит переменные, переданные с помощью метода POST (метод указывается в заголовке формы), а $HTTP_GET_VARS - метода GET. Различие между методами состоит в том, что при передаче данных методом GET эти данные отображаются в адресной строке браузера, а при использовании метода POST - нет.
    Начиная с РНР версии 4.1, передаваемые через форму переменные помещаются еще и в массивы SPOST и SGET. Отличие этих массивов от предыдущих состоит в том, что их переменные доступны еще и во всех функциях, расположенных в программе РНР, т. е. они являются глобальными.

    Кнопка, вызывающая переход на страницу, указанную в параметре action заголовка формы, должна иметь тип submit, например:

    <input type=submit value="Вывести оглавления отмеченных альбомов">.


    Загрузив заглавную страницу сайта harchikov.ru, можно легко изучить структуру расположенной на ней формы, что вы и сделайте, если описание вам непонятно.
    В файле же albm.php (адрес именно этого файла указан в заголовке формы заглавной страницы) помещена простая программа, которая выглядит так:

    <?php
    if ($bar01==True) {include ( "bar01.php"); }
    if ($bar02==True) {include ('bar02.php"); }
    ... по строке на каждый альбом...
    ?>

    В файлах bar01.php, bar02.php и т. д. находятся описания альбомов и ссылки на МРЗ-файлы песен. Если checkbox с соответствующим именем был отмечен на заглавной странице, то переменная его имени оказывается равной True - именно это и проверяется в сценарии.
    Удивительно, что этот простейший прием в настоящее время практически не применяется на сайтах Сети - используется традиционная схема размещения информации со множеством ссылок на отдельные разделы. А ведь как удобно - например, на сайте Харчикова можно выбрать альбомы, сгенерировать себе страницу со ссылками на песни из них и, заходя на нее, постепенно загружать песни или передать весь список ссылок на файлы в какую-нибудь из программ-"качалок". Или, скажем, на сайте фирмы "Экон-Профи" (econprofi.ru) точно так же сделан раздел "Вопросы и ответы" (рис.4.3) - отметив интересующие вопросы на странице раздела, можно получить подробные консультации исключительно по выбранным темам. Полученная страница и загрузится быстрее, да и при ее распечатке лишней бумаги тратить не потребуется.

    Данную схему, разумеется, можно доработать. Опыт показывает, что посетители чаще всего предпочитают просмотреть либо два-три выбранных раздела, либо все разделы сразу. В последнем случае им придется отмечать все checkbox'bi страницы, что занимает время и силы. Поэтому стоит поместить на страницу еще и кнопку вывода сразу всех разделов - "Просмотреть все". Ей можно назначить гиперссылку с адресной строкой, содержащей все переменные в значении on, а можно немного доработать код РНР на странице-обработчике запроса, попросту добавив во все условия проверку значения еще одной, общей для всех условий переменной: if (($bar02==True) || ($all==True)) {... (напоминаю, что знак || означает "или"), и тогда гиперссылка может вести всего лишь на адрес albm.php?all=True.
    Можно для решения той же задачи поместить на страницу пару сценариев на JavaScript, выполняющих соответственно отметку всех checkbox'oв и, наоборот, их очистку. Так что простор для творчества имеется, и немалый.
     

    Вложения:

    • 1.gif
      1.gif
      Размер файла:
      8 КБ
      Просмотров:
      334
    • 2.gif
      2.gif
      Размер файла:
      21.8 КБ
      Просмотров:
      328
    • 1.gif
      1.gif
      Размер файла:
      117.5 КБ
      Просмотров:
      320
    • 2.gif
      2.gif
      Размер файла:
      115.5 КБ
      Просмотров:
      318
    • 3.gif
      3.gif
      Размер файла:
      99.2 КБ
      Просмотров:
      344
    Последнее редактирование модератором: 26/11/15
  4. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ГЛАВА 5. РНР: ПРОСТЕЙШИЙ ИНТЕРНЕТ-МАГАЗИН

    С помощью РНР можно легко сделать мини-Интернет-магазин -т. е. установить на сайт форму заказа, которая будет отправляться вам по электронной почте. При этом почтовая программа посетителя использоваться не будет - ему даже необязательно вообще ее иметь.
    К примеру, такой "магазин" сделан на странице harchikov.ru/cass.php . В этой главе рассказывается о его устройстве.

    ЗАДАЧИ

    Что, собственно, должен делать Интернет-магазин? Пожалуй, следующее:

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


    ПРОЕКТ

    Из каких же компонентов web-магазин должен быть сделан?
    Отобразить ассортимент из пары десятков товаров можно на одной web-странице. На ней же можно разместить "калькулятор" и форму ввода контактных данных.
    Раздел страницы, относящийся к одному товару, должен быть снабжен чем-то, что могло бы позволить посетителю как-нибудь этот товар отметить. Для последнего лучше всего использовать выпадающий список (рис.5.2 - наподобие того, в котором устанавливается размер шрифта в Word): он заодно дает посетителю возможность выбрать и количество товара для заказа. На HTML для отображения такого списка необходимо использовать элемент <select паmе="имя этого элемента формы" >, внутри которого размещены тэги <ор-tion. . . >, в которых и указаны те значения, что в меню отображаются. При отправке формы странице-обработчику сценарию на ней передается переменная с именем, равным имени элемента <select...> и значением, равным числу из параметра value того тэга <option...>, который был посетителем выбран.


    <select name=spis>
    <option value=45>Пepвым</option>
    <option value=81>Bторой</option>
    <option value=31>Tpетий</option>
    </select>

    В зависимости от того, какой пункт списка будет выбран посетителем, сценарию-обработчику передастся в качестве значения переменной $spis (и элемента массива $HTTP_POST_VARS [ ' spis ' ]) то число, которое находилось в параметре value тэга <option>, отображающего выбранный пункт.
    Для ввода посетителем контактных данных можно использовать элемент <textarea. . . >, позволяющий помещать в себя достаточно длинные фрагменты текста на нескольких строках (например, почтовый адрес), а для ввода адреса электронной почты - элемент типа text (он отображает однострочное поле для ввода текста)


    Форма, в которую посетитель внесет сведения о своем заказе и свои контактные данные, должна быть отправлена владельцу сайта. Для этого на странице, указанной в заглавии формы как ее обработчик; нужно разместить сценарий, собирающий значения всех элементов формы в единую текстовую строку и отправляющий эту строку на e-mail владельца сайта. Последнее сделать можно командой PHP mai 1 ().
    Итак, весь Интернет-магазин будет состоять из двух файлов: витрины и обработчика заказа. Однако практически все возможности для торговли будут иметься: и список товаров, и возможность указания вида и количества заказываемого товара.
    "Калькулятор", о желательности которого упоминалось на предыдущем шаге проектирования, можно сделать на JavaScript. Программа должна отслеживать изменения в выпадающих списках, сверяться со списком цен и в соответствии с данными этого списка выводить посетителю сообщение о стоимости его заказа. Вывод сообщения лучше всего сделать с помощью средств Dynamic HTML, динамически изменяя содержимое страницы.


    ВИТРИНА

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

    <FORM METHOD="post" ACTION="zakaz.php"
    NAME="mainform">

    Допустим, что PHP-программа, обрабатывающая форму, находится в файле zakaz.php (и именно на эту страницу произойдет переход после нажатия кнопки типа submit в форме). Не забудьте указать параметр пате в заголовке формы - он потом пригодится для использования в коде калькулятора стоимости заказа. (Кстати, обратите внимание, что так как для передачи данных формы используется метод POST, а не GET, то при этом в адресной строке данные полей формы отображаться не будут.)
    Ну а внутри формы следует расположить коды выпадающих списков - по одному на каждый товар (рис.5.4). В качестве значений параметров пате удобнее всего использовать небольшие буквосочетания - коды товаров:

    <select name="TOV1">
    <option value=0>0</option>
    <option value=1>1</option>
    <option value=2>2</option>
    ...
    <option value=10>10</option>
    </select>

    Обратите внимание, что первым по счету в выпадающем списке должно стоять значение 0 - именно оно будет отображаться по умолчанию.


    Также в форме должны присутствовать поля ввода контактной информации - см. на рис.5.1. Скажем, текстовая строка типа text с именем e-mail - для адреса электронной почты и поле ввода текста textarea с именем contact - для ввода контактных данных (что сочтет нужным покупатель - имя, телефон, домашний адрес).

    <input name="email" type="text">
    <textarea name="contact" cols="30" rows="5" wrap="virtual">
    </textarea>

    (В параметре cols тэга textarea указывается количество символов, которое должно помещаться в одну строку в поле ввода текста, в параметре rows - количество строк текста, которые можно будет вписать в поле ввода до появления полос прокрутки. Параметр wrap="virtual" разрешает автоматический перенос текста на следующие строки в поле ввода.)
    Разумеется, в форме должна быть кнопка ее отправки

    <input type=submit>

    и закрывающий тэг формы

    </form>



    ОТПРАВКА ЗАКАЗА

    После оформления заказа и нажатия посетителем кнопки отправки формы произойдет переход на страницу, указанную в заголовке этой формы (в рассматриваемом сценарии - zakaz.php). Именно в этом файле содержится программа отправки заказа.
    При передаче формы сценарию на РНР содержимое каждого элемента переданной формы (для поля ввода текста - введенный текст, для элемента <select. . .> - значение параметра value выбранного пункта <орtion>) помещается в переменную, имя которой равно значению параметра пате данного элемента (Так происходит, если в файле pkp.mi установлен в on параметр register_globals). Кроме того, все эти значения помещаются в одноименные соответствующим значениям параметров пате элементы массива $HTTP_POST_VARS (если форма передана методом POST) или $HTTP_GET_VARS (если форма передана методом GET) (Так происходит, если в файле php.ini установлен в on параметр track_vars), а в РНР версии 4.1 и выше - еще и в массивы $_POST и $_GET соответственно. Например, значение элемента <select name="TOV1"> будет доступно сценариям на странице-обработчике в переменной $TOV1 и в элементе массива $HTTP_POST_VARS [ "TOV1' ] (а в РНР версии 4.1 и старше - еще и в элементе массива $_POST [ ' T0V1' ].
    Однако особенностью использования этих массивов в частности является то, что для присоединения значения любого их элемента к какой-либо строковой переменной нельзя просто поместить их внутрь текста строки - нужно использовать оператор сложения строк: точку. Скажем, написать

    $zak="$zak $HTTP_POST_VARS['TOV1']";

    нельзя - надо использовать формат

    $zak="$zak "$HTTP_POST_VARS['TOV1'];

    Отправка письма осуществляется командой mail, как вы помните, имеющей формат
    тай ("Кому", "Тема", "Текст сообщения", "Дополнительныезаголовки");
    При выполнении данной команды на сервере формируется электронное письмо в соответствии с указанными параметрами и отправляется с помощью установленной на web-сервере почтовой программы (Вы можете установить такую программу и на своем компьютере - используйте, например, Office Mail Server Юрия Кучуры (доступен с eu3eu.chat.ru) или Courier Mail Server Романа Ругаленко (доступен с courierms. narod. ru)).
    В качестве параметра "Кому" может выступать набор адресов, разделенных запятыми.
    "Дополнительные заголовки" могут быть любые из допустимых почтовыми протоколами, разделяться они должны комбинацией символов /п, которая в РНР означает перевод строки. Если среди "Дополнительных заголовков" не указано поле From, то оно заполняется по умолчаниюпочтовой программой, установленной на web-сервере, например, именем "Unprivileged User".
    Для отправки письма с заказом необходимо приготовить его текст. Можно, конечно, просто включить в письмо значения всех переменных с именами, равными кодам товара (т. е. полученные из элементов <select...>), и в конец добавить контактные данные посетителя. Но куда как лучше, чтобы владелец web-сайта получал не набор кодов, которые он еще должен по своим данным перевести в названия, а уже готовый список заказанных посетителем товаров (рис.5.5). Для этого в текст сценария включим блок определения полного названия товара по его коду.


    Итак, в любом месте файла-обработчика формы, но лучше всего в начале, следует поместить следующий сценарий:

    <?php
    $zak="";

    (В эту переменную будем последовательно собирать названия заказанных товаров.)

    if ($TOV1>0){$zak="$zak Название товара 1 -$TOV1 шт.\n"; }
    if ($TOV2>0){$zak="$zak Название товара 2 -$TOV2 шт.\n"; }
    ...

    И такие же строчки - для каждого товара. В качестве имени переменной в условной части блока if ($ . . . >0) указывается значение параметра пате соответствующего тэга <select. . .>, а в последующих фигурных скобках - название того товара, к которому этот тэг относился на странице-витрине. В результате в том случае, если посетитель изменил значение какого-либо выпадающего списка на число, отличное от нуля, то в переменную Szak, которая впоследствии станет текстом отправляемого письма, включается название товара, соответствующего этому выпадающему списку, и сведения о количестве его заказанных единиц - та величина, которая в конце концов и оказалась значением этого выпадающего списка.
    Теперь завершим составление текста письма:

    $zak="C адреса $email от заказчика с контактными данными $contact пришла заявка на приобретение товара: \n$zak";

    и отправим письмо-заявку:

    mail ("электронный адрес владельца сайта", "Заказ на товар", $zak, "From: $email\nReply-To: $email\nContent-Type: text/plain; charset=windows-12 51");?>

    В результате выполнения этой команды тот, кто обрабатывает заказы, получит аккуратный список заказанных товаров и сведения о заказчике (см. рис.5.5). Причем если посетитель правильно ввел свой е-mail, то для связи с ним после получения письма достаточно нажать кнопку "Ответить" или ей подобную в почтовом клиенте - этот e-mail подставляется в заголовок письма From:.

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


    В приведенном сценарии вместо одноименных элементов формы переменных можно использовать и соответствующие элементы массивов $HTTP_POST_VARS и (в РНР версии старше 4.1) SPOST. Например, строка добавления в текст заказа нового товара будет выглядеть как

    if ($HTTP_POST_VARS['TOV1']>0){$zak="$zak Название товара 1 -
    ".$HTTP_POST_VARS['TOV1']." шт.\n"; }

    строка генерации письма - как

    $zak="C адреса ".$HTTP_POST_VARS['email']. " от заказчика с контактными данными
    ".$HTTP_POST_VARS['contact']." пришла заявка на приобретение товара:\n$zak";

    и команда отправки письма - измененная по тому же принципу.


    КАЛЬКУЛЯТОР

    Калькулятор для отображения на странице витрины информации о сумме заказа сделан на Javascript. Его текст приводится ниже. Но, так как книга посвящена РНР, а не Javascript, к его командам даны лишь минимально необходимые комментарии. Просто поместите код сценария в тексте web-страницы, набрав его с клавиатуры или отсканировав страницы книги.
    В раздел <head> страницы с витриной следует поместить сценарий:

    <SCRIPT LANGUAGE="JavaScript">
    function calc()
    {

    В следующей строчке производится задание массива кодов товаров, встречающихся на web-странице и подлежащих учету. В ней должны быть перечислены все встречающиеся на странице коды товаров. Порядок перечисления кодов товаров не важен и не зависит от их порядка следования содержащих их элементов <select...> на самой странице.

    tov=new Array("TOV1", "TOV2", "TOV3", "T0V4");

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

    prc=new Array (100, 200, З00, 400);

    Сценарий продолжается...

    var kolvo=0;
    var stoim=0;
    for (n=0; n<tov.length; n++)
    {
    if (document.mainform(tov[n])!=null)
    {
    kolvo=kolvo+l*document.mainform(tov[n]).value;
    stoim=prc[n]*document.mainform(tov[n]).value+stoim;
    mess.innerНТМL="Количество заказанных товаров -"+kolvo+"<br>"+"CTOИMOCTb заказанных товаров -"+stoim;
    document.mainform("stoim").value=stoim; document.mainform("kolvo").value=kolvo;
    } </SCRIPT>

    Вкратце можно сказать, что этот сценарий при своем запуске просматривает значения всех элементов форм на web-странице, имеющих перечисленные в массиве tov имена (а, как вы помните, в этом массиве перечислены коды товаров: т. е. элементы с этими именами - это соответствующие этим товарам выпадающие списки <select...>), и вычисляет сумму этих значений (общее число заказанных товаров) и сумму произведений этих значений на соответствующее каждому коду число из массива ргс - списка цен (т. е. считает общую сумму покупки). Полученные значения помещаются в элементы web-страницы с именем mess (текстовое сообщение), stoim (стоимость заказа), kolvo (количество заказанных единиц товара)


    В каждый тэг <select...>, присутствующий на странице и предназначенный для заказа товара, добавьте команду, предписывающую браузеру выполнять сценарий calc при каждом изменении значения элемента, отображаемого этим тэгом:

    <select name=TOV1l onchange=calc ()>
    <option value=0>0
    ...
    </select>

    В том месте страницы, где вы желаете отображать посетителю сведения о заказе, поместите строчку с элементом <р> или <div>, имеющую идентификатор mess - тот же, что упоминался в сценарии (здесь надо использовать именно параметр id, а не nаmе):

    <р align=center id=mess> Информация о заказе появится здесь</р>

    Где-нибудь в форме также поставьте два скрытых поля:

    <input type=hidden name=stoim value=0>
    <input type=hidden name=kolvo value=0>

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

    $zak="C адреса $email от заказчика с контактными данными $contact пришла заявка на приобретение товара: \n$zак\пКоличество заказанных товаров -$kolvo\n О6щая стоимость заказа - $stoim";


    ДОБАВЛЕНИЕ ТОВАРА

    Для добавления в магазин нового товара необходимо:

    • вставить на страницу его описание и тэг <select...> с кодом этого товара;
    • добавить в сценарий-калькулятор новые элементы массивов кодов и цен товаров - можно просто в конец;
    • добавить в сценарии-обработчике строчку, вставляющую в текст письма название товара согласно его коду.

      ПЕРСПЕКТИВЫ

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


     

    Вложения:

    • 1.gif
      1.gif
      Размер файла:
      109.7 КБ
      Просмотров:
      338
    • 2.gif
      2.gif
      Размер файла:
      1.4 КБ
      Просмотров:
      339
    • 3.gif
      3.gif
      Размер файла:
      2.1 КБ
      Просмотров:
      359
    • 4.gif
      4.gif
      Размер файла:
      1.8 КБ
      Просмотров:
      344
    • 5.gif
      5.gif
      Размер файла:
      23.9 КБ
      Просмотров:
      329
  5. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ГЛАВА 6. РНР:ПАПКОПОТРОШИЛКА

    При создании Интернет-ресурса, содержащего часто обновляющееся однотипное содержание, проблема быстроты и удобства обновления встает достаточно остро. Например, вы являетесь администратором сайта, на котором размещаются статьи разных авторов. В таком случае при поступлении новой статьи вам приходится, помимо размещения на web-сервере (или выделенном вам аккаунте) ее самой, еще и обновлять страницу со списком этих статей, добавив ссылку на новоразмещенную web-страницу со статьей - иначе ведь попасть на новую статью с сайта будет невозможно. А если статьи поступают часто? Да еще и не только поступают, но и удаляются, или в них меняется название? Тогда ведь для отслеживания правильности содержания приходится прилагать немало усилий.
    Или другая ситуация - необходимо разместить на сайте новостную ленту. Простое решение напрашивается сразу: просто включать текст новостей в содержащую их страницу. Или, в.крайнем случае, писать новости в отдельном файле, а в web-страницу включать этот файл с помощью команды PHP include - тогда при обновлении новостей придется загружать на сервер только файл с новостями, а не всю страницу. Но все же... не так это и удобно! Каждый раз работать с файлом с гипертекстовой разметкой, каждый раз его загружать на сайт... А если вам надо поручить загрузку человеку, который совершенно не знает HTML? Текст-то он напишет, а вот вставить его в нужное место гипертекстовой разметки?
    Или, наконец, третья ситуация - вы делаете файловый архив, и ваши друзья загружают на ваш сервер свои файлы. Как сделать так, чтобы они появлялись в списке доступных для посетителей файлов сразу же после их загрузки, без вашего участия, без необходимости вручную обновлять их список?
    Приведенный ниже сценарий на языке РНР пригодится вам во всех трех случаях. Вкратце его алгоритм прост: при вызове содержащей его страницы он пробегает по всем файлам в указанной в сценарии директории и составляет их список. А с этим списком можно уже сделать все что хочется: либо включить их содержимое друг за другом в выводимую web-страницу, либо составить каталог файлов.
    Итак - вот сценарий:

    <?php

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

    $dirct="new";

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

    $hdl=opendir($dirct);

    Теперь запишем все имена содержащихся в ней файлов в массив $а [ ]. Согласно синтаксису РНР (см. гл. 3), для этого достаточно просто присваивать массиву $а [ ] различные значения - при этом автоматически в него будут добавляться новые члены, которым эти значения будут присваиваться. Для помещения имен файлов (с расширениями) из директории $dirct в массив используется функция readdir (имя каталога), работающая с дескриптором этой директории, записанным ранее в переменную $hdl с'помощью функции opendir.

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

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

    while ($file = readdir($hdl))
    if ( ($file!=".")&&($file!="..")) $a[]=$file;
    }

    Теперь закроем открытую папку, очистив дескриптор (так необходимо) - функцией closedir (каталог):

    closedir($hdl);

    Список имен файлов папки, помещенный теперь в массив $а, содержит эти имена в случайном порядке - так их выдает функция readdir. Однако массив можно отсортировать - функциями asort (по алфавиту - прямое) или rsort (по алфавиту - обратное: с z до а). Использование сортировки массива даст возможность включать имена файлов или их содержимое в определенном порядке - достаточно лишь называть их так, чтобы они сортировались нужным образом (скажем, новости удобно именовать датой - файлы с ними могут иметь имена типа 20020901 .php, 20020902.php, тогда при прямой сортировке самые свежие файлы окажутся внизу списка, при обратной -вверху).

    rsort($a);

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

    foreach ($a as $value) {

    Комментарий:
    Оператор foreach будет работать только вРНР 4.0 и выше. Если вы можете использовать лишь РНРЗ, то вместо него можно использовать немного более громоздкий код - вначале определим размер полученного списка:
    $l=sizeof($a);
    а затем выполним нижеследующий цикл для каждого элемента массива с помощью цикла for, указав в его параметрах узнанную величину массива:
    for ($k = 1; $k < $1; $k++)
    Для удобства можно записать значение очередного элемента массива в переменную:
    $value=$a[$k]; и получится практически полный аналог оператора for each.

    Дальнейший текст сценария зависит от ваших потребностей (и одинаков как для оператора f oreach, так и при использовании цикла for).
    Чтобы вывести простой список файлов в папке $dirct, состоящий из гиперссылок на них, можно использовать такую команду, поместив ее в это место сценария:

    echo ("<a href = $dirct/$value>$value</axbr>") ;

    Чтобы вставить в страницу содержимое всех файлов в папке Sdirct, можно применить команду include:

    include ("$dirct/$value");

    Данный способ, например, используется при выводе ленты обьяв-лений и новостей на уже упоминавшемся сайте harchikov.ru. в корневом каталоге сайта создана папка news, а на его заглавной странице размещен вышеприведенный сценарий (второй вариант -с использованием команды include)/Для помещения на сайт нового объявления администратору достаточно набрать его текст (при необходимости использовав html-разметку, но можно и без нее), поместить этот текст в файл, назвать файл цифровой записью даты создания объявления (для удобства работы и сортировки) и разместить его в папке news на сайте. Никакой редакции каких-либо страниц сайта не требуется. Для удаления объявления с сайта достаточно просто удалить файл с ним из папки news, и впредь выдаваемые посетителям страницы не будут включать в себя его содержимое. Весь процесс нетрудно поручить даже секретарше или полному "чайнику".
    Однако для составления списка статей информации только об именах файлов мало. Ведь в таком списке желательно указать хотя бы название статьи и имя ее автора. Чтобы это сделать, можно, например, указывать эти данные в тэгах meta, включаемые в каждый файл со статьей, а узнать содержимое данных тэгов можно с помощью функции get_meta_tags (имя файла).

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

    Например, положим, что названия статей будем писать в мета-тэгах zagol, а имена авторов - в мета-тэгах author (т. е. в раздел <head> каждого файла со статьей нужно будет добавить строчки <meta name="zagol" content="3arоловок статьи "><meta name="author" content="ABTop статьи">). Тогда строки сценария, вытаскивающие из файла содержимое этих тэгов и помещающие их на страницу, будут выглядеть так:

    $m=get_meta_tags("$dirct/$value");
    echo "<a href=$dirct/$value>$m[zagol]</a> &nbsp;$m[author]<br>";

    Использование этого способа иллюстрируется в примере на рис.6.1. В папке duel находится файл index.php сданным сценарием, а в папке stats - статьи. В каждом файле со статьей присутствуют мета-тэги zagol и author, в которых указаны названия статей и их авторы. При вызове файла index.php находящийся в нем сценарий пробегает по всем файлам в папке stats, вытаскивает из них мета-тэги и отображает их на странице. Номера в названиях файлов со статьями используются для установки очередности вывода ссылок на них.
    Ну и конец сценария:

    }
    ? >

    При небольшой доработке возможности использования сценария можно серьезно расширить - скажем, генерировать с его помощью списки файлов в любой директории, а не только в указанной. Для этого следует убрать из сценария строку, жестко задавающую имя папки -в приведенном примере $dirct="new";, а значение переменной с именем подлежащей "потрошению" папки с файлами - $dirct -задавать через ссылку для вызова страницы. Если статьи разных номеров журнала помещаются в отдельные папки (например, соответственно называющиеся newsl, news2), то для того чтобы использовать одну и ту же страницу со сценарием для вывода оглавлений различных номеров, нужно указывать имя папки в передаваемой через адресную строку переменной, а впоследствии именно эту переменную использовать в сценарии в качестве имени "потрошимой" папки. Например, ссылки на той странице, откуда происходит переход на страницу со сценарием, могут выглядеть так:

    glav.php?dirct=newsl, oglav.php?dirct=news2

    и т. д., где oglav.php - страница со сценарием, a $dirct - переменная, в которую записывается имя папки

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

    Вложения:

    • 1.gif
      1.gif
      Размер файла:
      47.2 КБ
      Просмотров:
      362
    • 2.gif
      2.gif
      Размер файла:
      28.6 КБ
      Просмотров:
      320
  6. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ГЛАВА 7. РНР: ЗАКАЧКА ФАЙЛОВ

    PHP: ЗАКАЧКА ФАЙЛОВ

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


    ПОДГОТОВКА

    Для начала следует создать папку, куда будут помещаться закачиваемые посетителями файлы - скажем, user - в том примере, что будет рассматриваться ниже, и присвоить ей атрибут 772, что означает предоставление посетителям сайта возможность записывать в нее файлы. Для присвоения атрибута достаточно, зайдя с помощью, скажем, CuteFTP на аккаунт, выбрать из контекстного меню этой папки (т. е. из меню правой кнопки мыши) пункт CHMOD (рис. 7.1) и указать, что виду пользователей Public разрешается в эту папку что-либо записывать

    В других программах для работы по протоколу FTP права доступа настраиваются аналогично.


    ОБЩИЕ СВЕДЕНИЯ

    Чтобы пользователь мог загрузить файл на сервер с web-страницы, на этой странице должна присутствовать форма с параметром заголовка enctype, равном "multipart/form-data", а также со специальным полем типа file (выглядит как поле ввода имени файла с кнопкой "Обзор", нажав на которую, можно отобразить окно выбора файла) и кнопкой submit (см., например, рис.7.3). Как только эта кнопка будет нажата, браузер начнет передавать файл, указанный в поле типа file, на сервер. В заголовке формы также следует указать параметр action, значением которого должно быть имя страницы с обрабатывающим загруженный файл сценарием.
    Загрузку файла на сервер умеют осуществлять практически все браузеры (только самые старые модели Microsoft Internet Explorer и Netscape Navigator этого не могут), а воспринять ее могут все web-серверы (кроме CERN и некоторых самых простых), в том числе и самый распространенный - Apache.
    После того как файл полностью загружен на сервер, он помещается в его временную папку и находится там до тех пор, пока web-сервер не закончит обрабатывать и отдавать браузеру пользователя ту страницу, имя которой было указано в параметре action формы загрузки файла. После полной выдачи страницы пользователю файл удаляется. Отсюда следует, что на этой странице должны обязательно присутствовать команды, перемещающие этот файл в какую-либо папку.
    Странице, указанной в параметре action заголовка формы, передаются несколько переменных ( Если в конфигурационном файле РНР - php.ini - параметр regis-ter_globals установлен в on) содержащих информацию о загруженном файле. Именно на их основе сценарий на ней сможет работать с загруженным файлом. Кроме того, эти же самые переменные помещаются в массив $HT TP_POST_FILES ( Если в конфигурационном файле РНР -php.ini - параметр track_varsустановлен в on), а в РНР версий 4.1 и выше -и в массив SFILES (в отличие от переменных и массива SHT TPPOSTFILES этот массив по умолчанию доступен и во всех функциях, размещенных на странице с программой-обработчиком загруженных файлов).
    Вот эти переменные:

    1. Переменная, имеющая то же имя, что и поле с типом file в исходной форме. Если оно выглядело как < input name= "uploadf ile" type= " f ile">, то переменная будет иметь имя $uploadfile (и соответственно еще $HT TP_POST_FILES['uploadfile']['tmp_name'], $_FILES [ ' uploadf ile ' ] [ ' tmp_name ' ]). В эту переменную записывается то имя (временное, создающееся автоматически), которое загруженный файл имеет в папке временных файлов. Именно с ним будут работать команды копирования файла.
    Если в исходной форме присутствовало несколько полей типа file с разными именами, то для каждого из них создается своя переменная со значением, относящимся к соответствующему файлу.
    2. Переменная, имеющая имя "Переменная 1 jiame" - т. е. к имени первой переменной просто приписывается горизонтальная черточка и слово name, например, для вышеуказанного примера ее имя будет выглядеть как $uploadf ile_name (ну и, разумеется, то же самое значение получат элементы вышеупомянутых массивов $HT TP_POST_FILES['uploadfile']['name'], $_FILES ['uploadf ile ' ] ['name ' ]). Ее значением является исходное имя файла в системе отправителя.
    3. Переменная, имеющая имя "Переменная 1_size". Ее значение -размер загруженного файла в байтах.
    4. Переменная, имеющая имя "Переменная 1_type". Ее значение -тип загруженного файла согласно спецификации MIME (например, "image/gif").
    Все эти переменные можно использовать в PHP-сценарии, расположенном на указанной в параметре action заголовка формы, принадлежащей передающей файл странице. Для копирования файла используется команда сору ("имя копируемого файла (и путь к нему)", "путь к папке, в которую нужно файл скопировать и его новое имя там"). Путь к файлу во временной папке можно не указывать (она используется по умолчанию), а путь к папке, куда файл должен быть помещен, должен указываться относительный от того каталога, в котором находится страница с обрабатывающим загруженный файл сценарием.
    Об удалении файла из временной папки после копирования его в нужный каталог можно не думать - это, как уже было сказано, произойдет автоматически.


    ФОРМА ДЛЯ ПОЛЬЗОВАТЕЛЯ

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

    <FORM ENCTYPE="multipart/form-data" ACTION "up . php" METHOD=POST>

    (Т. е. программа, обрабатывающая загруженный файл, будет помещаться в файле up.php.)


    Теперь - поле ввода пароля. Его значение при передаче формы запишется в переменную с тем же именем, что и у этого поля (в данном случае - в переменную $pass), а также будет доступно в массиве $HT TP_POST_VARS, в элементе $HT TP_POST_VARS ['pass'] (начиная с РНР версии 4.1 - в элементе $_POST['pass']). Ее вы сможете использовать в сценарии на странице, указанной в параметре action заголовка формы. Если вы укажете в параметре type этого поля значение "text", то вводимые пользователем символы будут отображаться на экране, если "password" - то заместятся звездочками (как на рис.7.3).

    Ваш пароль: <INPUT NAME="pass" TYPE="password">

    И поле ввода имени файла:

    Закачать файл:<INPUT NAME="zak" TYPE="file">

    Кнопка начала загрузки:

    <INPUT TYPE="submit" VALUE="Закачать">

    Собственно, и все... Для загрузки достаточно.

    </FORM>


    СЦЕНАРИЙ ОБРАБОТКИ

    Теперь не менее важная часть - сценарий обработки загруженного файла.
    На странице, имя которой указано в параметре action заголовка формы загрузки файла, в любом ее месте следует поместить такой код:

    <?php

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

    if ($zak=="none")
    {echo ("Вы забыли указать файл...");}


    Примечание:
    Команда elseif используется в операторе if для того, чтобы проводить проверку какого-либо условия в том случае, когда то условие, которое указано в заглавии оператора if, неверно. Она идентична конструкции:
    }
    else
    {
    if (выражение) {
    } }
    и введена в РНР для упрощения синтаксиса программ.

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


    Если вы желаете назначить разным пользователям отдельные пароли (чтобы, скажем, иметь возможность запретить загружать файлы лишь одному из них, не затронув интересы остальных), то просто укажите здесь соответствующее условие (может выглядеть так: "elseif ( ($pass!="paroll")&&($pass! = "parol2") )"):

    elseif ($pass!="parol")
    { echo ("Ваш пароль неверен!");}

    И наконец, само копирование - допустим, в папку user. По его окончании пользователю выдается соответствующее сообщение


    В условии elseif в нижеследующей строчке проверяется, выдает ли команда сору значение True - что должно происходить при успешном копировании. (Если не можете разобраться в синтаксисе -смотрите Описание РНР.)

    elseif (copy($zak, "user/$zak_name"))
    {echo("Файл $zak_name размером $zak_size байт успешно загружен на сайт.");}

    Примечание:
    Команда сору выполняет копирование файла из того места, которое указано в ее первом параметре, на то, которое указано во втором. При наличии в месте назначения файла с тем же именем, что и у копируемого, новый файл пишется поверх старого. Команда возвращает True, если копирование проходит удачно, и False, если нет, выводя в последнем случае также сообщение на ту страницу, в сценарии на которой она расположена. (Если последнее нежелательно, то заблокируйте вывод сообщений об ошибке, поставив перед командой знак @.)

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

    else
    { echo("He удалось скопировать $zak_name");}
    Конец скрипта:
    ?>


    Вот, собственно, и все. Пользователь, зайдя на первую страницу (рис.7.3), должен ввести свой пароль и найти с помощью открывающегося при нажатии на кнопку "Обзор" диалогового окна файл для загрузки. После нажатия кнопки "Загрузить" он увидит одно из трех сообщений - см. рис.7.4, 7.5, 7.6.
    Если вместо имен, содержащих информацию о загружаемом файле и передаваемых через форму переменных, использовать имена соответствующих элементов массивов $HT TP_POST_FILES и $HT TP_POST_VARS, то код обработчика будет выглядеть так:

    <?php
    if ($HT TP_POST_FILES['zak']['name']=="none") {echo ("Вы забыли указать файл...");}
    elseif ($HT TP_POST_VARS['pass']!="parol") { echo ("Ваш пароль неверен!");}
    elseif
    (copy($HT TP_POST_FILES['zak']['tmp_name'], "user/".$HT TP_POST_FILES['zak']['name']))
    {echo ("Файл ".$HT TP_POST_FILES['zak1] ['name'] ." размером ".$HT TP_POST_FILES['zak']['size']." байт успешно загружен на сайт.");}
    else
    echo("Hfe удалось скопировать ".
    $HT TP_POST_FILES['zak']['name']);} ?>

    Обратите внимание, что при формировании конечного имени файла (в команде сору), а также в строках, выводимых командой echo, писать просто имена элементов массива нельзя - будет выдаваться ошибка! Необходимо использовать оператор конкатенации - точку:
    Неправильно:

    echo ("Имя файла: $HT TP_POST_FILES['zak']['name']")

    Правильно:

    echo ("Имя файла:". $HT TP_POST_FILES t'zak'] ['name'])

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

    <input name="uploadfile[]" type="file">
    <input name="uploadfile[]" type="file">
    <input name="uploadfile[]" type="file">

    В результате в программу-обработчик будут переданы:

    1. Массивы $uploadfile[], $uploadfile_name[], $uploadfile_size[], $uploadfile_type[], содержащие соответственно временные имена загруженных файлов, исходные имена загруженных файлов, размеры загруженных файлов и типы загруженных файлов. Порядок элементов в массивах в точности соответствует порядку полей в исходной форме - так, если имя файла file.zip было введено в первое поле типа file, то относящиеся к этому файлу переменные будут располагаться в элементах перечисленных массивов с индексом 0 (не забывайте - нумерация элементов массивов начинается с нуля!).
    Данные массивы будут переданы в обработчик во всех версиях РНР, начиная с 3.0.1, если в файле php.ini ( Настройка этого файла - привилегия администратора web-cepвepa, так что если вы таковым не являетесь, то включить вы ее не сумеете) включена опция regis-ter_globals.
    2. Массивы $HT TP_POST_FILES['uploadfile']['tmp_name'][], $HT TP_POST_FILES[luploadfile')['name'][], $HT TP_POST_FILES ['up-loadfile'H'size'][] и $HT TP_POST_FILES['uploadfile']['type'][], содержащие соответственно временные имена загруженных файлов, исходные имена загруженных файлов, размеры загруженных файлов и типы загруженных файлов. Порядок элементов в массивах опять-таки в точности соответствует порядку полей в исходной форме.
    Данные массивы будут переданы в обработчик во всех версиях РНР, начиная с 3.0.1, если в файле php.ini включена опция track_vars.
    3. Массивы $_FILES['uploadfile']['name'][], $_FILES['uploadfile'] ['tmpjiame'JO, $_FILES['uploadfile']['size'][] u $_FlLES['uploadfile'] I'type'Jl]. Их содержимое аналогично предыдущим. Данные массивы будут переданы в обработчик в версиях РНР, начиная с 4.1.
    В данных примерах uploadfde - это всего лишь имя массива, вы, естественно, можете назвать его по-другому.
    В РНР 3-й версии с номером подверсии 3.0.17 и выше, а также начиная с версии 4.0.3, в РНР специально для работы с загруженными через форму файлами есть две команды - is_uploaded_file иmove_uploaded_file. При использовании описанного выше способа загрузки файлов существует опасность того, что некий злоумышленник вместо указания в форме реального файла со своего компьютера укажет путь к какому-либо файлу на web-сервере (например, файлу с паролями пользователей), и тем самым сценарий, обрабатывающий загруженный файл, будет работать уже с этим файлом. Ясное дело, такое развитие событий представляется весьма нежелательным. С помощью данных команд можно исключить такую возможность. Первая команда проверяет, был ли тот файл, который указан в ее параметре, загружен через форму загрузки файлов из браузера посетителя, и если да, то возвращает True, в противном случае - False. Вторая же аналогична команде сору, однако, в качсстве#исходного файла для копирования в ней допустимо указывать лишь загруженный от посетителя файл. В противном случае команда не отработает, вернув False (без вывода в документ каких-либо предупреждений, в отличие от ситуации неудачи копирования по каким-либо другим причинам).

    Примечание:
    Команда is_uploaded__file() no сути дела проверяет, находится ли указанный в ее параметрах файл во временной директории сервера - т. е. той, куда все загружаемые файлы первоначально помещаются. То же самое проверяет иmove_uploaded_file () перед началом копирования.

    Так что, как видите, предоставить посетителям возможность загружать файлы на ваш сайт довольно просто. Как и создать простейшую, но довольно эффективную систему ограничения этой возможности по паролю - всего лишь с помощью проверки передаваемой через форму переменной, содержащей пароль; сам же пароль указывается в тексте программы на РНР. Для того, чтобы дать вашему другу возможность вести свою "колонку" на вашем сайте, этого будет достаточно.
    Еще, конечно, хотелось бы сделать нечто вроде простого "файл-менеджера", который бы позволил пользователю хотя бы удалять ненужные файлы из его каталога. О том, как реализовать такую возможность - в главе 10 этой книги.
    Однако описанные выше сценарии имеют один весьма существенный недостаток, который, в частности, весьма затрудняет загрузку больших файлов. Обратите внимание, что переход на страницу со сценарием, обрабатывающим загруженный файл и помещающим его в нужную папку, а заодно и проверяющим правильность пароля пользователя, возможен только после полной загрузки файла. Т. е. пользователю, который ввёл неверный пароль, все равно придется ждать окончания бесполезной загрузки его файла на сервер, тратя на это свое время в Сети и трафик. Если загружаемые файлы маленькие, то это еще как-то можно потерпеть, а если они имеют мегабайтные размеры? Тогда ведь вполне можно ждать жалоб от разозленных пользователей, потративших по получасу времени в Интернете на то, чтобы узнать в конце концов, что их пароль неправилен...
    Поэтому для создания полноценного сервиса размещения пользовательских файлов необходима еще и служба авторизации пользователей, позволяющая им, единожды введя логин и пароль, в дальнейшем при работе на вашем сайте их уже не проверять. Созданию такой службы также будет посвящена следующая глава этой книги.
     

    Вложения:

    • 1.gif
      1.gif
      Размер файла:
      13.4 КБ
      Просмотров:
      350
    • 2.gif
      2.gif
      Размер файла:
      4.6 КБ
      Просмотров:
      326
    • 3.gif
      3.gif
      Размер файла:
      8.7 КБ
      Просмотров:
      338
    • 4.gif
      4.gif
      Размер файла:
      8.6 КБ
      Просмотров:
      261
    • 5.gif
      5.gif
      Размер файла:
      8.4 КБ
      Просмотров:
      349
  7. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ГЛАВА 8. РНР: АВТОРИЗАЦИЯ ДОСТУПА 1 часть

    PHP: АВТОРИЗАЦИЯ ДОСТУПА
    Если вы хотя бы иногда посещаете сайты, на которых есть "защищенная зона", т. е. часть, доступ на которую возможен лишь по определенным логину и паролю (например, почтовые службы с web-интерфейсом или сервисы хостинга), то вас наверняка интересовало, как эта авторизация происходит. И наверняка вам хотелось устроить то же самое и на вашем сайте, ведь необходимость в этом иногда возникает. Ниже будет рассказано о технологиях авторизации доступа, основанных на средствах web-сервера и технологии РНР.
    Думается, значение слова "авторизация" вам понятно - это не что иное, как обеспечение возможности доступа к чему-либо тем и только тем пользователям, которые знают определенные кодовые слова - логин и пароль.


    АВТОРИЗАЦИЯ СРЕДСТВАМИ WEB-CEPBEPA

    Для того, чтобы к файлам, находящимся в какой-либо директории, могли иметь доступ лишь определенные посетители, знающие два кодовых слова (логин и пароль), можно использовать встроенные в Web-сервер Apache средства ограничения доступа.
    В конфигурационных файлах Apache есть специальная строчка -AccessFileName. Там указано имя файла, найдя который в той или иной папке, Apache выполнит по отношению к ней указания, содержащиеся в этом файле. По традиции этим именем является .htaccess, и именно таким оно установлено на всех серверах хостинга. В файл .htaccess можно поместить команды ограничения доступа к той папке, в которой это файл находится.
    Выглядят эти команды так. Вначале указывается название защищенной зоны - AuthName. Именно это название будет впоследствии выводиться в запросе посетителю (рис. 8.1).

    AuthName "Private Zone"
    AuthType Basic

    В следующем параметре - AuthUserFile - указывается путь к файлу с логинами и паролями посетителей. Этот файл должен быть создан в особом формате, так как пароли в нем хранятся в зашифрованном виде. Для создания файлов с паролями применя-
    ются специальные программы - такую программу вы можете взять, например, в разделе технической поддержки компании Valuehost по адресу support.valuehost.ru/bbs/files/69-htpasswd.exe. Запускать ее следует из командной строки в формате 69-htpasswd.exe -с имя_файла_паролей логин, а в открывшемся окне ввести пароль (используя только латинские буквы). Чтобы добавить новые логины и пароли в уже имеющийся файл, эту программу следует запускать без параметра -с.
    По традиции файл с паролями посетителей принято называть .htpasswd. Обычно Apache настраивается так, что файлы с именами .htaccess и .htpasswd невозможно просмотреть через Web - при такой попытке будет выдаваться лишь сообщение о запрещении доступа. Однако выполнение такой настройки (для этого надо указать несколько параметров в ht tpd.conf - конфигурационном файле Apache) - целиком на совести администраторов web-сервера.
    Обратите внимание, что путь к файлу паролей следует указывать абсолютный - т. е. от корневого каталога сервера с указанием всего дерева каталогов. На серверах хостинга он обычно имеет вид /pub/home/имя аккаунта/..../имя файла паролей, а на вашем локальном компьютере зависит от местоположения web-сервера и его настроек, например, может выглядеть и как f:/ww w/exper/cov/.htpasswd.

    AuthUserFile /pub/home/exper/cov/.htpasswd require valid-user

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

    Итак, пожелав "запаролить" доступ к ресурсам какой-либо папки, создайте файл с именем .htaccess с вышеуказанными параметрами.

    Комментарий:
    Сделать это командой "Проводника" или "Нортона" вам не удастся, так как эти программы не допускают создание файлов без имени (a .htaccess они воспринимают именно как расширение без имени!), поэтому наберите соответствующий текст в какой-нибудь программе, позволяющей это совершить (например, ViewText Георгия Гуляева, altailand. ru).

    Создав файл .htaccess, загрузите программу для создания файла паролей и поработайте с нею. После этого загрузите оба файла на свой сайт: .htaccess - в закрываемую папку, а файл с паролями - в соответствии с прописанным в .htaccess путем к нему (рис.8.1).

    Вот и все! Теперь при попытке запроса любого ресурса из защищенной папки (в том числе и картинок, включенных в другие страницы тэгом < img...>) посетителю будет выдан стандартный запрос логина и пароля (рис. 8.2). Если логин и пароль совпадают с хранящимися в файле паролей (по умолчанию есть три попытки ввода), то доступ разрешается, если нет - средствами web-сервера выводится соответствующее сообщение.

    Доступ открывается "для определенного окна браузера и всех его дочерних окон". Иными словами, если посетитель однажды ввел правильные логин и пароль, то он, работая в одном и том же окне браузера, может не только свободно путешествовать по всем ресурсам в запароленной папке, но и, выйдя из нее, свободно вновь в нее войти. То же самое верно и для всех окон браузера, открытых из исходного с помощью команды "открыть в новом окне". А вот если пользователь откроет новое окно браузера и зайдет уже в нем в эту папку, то запрос на ввод логина и пароля появится вновь (разумеется, если страница не была взята из кэша браузера - в последнем случае достаточно ее обновить).
    Использовать данный способ удается не всегда - администрация сервера иной раз не позволяет это делать посетителям, да и программа для создания файла паролей не всегда под рукой. Однако средства РНР позволяют обойтись без применения файлов .htaccess.


    АВТОРИЗАЦИЯ С ПОМОЩЬЮ ЗАГОЛОВКА

    В РНР есть команда Header - она позволяет отправить браузеру посетителя, запросившему страницу с содержащим эту команду сценарием, определенную служебную информацию - так называемый "заголовок". Существует довольно много вариантов заголовков (например, заголовок "Location: ht tp://адрес" приведет кперенаправ-лению на указанный URL; то же самое, что и при использовании мета-тэга ht tp-equiv с параметром "Refresh"), однако для авторизации нам потребуется заголовок "WW W-Authenticate".

    Примечание:
    Заголовок - это данные, передаваемые браузеру до передачи самой web-страницы, сообщающие ему некоторые параметры передаваемого файла ипи определенные команды. Список всех возможных заголовков, которые обязаны поддерживать современные браузеры, можно найти в спецификациях протокола HT TP - они есть, например, на сайте ww w.w3.org. PHP-команда Header выполняет всего одно действие - она просто передает то, что указано в ее параметре, в браузер, запросивший страницу, на которой она находится, в качестве заголовка.
    Следует помнить, что заголовок должен передаваться в браузер до любого другого вывода в него, за исключением установки cookie.

    В том случае, если браузер получает заголовок "WW W-Authenticate", то он выдает посетителю стандартное окно для ввода логина и пароля, которое вы наверняка много раз видели (рис.8.2). Как только посетитель нажимает кнопку Ok этого окна, браузер вновь заходит на ту страницу, с которой этот заголовок был ему послан, но на этот раз уже передает сценарию на этой странице две переменные - то, что было введено в поля ввода логина и пароля. Web-сервер дает этим переменным имена $PHP_AUTH_USER и $PHP_AUTH_PW, и их становится можно использовать в остальных сценариях на странице как любые другие переменные - использовать в выражениях, сравнивать с каким-либо эталоном, присваивать им какие-либо другие значения, наконец.
    Если посетитель нажимает кнопку Cancel в диалоговом окне запроса логина и пароля, то выполнение кода страницы просто продолжается со следующей строчки за командой Header. Никакие переменные странице не передаются.
    Однако переменные $PHP_AUTH_USER и $PHP_AUTH_PW - не простые. Если они один раз были определены, то впоследствии они передаются всем web-страницам, которые загружаются в то же самое окно браузера, где произошла авторизация! Иными словами, если по каким-то причинам требуется проверять логин и пароль посетителя на каждой из страниц сайта (скажем, выводить разную информацию авторизованным и неавторизованным посетителям), то каждый раз запрашивать эти данные не нужно - достаточно использовать значения переменных $PHP_AUTH_USER и $PHP_AUTH_PW. Значения данных переменных теряются в случае закрытия окна браузера, в котором изначально произошла авторизация (а в другие окна они и не передаются). При выходе за пределы виртуального сервера, на котором произошла авторизация (обычно его границы совпадают с границами ак-каунта), данные переменные перестают передаваться страницам, однако при повторном входе на исходный адрес вновь становятся доступными (это обеспечение безопасности - за пределами вашего виртуального сервера логины и пароли ваших посетителей никто узнать из их браузеров не сможет).
    Кстати, при использовании предыдущего способа - средствами Apache - в переменные $PHP_AUTH_USER и $PHP_AUTH_PW тоже помещаются значения логина и пароля, введенные пользователем. В принципе вы можете найти им какое-нибудь применение.
    К примеру, вспомним содержание седьмой главы, в которой рассматривалась программа для самостоятельной загрузки посетителями файлов на сайт. Помните, в чем была проблема - проверка пароля и сама загрузка файлов совершались сценарием на одной и той же странице, и в случае ошибки при вводе пароля посетитель все равно был вынужден ждать окончания загрузки файла на сайт, чтобы тот был сразу же оттуда удален? Так вот - используя данный способ авторизации (и предыдущий - средствами Apache - тоже), можно разделить авторизацию и закачку файлов, предоставив посетителю возможность вначале ввести логин с паролем, а только потом, если они правильные, выдать ему форму для закачки файла. Если добавить на страницу обработки закачанного файла краткую программу для проверки переменных $PHP_AUTH_USER и $PHP_AUTH_PW, то можно не бояться захода на страницу загрузки неавторизованных посетителей (скажем, по закладке или путем прямого набора ее адреса в браузере) - таковые будут отсеяны, а запросы легальных обработаны.
    Ниже приводится сценарий, который запрашивает у пользователя логин и пароль, проверяет их по наличию в определенном файле, а затем выводит либо приглашение к загрузке файла, либо сообщение об отказе в авторизации.
    Итак, начало сценария. Обратите внимание, что для того, чтобы он сработал, до команды Header в выдаваемый документ не должно ничего выводиться: ни результат выполнения команд РНР, ни простое содержимое страницы, - так уж воспринимают web-страницы браузеры. В частности, данный сценарий должен располагаться в самом начале страницы, и символы <?php должны быть на ней самыми первыми, перед ними не должно быть даже пробела.

    <?php

    Поскольку после выдачи окна авторизации браузер вновь вызывает web-страницу, передавая ей авторизационные данные, то можно проверить их еще до отправки браузеру "заголовка WW W-Authenticate. В самом деле - если окно авторизации не выводилось вообще, то переменные $PHP_AUTH_USER $PHP_AUTH_PW будут пустыми (вернее, вообще не определены), а если выводилось - то в них окажется информация, введенная посетителем (т. е. логин и пароль).
    Наиболее простым вариантом будет указание логина и пароля в тексте самой программы авторизации - ведь все равно код на РНР, размещающийся на странице, посетители увидеть не смогут1. В этом случае команда проверки содержимого переменных $PHP_AUTH_USER и $PHP_AUTH_PW на соответствие указанным будет выглядеть как

    if (($PHP_AUTH_USER!="login")||($PHP_AUTH_PW!= "parol"))

    Дальше идет тот код, который выполняется в случае несоответствия содержимого переменных указанным в команде логину и паролю. В случае самой первой загрузки страницы он, естественно, тоже вы-
    Вернее, смогут лишь в том случае, если данный код располагается в фаше не с тем расширением, которое указано в настройках web-cepeepa как признак страниц с программами на РНР. 70
    полнится - переменные $PHP_AUTH_USER и SPHPAUTH PW в таком случае еще не будут определены.
    Итак - выдаем окно авторизации, для чего посылаем браузеру соответствующий заголовок:

    Header("WW W-Authenticate: Basic
    realm=\"Защищенная зона"\"");

    Браузер, получив такое, выдаст посетителю окно (такое же, как на рис. 8.1) с запросом логина с паролем. После нажатия кнопки Ok страница будет загружена вновь и в том случае, если логин и пароль соответствовали указанным в ее тексте, будет выводиться остальной ее текст - тот, что последует за командой if, за ее закрывающей фигурной скобкой. Ну а если логин и пароль будут введены неправильно, то окно авторизации выскочит вновь - и у посетителя появится еще один шанс правильно авторизоваться. И так до тех пор, пока не будут введены правильные логин и пароль.
    Однако в выдаваемом окне есть еще кнопка "Отмена"! и в том случае, если посетитель нажмет ее, то код просто начнет выполняться дальше, со следующей после Header команды. Следовательно, в этот код и нужно вставить те команды, которые сообщают посетителю, так и не сумевшему ввести правильные логин с паролем, что он не может войти в защищенную зону. (Не забудьте, что все эти команды должны находиться в пределах блока оператора if- ведь нам надо, чтобы они выполнились только в случае нажатия кнопки "Отмена"!).
    Выдадим браузеру заголовок, сообщающий об отказе в авторизации (требуется некоторым браузерам, а заодно и обнуляет переменные $PHP_AUTHJJSER и $PHP_AUTH_PW):

    Header ("HT TP/1.0 401 Unauthorized");

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

    echo ("<р>Доступ закрыт!</р>");

    (При желании вы можете сделать целую web-страницу, на которой подробно рассказать, например, как можно достать правильные логин с паролем, и вставлять ее текст сюда в случае отказа в авторизации с помощью команды include:

    include ("noauth.php");

    Например, так стоит сделать, если код этой страницы весьма большой или одна такая страница будет использоваться для нескольких мест авторизации.)
    И наконец, завершим работу с текущей страницей - нам ведь не нужно выполнять тот код, что дальше; он ведь должен быть доступен только авторизованным посетителям. Для выхода используем комаду exit:

    exit; }

    Она полностью прекращает как вывод web-страницы посетителю, так и выполнение какого-либо кода. Вот, собственно, и все:

    ?>

    Для наглядности - все строчки кода вместе:

    <?php
    if (($ PHP_AUTH_USER! = "log in") | | ($ PHP_AUTH_PW! = "parol"))
    {
    Header("WW W-Authenticate: Basic realm=\"Защищенная зона"\"");
    Header("HT TP/1.0 401 Unauthorized");
    ...текст страницы, выдающейся посетителю в случае нажатия им кнопки "Отмена"...
    exit;
    } ?>

    Указание логина и пароля в самом тексте PHP-сценария - простой, но не очень удобный способ их хранения. В самом деле - если вы планируете предоставить доступ нескольким посетителям, то вам придется давать им одну и ту же пару логина и пароля. Это чревато тем, что при необходимости отказать кому-нибудь из них в доступе придется менять пароль, о чем придется сообщать всем остальным.
    Ниже приводится небольшой код, реализующий проверку содержимого авторизационных переменных на совпадение с какой-нибудь парой "логин-пароль" из специального файла паролей.
    Допустим, файл, содержащий логины и пароли, располагается в папке passw и называется passwr, а формат его прост - запись типа "логин пароль" (через пробел) на каждой строчке (см. рис. 8.3). Для того, чтобы этот файл нельзя было загрузить через web-интерфейс, просто набрав его имя (и тем самым получив на экран все его содержимое), можете сделать это имя как можно более длинным и заковыристым (все равно оно фигурирует только в программном коде, т. е. из Сети его узнать будет никак нельзя), а можете просто запретить чтение данного файла из Web, соответственно установив его атрибуты, например, в 770 (в CuteFTP это делается пунктом CHMOD из контекстного меню файла, рис. 8.4).

    Примечание:
    Еще запретить чтение содержимого директорий из Web можно, указав в файле настроек web-сервера Apache (именующемся ht tpd.conf) в разделе описания соответствующего виртуального сервера параметр Location (например:
    <Location /passw>
    deny from all
    </Location>
    - в три строки), однако доступ к файлу настроек web-сервера есть не всегда.


    Итак, начнем сценарий. Командой file считаем файл построчно в массив...

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

    ...и начнем сравнивать пару "логин-пароль" каждой строчки файла (т. е. каждый элемент массива) с той парой, что мы получили от пользователя. Массив даже нет нужды именовать - достаточно просто указать команду file в цикле обработки всех элементов массива f oreach (как упоминалось в гл. 3, этот оператор считывает каждый элемент указанного в его параметрах массива в переменную с именем, указанным после ключевого слова as, и выполняет для каждого элемента массива код, указанный в фигурных скобках).

    <?php
    foreach (file("passw/passwr") as $k)
    {

    Комментарий:
    Оператор foreach будет работать только в РНР 4.0 и выше. Если вы можете использовать лишь РНРЗ, то вместо этого оператора можно использовать цикл for, указав в его параметрах величину массива:
    $b=file("passw/passwr");
    for ($i = 1; $i < $sizeof($b); $i++)
    {
    Для удобства можно записать значение очередного элемента массива в переменную:
    $value=$k[$i];

    Поскольку каждая строчка файла завершалась символом перевода строки (вернее, двумя символами - с ASCII-кодами 10 и 13), то его необходимо удалять перед сравнением (в введенных пользователем значениях символа перевода строки-то нет!) - это делает функция substr.

    if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW") {

    ГЛАВА 8. РНР: АВТОРИЗАЦИЯ ДОСТУПА 2 часть


    Примечание:
    Команда substr предназначена для выделения из строки ее части. Строка (или переменная, ее содержащая) должна быть указана в первом параметре команды. Второй параметр - позиция, с которой начинается выделяемая часть (вернее, число символов, которые необходимо пропустить до начала выделения части строки), а третий -количество выделяемых символов.
    Второй параметр может быть и отрицательным. В этом случае отсчет позиции начала выделяемой части будет идти не с начала, а с конца строки. Иными словами, в результате выполнения команды substr ("qwertyuiop", -3, 2) из строки "qwertyuiop" будет выделена строка io - она начинается за 3 символа от конца исходной строки и продолжается 2 символа.
    Третий параметр тоже может быть отрицательным. В этом случае будет выделена строка, начинающаяся с указанной во втором параметре позиции и оканчивающаяся за столько символов до конца строки, сколько указано в третьем параметре. Иными словами, в результате выполнения команды substr ("qwertyuiop", 3, -2) из строки "qwertyuiop" будет выделена строка rtyui - она начинается после 3 символа исходной строки и заканчивается за 2 символа до ее окончания.
    В том случае, если параметры установлены так, что выделить согласно им символы из строки оказывается невозможно (например, второй параметр больше, чем число ее символов), то результатом работы команды substr будет пустая строка- "".

    Если в файле с паролями была найдена пара "логин-пароль", совпадающая с данными, введенными пользователем, то присвоим переменной $rez значение 1. Впоследствии ниже, когда нам надо будет проверить, совершилась ли авторизация, просто будем проверять значение этой переменной - так проще, чем вновь проводить просмотр файла паролей.

    $rez=l;
    } }

    Собственно, и все - проверка завершена. Теперь в том случае, если переменная $rez не равна 1, следует выдать окно авторизации и получить от посетителя логин и пароль, а если равна - то выводить страницу дальше.

    if ($rez!=l) {
    Header("WW W-Authenticate: Basic realm=\"Защищенная зона"\"");
    Header("HT TP/1.0 401 Unauthorized");
    ...текст страницы, выдающейся посетителю в случае нажатия им кнопки "Отмена"...
    exit;
    } ?>

    Как уже говорилось, переменные SPHPAUTHUSER и $PHP_AUTH_PW передаются всем страницам, которые загружаются в то же самое окно браузера - т. е. на которые посетитель переходит. Поэтому их можно использовать для проверки его прав на выполнение того или иного действия без новых запросов. Скажем, если на какой-нибудь странице, на которую посетитель должен перейти лишь после авторизации, должна производиться загрузка файла, то перед загрузкой (в сценарии-обработчике загруженного файла, подробнее -см. гл. 7) следует вновь проверить соответствие переданных этой странице переменных SPHPAUTHJJSER и $PHP_AUTH_PW какой-нибудь паре логина и пароля в файле паролей:

    <?php
    foreach (file("passw/passwr") as $k)
    {
    if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW")
    { ...команды загрузки файла...
    } } ?>

    Данный код просматривает файл с паролями (да, опять тот же файл...) и определяет, есть ли там пара "логин-пароль", соответствующая переданным странице переменным. Если есть, то файл загружается, если нет (т. е. посетитель зашел на страницу с формой для загрузки файла, скажем, по сделанной в "Избранном" закладке или введя ее URL в адресную строку браузера, миновав страницу авторизации), то загрузка не производится.
    Иными словами - один раз введенные посетителем правильные логин с паролем записываются в переменные SPHPAUTHUSER и $PHP_AUTH_PW до тех пор, пока посетитель не закроет окно браузера (и все окна, открытые по ссылкам командой "Открыть в новом окне" из окна, где произошла авторизация). На тех страницах, куда посетитель может попасть после авторизации, значения этих переменных можно проверять, сравнивая с каким-либо эталоном, например, записанными в скрытом файле логинами и паролями, и выдавать посетителю в зависимости от соответствия эталону его авторизационных данных разную информацию. Это предотвратит возможность попасть в "закрытую зону" помимо окна авторизации, через набор адреса в адресной строке или по закладке.
    Например, для отправки на страницу авторизации всех, кто ее не прошел, можно воспользоваться кодом

    <?php
    foreach (file("passw/passwr") as $k)
    77
    if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW")
    { $rez=l; } }
    if ($rez!=l) {
    Header ("Location: auth.php"); } ?>

    где auth.php - страница с кодом выдачи окна авторизации. Заголовок Location, переданный браузеру, вызывает его переход на указанную в нем страницу. Так как в данном коде используется команда Header, то она сработает без ошибок лишь в том случае, если до нее в браузер посетителя ничего не выдавалось (кроме разве что других заголовков и cookies).
    Особенности описанного способа авторизации довольно очевидны. Например, данные авторизации сохраняются в переменных лишь в течение одного сеанса работы посетителя; достаточно ему закрыть окно браузера, чтобы необходимость ввода логина и пароля возникла снова. Для заполнения полей окна авторизации нельзя использовать имеющуюся во многих браузерах функцию автозаполнения форм (современные браузеры могут запоминать соответствие определенному URL лишь одной пары "логин-пароль" и подставлять именно ее в поля окна), да и в интерфейс страницы это окно вписать никак нельзя (оно ведь отображается браузером).
    Однако есть еще один прием регламентации доступа к страницам сайта - с использованием файлов cookies.


    АВТОРИЗАЦИЯ С ПОМОЩЬЮ COOKIES

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


    Примечание:
    Cookie можно установить (т. е. прислать на компьютер посетителя) и средствами РНР. Для этого используется команда SetCookie, имеющая параметры: имя cookie, информация, записанная в cookie, время жизни cookie - указывается количество секунд, после истечения которых с 1 января 1970 года cookie не должен считы-ваться с компьютера посетителя (так уж измеряется время в операционных системах типа Unix - с начала "эпохи Unix" 01,01.1970), адреса сайта и каталога на нем, где cookie должен быть действителен, и указание на протокол передачи cookie (подробнее смотрите в Описании РНР). Считать cookie можно простой командой echo ("имя cookie"). Можно сказать, что, как только cookie установлен, сценариям на всех страницах того сайта, на котором он был поставлен, становится доступна переменная с тем же именем, что и у cookie, и тем содержимым, которое было записано в нем (если в файле настройки РНР установлен в on параметр register_globals).
    Кроме того, значения cookie помещаются в массив $HTTP_COOKIE_VARS и доступны в его элементах, одноименных с именами cookie - SHTTP_COOKIE_VARS['umh cookie'] (если в файле настройки РНР установлен в on параметр track_vars), а в РНР версии 4.1 и выше - еще и в массив $_С00К1Е.
    Для удаления cookie достаточно записать в него пустое значение (это сделает команда SetCookie с единственным параметром -именем cookie).
    Для установки времени жизни cookie можно сначала узнать текущее "время Unix" командой time(), а потом просто прибавить к нему то количество секунд, которое cookie должен просуществовать после его установки на компьютер посетителя. Если время жизни для cookie не установлено, то он проживет до закрытия всех окон браузера посетителя.
    Как и отправка заголовков командой Header, установка cookie должна предшествовать любому выводу в выдаваемый документ: как результатов выполнения команд РНР, так и простого содержимого страницы. Иначе возникнет ошибка.

    Как cookie можно использовать для решения обсуждаемой в этой главе задачи - авторизации доступа? Да вчень просто - запросив от посетителя логин и пароль, записать их в cookie, а потом на каждой странице "защищенной зоны" считывать их оттуда и проверять, имеются ли такие данные в файле паролей. Ну и поступать в соответствии с результатом такого сравнения - например, отправлять те браузеры, которые не смогли представить cookie с правильными логином и паролем, прямиком на страницу авторизации, посылая им с помощью РНР-функции Header заголовок Location с соответствующим параметром, как было показано выше для предыдущего варианта авторизации.
    Вот фрагменты сценария, в которых видна технология использования cookies. На той странице, откуда должен осуществляться вход в "защищенную зону", следует поставить простую форму для ввода логина и пароля (см.рис.8.6). Например, такую:

    <FORM ACTION="up.php" METHOD=POST> Логин: <INPUT NAME="login" TYPE="text"><br> Пароль: <INPUT NAME="pass" TYPE="password"><br> <INPUT TYPE="submit" VALUE="Войти"></FORM>


    На той странице, имя которой указано в параметре ACTION заголовка формы, введенные данные проверяются, и в том случае, если такие логин и пароль имеются в файле паролей, браузеру посетителя отсылается cookie, куда эти логин с паролем записываются.

    <?php
    foreach (file("passw/passwr") as $k)
    {
    if (substr($k, 0, -2)=="$login $pass")
    {
    $rez=l;

    И вот - сама установка cookie под именем auth. Ему устанавливается "время жизни" - 3600 с, т. е. час.

    SetCookie("auth","$login $pass",time()+3 600);
    } } ?>

    Дальше должен находиться сценарий, который в зависимости от исхода авторизации - т. е. значения переменной $rez - выводит различную информацию. Например, можно отослать посетителя назад на исходную страницу командой Header ("Location..."), как в примере предыдущего раздела этой главы.
    На всех остальных страницах "защищенной зоны" должен находиться сценарий проверки содержимого переменной auth (т. е. той, чье имя совпадает с именем поставленного cookie) - т. е. точно такой же скрипт, как и на той, где cookie ставился, только строка проверки должна выглядеть как

    if (substr($k, 0, -2)=="$auth"),

    ну и, естественно, самой команды установки cookie быть не должно. Дальнейший текст страницы - на усмотрение web-мастера: если логин с паролем, полученные из cookie, есть в файле паролей, то, скажем, вывести форму для закачки файлов, если нет - то вежливо распрощаться...
    Желательно также сделать страницу "выхода", включив в нее команду установку cookie без параметров - SetCookie ("имя cookie").
    В результате в том случае, если посетитель единожды прошел авторизацию, то он может спокойно посещать страницы "защищенной зоны" до тех пор, пока cookie "жив" на его компьютере. Он может закрыть окно браузера и даже выключить компьютер, а потом, включив его, вновь зайти на тот же адрес, используя "Историю" браузера или "Закладки"- и он будет авторизован, если время жизни cookie не истекло. Зато те, кто "подглядит" этот адрес или украдет закладку, но не будет иметь соответствующего cookie, авторизованы не будут.
    В отличие от предыдущего способа, данный вариант не является абсолютно надежным в плане сохранности в тайне логина с паролем. Во-первых, cookie с этими данными сохраняется на компьютере посетителя, а значит, теоретически может быть с него похищен (тем, кто просто сядет за этот компьютер и скопирует нужный cookie из той папки, где они хранятся). Во-вторых, возможность захода на web-страницу "защищенной зоны" в течение некоторого времени без необходимости ввода логина и пароля может привести и к нежелательным последствиям - если посетитель забудет зайти на страницу выхода, то любой, кто воспользуется его компьютером до истечения срока действия cookie, с точки зрения сервера будет вполне легальным пользователем и сможет устроить истинному владельцу логина немало проблем.
    Стоит сказать, что использовать имя cookie как переменную можно только в том случае, если в файле настройки РНР - php.ini - есть параметр register_globals. Там, где этого параметра нет (например, в РНР версии 4.2 и выше он по умолчанию неактивен), работать с cookies как с обычными переменными не получится. Информацию, помещенную в них, придется получать из массива с названием SHTTPCOOKIEVARS (создается автоматически при обнаружении cookies от данного сайта), используя имя нужного cookie в качестве индекса:

    <?php
    foreach (file("passw/passwr") as $k)
    {
    if (substr($k, 0, -2)==$HTTP_COOKIE_VARS['auth'])
    { $rez=l;
    }
    }
    ...

    В РНР версии 4.1 и выше вместо $HTTP_COOKIE_VARS можно использовать массив $_СООК1Е.
    Надеюсь, вы поняли, что все эти проверки логинов и паролей в cookies и передающихся между окнами переменных, о которых так подробно рассказывается в этом и предыдущем разделах, предназначены для одной цели - чтобы тот, кто каким бы то ни было образом узнал бы адрес страницы из "защищенной зоны" и зашел бы на эту страницу путем набора ее адреса в адресной строке браузера (или с помощью ярлыка в "Избранном"), не мог бы увидеть на ней то же самое, что и добросовестно прошедшие авторизацию посетители. Чтобы не приходилось запрашивать от посетителей пароль и логин на каждой странице, где есть возможность совершить те действия, которые крайне нежелательно позволять делать всем подряд - как, например, загрузка файлов или просмотр личной почты - а дать посетителям возможность, единожды введя авторизационные данные, свободно перемещаться по "защищенной зоне". Именно это и является основной задачей описанных технологий.
     

    Вложения:

    • 1.gif
      1.gif
      Размер файла:
      12.5 КБ
      Просмотров:
      309
    • 2.gif
      2.gif
      Размер файла:
      11.8 КБ
      Просмотров:
      299
    • 3.gif
      3.gif
      Размер файла:
      14.2 КБ
      Просмотров:
      296
    • 4.gif
      4.gif
      Размер файла:
      4.6 КБ
      Просмотров:
      339
    • 5.gif
      5.gif
      Размер файла:
      4.7 КБ
      Просмотров:
      326
    • 6.gif
      6.gif
      Размер файла:
      18.4 КБ
      Просмотров:
      319
  8. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ГЛАВА 8. РНР: АВТОРИЗАЦИЯ ДОСТУПА 3 часть


    АВТОРИЗАЦИЯ С ПОМОЩЬЮ СЕССИЙ

    Вы, наверное, уже заметили особенность обоих вышеописанных способов авторизации - проверка правильности логина и пароля осуществляется на каждой странице, где требуется авторизованный доступ. Если посетителей на сайте не очень много, то это вполне допустимо, однако при большом числе авторизованных посетителей нагрузка на web-сервер может оказаться немалой.
    В связи с этим возникает вопрос: а нельзя ли как-нибудь избежать необходимости каждый раз осуществлять проверку логина и пароля посетителя? Чтобы, единожды авторизовав посетителя, впоследствии предоставлять ему доступ на страницы защищенной зоны без каких-либо проверок? Именно так, кстати, действует защита на основе средств web-сервера - файлов .htaccess, описанная в первом разделе главы. Но можно ли сделать то же самое средствами РНР? Да и вообще использовать cookie для хранения паролей не очень желательно: его содержимое может узнать любой, кто воспользуется компьютером, на котором этот cookie сохранен (многие браузеры хранят cookie в предназначенной для них папке, даже если "время жизни" cookie истекло и он больше не принимается сервером).
    Напрашивается первое предложение: а почему бы, например, после успешной авторизации не отправить посетителю cookie с какой-либо пометкой (например, устанавливать в 1 значение переменной в этом cookie), а впоследствии проверять не наличие записанных в cookie логина и пароля в файле паролей или базе данных, а присутствие в cookie этой самой пометки, одинаковой для всех, прошедших авторизацию? Или даже сделать разные типы пометок и в зависимости от типа предоставлять посетителю разные возможности на сайте?
    Сделать-то так можно, да вот устойчивость такой системы авторизации к взлому будет не особо великой. Злоумышленнику будет достаточно узнать, что за пометку помещает сценарий авторизации в cookie, чтобы получить к защищенной зоне полный доступ - просто вручную создав такой cookie. (А если при проверке "пометки" использовался не элемент массива $HTTP_COOKIE_VARS, а одноименная переменная, то и просто подставив ее значение в адресной строке при заходе на страницу с такой проверкой: например, page . php?auth=1.) Кроме того, просмотреть значение cookie на компьютере посетителя и узнать, какие его имя и значение являются "пометкой", тоже не так трудно.
    Но самое главное - посетители нередко отключают использование cookie при своих путешествиях по Интернету. При отключенных cookie описанная выше система авторизации на их основе работать не будет.
    Как же быть?
    Следует использовать весьма интересный механизм сессий, появившийся в 4-й версии РНР.


    СЕССИИ

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

    Если у посетителя браузер принимает cookie, то ему высылается cookie (с определенным именем - по умолчанию "PHPSESSID"), содержащий так называемый "идентификатор сессии" (рис. 8.9), а если нет, то web-сервер автоматически помещает данный идентификатор в переменную PHPSESSID в каждую ссылку (рис. 8.10) на выдаваемых посетителю страницах сайта (естественно, "внутреннюю" - т. е. ведущую на другие страницы того же самого сайта, с тем же самым доменным именем). Таким образом, идентификатор передается на сервер при каждом заходе посетителя на какую-либо из страниц сайта. При этом идентификатор выбирается либо из соответствующего cookie, установленного посетителю при открытии сессии, либо из адресной строки ссылки, куда этот идентификатор автоматически помещается web-сервером.

    Как только сервер получает от посетителя определенный идентификатор сессии, то он передает сценарию на той странице, на которую зашел посетитель, все установленные для этого посетителя сохраненные переменные, после чего сценарий может их использовать, т. е. читать, изменять, уничтожать. При переходе на следующую страницу сайта все изменения будут сохранены.
    Каждый раз создаётся новый идентификатор сессии. Благодаря хорошему алгоритму генерации вероятность того, что для какой-либо последовательности символов на определенном сервере будет существовать набор сохраненных переменных, пренебрежимо мала. Еще меньше вероятность совпадения двух идентификаторов сессий, так что разные посетители сайта ну никак не смогут получить значения переменных друг друга.
    Бесспорно, набор сохраненных переменных, относящихся к одной сессии, будет существовать на сервере не вечно. В параметрах файла конфигурации РНР - php.ini - указывается, какое время жизни устанавливается для cookie с идентификатором сессии (по умолчанию 0 -т. е. до закрытия окна браузера и всех открытых из него окон), а также через какое время данные сессий из папки временных файлов удаляются физически (рис. 8.11). Кроме того, существует специальная команда "разрушения сессии", которая при своем выполнении уничтожает сохраненные в папке временных файлов данные сессии и тем самым делает недействительным идентификатор сессии. Параметры устанавливаемых cookie, в частности, их "время жизни" также можно задать специальной командой в сценарии на РНР, однако время хранения данных сессии в папке временных файлов определяется параметром в php.ini, так что при использовании виртуального хостинга вам не всегда удастся настроить работу с сессиями полностью так, как вам бы хотелось.

    тобы использовать в сценарии на странице возможности работы с сессиями, необходимо включить в него команду session_start () (так как при работе с сессиями используются cookie, то данная команда должна находиться в начале страницы, перед какими-либо выводимыми в браузер данными) - как при первоначальной установке переменных, так и при последующей работе с ними (если в файле php.iniустановлен в 1 параметр session.auto_start, то это делать не обязательно). Чтобы указать, какие переменные следует сохранять в качестве данных сессии, следует использовать команду session register("имя первой переменной", "имя второй переменной",... и т. д.), а чтобы закрыть сессию - команду session_destroy (). При закрытии сессии переменные, переданные сценарию с ее помощью, не обнуляются (последнее делает команда session_unset () ;), так что их можно использовать и в остальной части сценария.
    Переменные сессии доступны на сценариях сайта по своим изначальным именам - скажем, если командой session_register переменная $а была зарегистрирована в качестве сессионной, то ее значение будет доступно под тем же самым именем - $а - на всех страницах сайта, где используются сессии (т. е. в их начале размещена команда session_start ()).
    Переменные сессии доступны в сценариях сайта по своим изначальным именам. Скажем, если командой session_register переменная $а была зарегистрирована в качестве сессионной, то ее значение будет доступно под тем же самым именем — $а - на всех страницах сайта, где используются сессии (т. е. в их начале размещена команда session_start ()).
    Однако в целях безопасности лучше работать в сценарии с переменными сессии через автоматически создаваемые массивы $HTTP_SESSION_VARS и (в РНР версий 4.1 и старше) SSESSION, используя одноименные с переменными элементы этих массивов. Дело в том, что в этом случае сценарий будет огражден от возможных попыток злоумышленников передать ему значения этих переменных через указание их в адресной строке, если сессия не была открыта (в указанные массивы попадают те и только те данные, что были получены с сессией). Такая передача может привести, скажем, к тому, что переменная - пометка об успешном прохождении авторизации будет получена сценарием не из данных сессии (в которых она может появиться только после успешного ввода посетителем правильных логина и пароля), а от злоумышленника.

    ГЛАВА 8. РНР: АВТОРИЗАЦИЯ ДОСТУПА 4 часть

    СЦЕНАРИЙ АВТОРИЗАЦИИ

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

    <?php
    foreach (file("passw/passwr") as $k)
    {if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW")
    {$rez=l;}}
    if ($rez!=l) {Header("WWW-Authenticate: Basic realm=\"Защищенная зона"\""); Header("HTTP/1.0 401 Unauthorized");
    ...текст страницы, выдающейся посетителю в случае нажатия им кнопки "Отмена"...
    exit,-}

    или таким (если логин и пароль передаются из формы в переменных Slogin и Spass):

    <?php
    foreach (file("passw/passwr") as $k)
    {if (substr($k, 0, -2)=="$login $pass"){$rez=l;
    if ($rez!=l) {...текст страницы, выдающейся посетителю в случае ввода неправильных логина и пароля ...
    exit;}

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

    session_start();

    ...регистрируем переменную:

    session_register("auth");

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

    $auth=1;

    Собственно, и все.

    ?>

    Дальше следует текст страницы, которую посетитель должен увидеть сразу же после успешной авторизации.
    Так как идентификатор сессии обычно сохраняется в cookie, то приведенный выше код должен стоять в самом начале страницы, чтобы сервер имел возможность работать с cookies, т. е. был бы в состоянии отправить cookie с идентификатором сессии браузеру посетителя. (Если браузер посетителя не принимает cookie, то идентификатор сессии будет автоматически присоединяться ко всем найденным на данной странице ссылкам на другие ресурсы сайта.)
    На каждой странице "защищенной зоны", в самом ее начале нужно поставить код

    <?php session_start();
    if ($auth!=l)
    {...текст страницы, выдающейся посетителю в случае попытки несанкционированного доступа...
    exit;}

    ...и все, что после этого кода, будет выполнено и/или выдано посетителю только в том случае, если он успешно прошел авторизацию на первой странице. При заходе на страницу "защищенной зоны" браузер посетителя перешлет серверу cookie с идентификатором сессии, а сервер возьмет из своего временного хранилища значение всех переменных сессии и передаст их сценарию.
    Страница выхода из "защищенной зоны" должна содержать код (если в файле php.ini установлен в 1 параметр session.autostart, то указывать команду session_start () на каждой странице, где используются переменные сессии или производятся действия с самой сессией, не обязательно).

    <?php
    session_start(); session_destroy(); ?>

    После его выполнения для посещения страниц "защищенной зоны" вновь потребуется авторизация.
    Если посетитель не воспользовался страницей выхода из защищенной зоны, то время, в течение которого из его браузера можно попасть на другие ее страницы, определяется настройками в файле php.ini. По умолчанию cookie с идентификатором сессии, устанавливаемым данному посетителю, существует до закрытия всех окон браузера, а сами данные сессии хранятся несколько часов. Существует команда session_set_cookie_params () (подробную информацию о ней смотрите в Описании РНР), с помощью которой можно установить другое "время жизни" cookie, однако для изменения настроек в файле php.ini необходимо иметь права администратора для web-сервера.
    Посредством сессий можно передавать между страницами сайта и другие данные. Например, при создании сценария Интернет-магазина, витрина которого занимает больше чем одну страницу, данные о заказываемых посетителем товарах имеет смысл передавать по страницам сайта в переменных сессии для последующего их оформления на специальной странице как заказа, как, собственно, и делается на большинстве подобных ресурсов Сети.
    Так что, как видите, никаких особых секретов в технологии ограничения доступа нет. Авторизация пользователей на многих службах хостинга, web-интерфейсов почтовых систем, Интернет-форумах обычно строятся на тех же принципах, что и приведенные выше сценарии.
    Реализовав данные приемы на своем сайте, вы можете, например, вполне спокойно приглашать к себе на работу ведущих отдельных разделов вашего сайта. Все компоненты для их удобной и безопасной работы у вас уже есть: и "папкопотрошилка", и "закачиватель файлов", теперь вот еще и "защищенная зона"... Разве что стоит добавить еще и нечто вроде "файлового менеджера", чтобы посетители могли и удалять, и переименовывать загруженные ими файлы. Но об этом -еще через пару глав.


    ПРИМЕР СЦЕНАРИЯ

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

    Файл 1

    <?php
    foreach (file("passw/passwr") as $k)
    {
    if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW")
    {$rez=l;} 1
    if ($rez!=l) {
    Header("WWW-Authenticate: Basic realm=\"Защищенная зона" \" ") ;
    Header("HTTP/1.0 401 Unauthorized"); echo ("<р>Доступ закрыт!</р>"); exit;
    <FORM ENCTYPE= "multipart/form-data" АСТION ="Файл 2" METHOD=POST>
    Закачать файл:<INPUT NAME="zak" TYPE="file"> <INPUT TYPE="submit" VALUE="Закачать">
    </FORM>

    Файл 2

    <?php
    foreach (file("passw/passwr") as $k) {
    if (substr($k, 0, -2)=="$PHP_AUTH_USER $PHP_AUTH_PW") { $rez=l; }
    if ($rez!=l)
    {
    echo ("<р>Доступ закрыт!</р>");
    exit;
    if ($zak=="none")
    {echo ("Вы забыли указать файл...");} elseif (copy($zak, "папка для файлов/$гак_пате"))
    {echo("Файл $zak_name загружен");} else
    { echo("He удалось скопировать $zak_name");} ?>

    Пояснения к сценарию загрузки файлов смотрите в предыдущей главе.
     

    Вложения:

    • 7.gif
      7.gif
      Размер файла:
      8.5 КБ
      Просмотров:
      335
    • 8.gif
      8.gif
      Размер файла:
      9.4 КБ
      Просмотров:
      265
    • 9.gif
      9.gif
      Размер файла:
      5 КБ
      Просмотров:
      254
    • 10.gif
      10.gif
      Размер файла:
      18 КБ
      Просмотров:
      331
    • 11.gif
      11.gif
      Размер файла:
      51 КБ
      Просмотров:
      318
  9. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ГЛАВА 9. РНР: ГОСТЕВАЯ КНИГА

    Вы наверняка неоднократно встречали в Интернете такой сервис, как гостевые книги, т. е. web-страницы, на которых каждый посетитель может оставить свой отзыв, который будет «виден» другим посетителям, впоследствии зашедшим на страницу. Скорее всего, вы думали, что создание гостевой книги требует долгого и сложного программирования.
    Не спорю, сделать крупный Интернет-портал, предоставляющий всем желающим гостевые книги для установки на сайт, довольно трудно. Однако на языке программирования РНР организация простой системы оставления сообщений может быть создана всего несколькими строками кода. Причем нетрудно заставить эти строки обслуживать сразу несколько отдельных гостевых книг, скажем, дать посетителям возможность оставлять свои комментарии и отзывы о различных материалах, размещенных на сайте, на тех же самых страницах, на которых эти материалы размещены. Или, допустим, организовать разные книги для разных категорий посетителей.
    Данная глава, как вы, наверное, уже поняли, посвящена рассказу о сценарии на РНР для создания простейшей гостевой книги. В главе разобран сценарий, позволяющий сделать на одном сайте несколько гостевых книг. Очевидно, что приспособить его для работы всего одной гостевой книги элементарно.
    Схема работы сценария простой гостевой книги такова.
    Для хранения сообщений выделена специальная папка, в которой каждое сообщение хранится в отдельном текстовом файле. Для того чтобы можно было различать сообщения, принадлежащие разным гостевым книгам, каждая книга имеет свой индекс (например, "gbOl"), который указывается в специальном сценарии в ее тексте. Имя каждого файла с сообщением начинается с этого индекса (см. рис. 9.1).
    Поскольку в гостевой книге, как нетрудно догадаться, количество сообщений весьма скоро превысит одно, то файлы с ними нужно еще и последовательно нумеровать. Вернее, не "последовательно", а так, чтобы их можно было отсортировать - наверное, достаточно возможности сортировки лишь по дате появления.
    В РНР есть интересная функция - time (); она выдает количество секунд между 1 января 1970 года (этот момент считается началом "эпохи Unix") и текущим временем, так называемую "временную метку Unix". (В настоящее время эта величина - чуть больше миллиарда.) Посмотрите - если имя файла с сообщением составлять из индекса гостевой книги и временной метки Unix (см. рис. 9.1), то, во-первых, каждое сообщение будет обладать своим уникальным именем (посылка нескольких сообщений в гостевую книгу разными пользователями в одну и ту же секунду теоретически возможна, но маловероятна), а, во-вторых, их легко можно будет отсортировать по времени появления (время ведь вспять не течет - каждое новое сообщение будет получать большую метку, нежели любое предыдущее).
    Бесспорно, так как сортировка имен, состоящих из индекса и временной метки, будет проводиться по законам сортировки строк (т. е., скажем, 21 будет стоять раньше 3 при сортировке по возрастанию - т. к. сравнение ведется с начала строки), то при увеличении разрядности временной метки новые сообщения окажутся посреди старых. Однако какие-либо проблемы в нашем случае начнутся не раньше момента достижения временной меткой значения в 10 миллиардов, а до него еще больше, чем две с половиной сотни лет...


    Итак, вот алгоритм работы сценария гостевой книги:

    1. При загрузке посетителем страницы книги просканировать папку с сообщениями, выбрать оттуда сообщения, относящиеся к данной книге (попросту найдя в именах содержащих их файлов индекс этой книги), отсортировать их и вставить в web-страницу.
    2. При вводе посетителем сообщения пересчитать уже имеющиеся и сохранить новое сообщение в файле с именем, состоящим из индекса текущей гостевой книги и временной метки Unix.
    Есть, впрочем, еще одно пожелание. Обратите внимание - если следовать данному алгоритму, то сообщение, помещенное посетителем в гостевую книгу, будет просто вставлено в текст той страницы, на которой она расположена. А это значит, что какой-нибудь злоумышленник вполне может поместить в сообщение гостевой книги код на РНР и тот будет преспокойно выполнен! А результат такого выполнения для владельца сайта непредсказуем. Это может быть и удаление с сайта всех файлов, и размещение на нем совсем не того, что хотелось бы, и массовая почтовая рассылка... .Поэтому наш алгоритм следует дополнить еще одним пунктом:

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

    <?php
    $пот="уникальная аббревиатура книги, без пробелов и специальных символов, например, book01";
    include ("niz.php"); ?>

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


    Содержимое же файла niz.php (см. рис. 9.2) может быть таким (пояснения относятся к коду под ними):

    <?php

    Укажем имя папки, в которой будут сохраняться отзывы (ее, разумеется, вначале надо будет создать на аккаунте сайта вручную). Само имя может быть любым - важно лишь, чтобы оно не содержало пробелов или специальных символов:

    $dirct="gb";

    Ну а далее следует уже знакомый вам сценарий "Папкопотрошилки" (см. гл. 6), применяемый к этой самой папке с отзывами. Вот практически точно такой же, как и в "Папкопотрошилке", код, записывающий в массив $а[] имена всех файлов, в имени которых содержится указанный выше индекс книги:

    $hdl=opendir($dirct) ;
    while ($file = readdir($hdl))
    if (strstr($file, $nom)!=False)
    $a[]=$file;
    closedir($hdl);

    Примечание:
    Функция strstr ищет в своем первом аргументе строку, указанную вторым аргументом, и возвращает True, если ее там находит.

    Теперь отсортируем полученный массив. Для этого сначала узнаем количество сообщений книги:

    $l=sizeof($a);

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

    if ($l!=0)
    {
    rsort($a);

    Теперь массив $а содержит имена файлов с сообщениями, причем в первых элементах массива содержатся имена файлов с наибольшими номерами (т. е. самые новые - как и следует из приведенного выше алгоритма). Если же требуется обратный порядок (т. е. чтобы новые сообщения помещались в конец страницы), то вместо функции rsort (сортировка по убыванию) следует использовать функцию sort (т. е. сортировка по возрастанию).
    Ну и, наконец, вставим все файлы с сообщениями в страницу с гостевой книгой с помощью оператора include, перебрав последовательно элементы массива с именами этих файлов конструкцией foreach:

    foreach ($a as $value)
    {
    include ("$dirct/$value");
    echo ("<br>(разделитель сообщений)");

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

    Комментарий:
    Оператор foreach будет работать только в РНР 4.0 и выше. Если вы можете использовать лишь РНРЗ, то вместо него можно использовать цикл for, указав в его параметрах величину массива $1:
    for ($k = 1; $k < $1; $k++) {
    Для удобства можно записать значение очередного элемента массива в переменную: $value=$a[$k] ;

    Все - код вывода имеющихся сообщений завершен!

    }>

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

    <form method="post" action="otziv.php">

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

    <input name="nom" type="hidden" value="<?php echo $nom; ?>">

    Комментарий:
    Скрытое поле (типа hidden) не отображается в браузере, однако передается вместе с формой.

    Ну и - непосредственно поле ввода сообщения, уже, ясное дело, не скрытое:

    <textarea name="otziv" cols="60" rows="10" wrap="virtual"></textarea>

    И вездесущая кнопка отправки формы:

    <input name="submit" type="submit" value="Добавить отзыв"></form>

    Теперь осталось сделать программу-обработчик новых отзывов. Как это ни удивительно, но она уместится всего в пять строк. Разместить ее надо в том файле, имя которого указано в заголовке формы для ввода сообщения - в нашем случае это otziv.php (см. рис. 9.2).

    <?php

    Укажем сценарию имя папки с отзывами:

    $dirct="gb";

    В принципе, можно было бы это имя и передать через форму с помощью скрытого поля - типа hidden. А можно было бы и вообще не запоминать в переменную - указывать в сценарии в нужных местах само имя папки (т. е. "gb" в нашем случае) - и дело с концом. Просто так несколько нагляднее, да и в случае необходимости изменить это имя проделать данную операцию будет достаточно лишь в этом месте.
    Сгенерируем имя для нового файла с сообщением - просто соединим вместе индекс гостевой книги и временную метку Unix, полученную функцией time():

    $otznam=$nom.time();

    Как вы помните, при передаче сценарию РНР информации через форму значения ее полей записываются в переменные, имена которых соответствуют значениям параметров пате этих полей, поэтому индекс гостевой книги, переданный через поле формы с именем пот, и оказался в переменной Snom.
    Теперь создадим новый файл со сгенерированным именем и откроем его для записи - все это делается одной командой - f open с параметром w+.

    Примечание:
    Для того чтобы из программы на РНР считать содержимое какого-либо файла или записать в него данные, этот файл нужно сначала открыть - командой fopen (так уж устроен РНР). При этом открытому файлу присваивается некое "внутреннее имя" - так называемый дескриптор, и именно его возвращает функция fopen. Первый параметр fopen - имя файла (вместе с относительным или абсолютным путем к нему), второй — способ открытия файла.
    В зависимости от второго параметра функции fopen файл может быть открыт по-разному - для чтения, для записи, с очисткой содержимого или без таковой. Возможные параметры fopen такие:
    • r - открыть файл только для чтения и приготовиться читать его с начала.;
    • r+ - открыть файл для чтения и для записи и приготовиться работать с ним с его начала;
    • w - открыть файл только для записи, предварительно удалив из него все содержимое, причем если файл с указанным именем не существует, то создается новый файл с таким именем;
    • w+ - открыть файл как для записи, так и для возможного последующего чтения, предварительно удалив из него все содержимое, причем если файл с указанным именем не существует, то создается новый файл с таким именем;
    • а - открыть файл только для записи и приготовиться дописывать данные в его конец. Если файл с указанным именем не существует, то создается новый файл с таким именем;
    • а+ - открыть файл для записи и для чтения и приготовиться дописывать данные в его конец. Если файл с указанным именем не существует, то создается новый файл с таким именем.
    Открываемый файл может располагаться и на удаленном сервере - в этом случае он будет доступен только для чтения независимо от параметров открытия файла. Путь к файлу в таком случае следует указывать полностью - начиная с ht tp://muftp://.

    (В нашем случае можно также использовать параметр а+ - различие этих двух параметров, заключающееся в том, что fopen с параметром w+ очищает все содержимое открываемого файла, a fopen с параметром а+ нет, несущественно, так как файл все равно создается новый):

    $hdl = fopen("$dirct/$otznam", "w+");

    Проводить операции записи или чтения из файла средствами РНР можно только через дескриптор этого файла - некое "внутреннее имя", "поток вывода данных". Именно дескриптор, а не имя файла, придется указывать в функциях, совершающих эти действия. Дескриптор создается при открытии файла функцией fopen, которая его и возвращает -в данном случае он записывается в переменную Shdl.
    Теперь запишем в открытый файл отзыв (находящийся в переменной Sotziv - именно такое имя имело поле ввода отзыва в форме для его ввода), предварительно убрав из него специальной командой, возможно, содержащиеся в нем тэги HTML и команды РНР - дабы обезопасить сайт от действий злоумышленников:

    fwrite($hdl,strip_tags($otziv));

    Примечание:
    Команда fwrite (дескриптор файла, записываемая в файл строка) записывает указанную во втором параметре строку в файл, дескриптор которого указан в ее первом параметре.
    То место в файле, с которого совершается чтение данных и в которое осуществляется запись, называется указателем файла. (Если файл представить как тетрадь, то указатель - это открытая страница, вернее, номер открытой страницы.) При открытии файла командой fopen с параметрами r, r+, w или w+ указатель файла ставится на его начало, а при открытии с параметром а или а + -в самый конец.
    При записи в файл командой fwrite в том случае, если указатель находится не в конце файла, записываемые данные пишутся поверх имеющихся. Если же файл был открыт командой fopen с параметром а или a +, то вне зависимости от позиции указателя запись в файл идет в его конец, т. е. - после всех данных файла.
    Функция strip tags (строка) вырезает из строки, указанной в ее параметрах, все тэги — т. е. "все в угловых скобках", как HTML, так и РНР, ASP и другие, возвращая эту строку с вырезанными тэгами. Если какие-либо тэги вырезать не следует, то их можно перечислить во втором параметре данной функции: команда
    strip_tags (строка, ' <a><b><ixu> ') ;
    вырежет из указанной в первом параметре строки все тэги, кроме <а>, <Ь>, </>, <и>, т. е. оставит посетителю возможность оформлять ими свой текст.


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

    fwrite($hdl, htmlspecialchars($otziv));

    Примечание:
    Функция htmlspecialchars (строка) конвертирует все "специальные символы" в указанной в ее параметре строке в так называемые "мнемоники HTML", которые отображаются браузером на странице как эти самые символы. Конвертация происходит следующим образом:
    • & (амперсанд) заменяется на сочетание символов &атр;
    • " (двойная кавычка) заменяется на сочетание символов &quot ;
    • < (меньше) заменяется на сочетание символов &11 /
    • > (больше) заменяется на сочетание cимволов &gt ;
    Сочетания символов "&атр;", "&quot;", "&lt;", "&gt;" отображаются в браузере как амперсанд, двойная кавычка, знаки "меньше" и "больше" соответственно.
    В РНР третьей (начиная с подверсии 3.0.17) и четвертой (начиная с подверсии 4.0.3) версий в качестве второго аргумента можно также указать параметр ENTjQUOTES или ENTNOQUOTES. Если указан первый, то помимо вышеуказанных замен выполняется еще и замена символа ' (одинарной кавычки) на сочетание символов &#039;, а если указан второй - то никакие кавычки не заменяются.

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

    ГЛАВА 9. РНР: ГОСТЕВАЯ КНИГА 2 часть

    Комментарий:
    Любую информацию, запрашиваемую от посетителя и впоследствии выводимую на какую-либо страницу, весьма желательно перед выводом обработать какой-нибудь из этих функций, htmlspecialchars или strip_tags, - для обеспечения устойчивости сайта к взлому. Ибо даже в том случае, если вы на одной странице запрашиваете у посетителя e-mail, а на другой - его выводите на страницу, злоумышленник в поле ввода e-mail'a может поместить код на РНР, и тогда, будучи включенным в выведенную страницу без какой-либо обработки, этот код благополучно исполнится! А ведь в этом коде может быть что угодно - вплоть до команд удаления файлов. Поэтому не забывайте обрабатывать данными функциями все информацию, что была введена в элементы формы и будет отображаться на какой-либо странице.
    Даже скрытые поля и выпадающие списки могут нести в себе угрозу безопасности сайта - если получаемая из них информация выводится на экран. Ничто не мешает злоумышленнику сделать локальную копию страницы с формой на своем жестком диске, прописать в качестве страницы-обработчика полный путь к ней - вместе с адресом сайта и изменить в форме содержимое любых полей, в том числе и скрытых, поместив туда PHP-код. Так что будьте бдительны!

    Если Вы желаете, чтобы при отображении на странице сообщений сохранялась их разбивка отправителями на абзацы, то обработайте записываемое в файл сообщение командой nl2br для конвертации символов конца строки в тэги <br>, которые этот разрыв строки и означают:

    fwrite($hdl,nl2br(strip_tags($otziv)));

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

    $otziv=nl2br(strip_tags($otziv)); fwrite($hdl,$otziv);

    Примечание:
    Функция nl2bг (строка) вставляет перед каждым символом начала строки, встреченном в строке в ее параметре, тэг <br> -в РНР версии до 4.0.5, или <Ъг /> - в РНР более поздних версий. (Последний тэг совместим и с языком XML.)
    Файл можно закрыть - и закончить сценарий.

    fclose($hdl);
    ?>

    Такой код будет работать в РНР версии 3. В РНР версии 4 и выше с этим кодом тоже проблем не будет, однако лишь в том случае, если в конфигурационном файле РНР установлена как on опция register_globals. Настройка данного файла - прерогатива администратора web-сервера (хотя по умолчанию данная опция включена). Если register_globals установить в off, то переменные формы по их именам в сценарии-обработчике доступны не будут.
    Однако все переменные, передающиеся через форму, записываются еще и в специальный массив - с именем $HT TP_POST_VARS (если передача произведена методом post - т. е. в адресной строке значения передаваемых переменных не отображаются; вид передачи указывается в заголовке формы) или $HT TP_GET_VARS (если передача произведена методом get-с отображением в адресной строке передаваемых переменных). В РНР4 так происходит всегда, а в РНРЗ - только в том случае, если в конфигурационном файле РНР (настраиваемом администратором web-сервера) установлена как on опция track_vars. Элементы этих массивов названы именами этих переменных; так, переменная, указанная в поле с именем otziv формы, передающей введенные в нее значения методом POST сценарию в файле scen.php, будет доступна в этом сценарии в элементе массива $HT TP_POST_VARS['otziv'].
    Поэтому для того, чтобы не зависеть от настройки РНР администратором сервера, вышеприведенный код можно переписать, используя в нем вместо имен переменных формы - элементы массива, поименованные как эти элементы формы. В таком случае он будет выглядеть следующим образом:

    <?php
    $dirct="gb";
    $otznam=$HT TP_POST_VARS ['nom'].time();
    $hdl = fopen("$dirct/$otznam", "w+");
    fwrite($hdl,nl2br(strip_tags($HT TP_POST_VARS['ot ziv1])));
    fclose($hdl);
    ?>

    Начиная с РНР версии 4.1, кроме массивов $HT TP_POST_VARS и $HT TP_GET_VARS, программе на РНР доступны идентичные им массивы $_POST и $_GET, так что в том случае, если на сервере, где должны быть размещены ваши сценарии, установлен РНР этой или более старшей версий, то вы можете использовать и такие имена.
    Версию РНР вы можете узнать, включив в сценарий команду phpinf о ();. Она даст исчерпывающую информацию как по этому, так и по множеству других вопросов.


    При работе приведенного выше сценария после добавления нового сообщения в гостевую книгу (рис. 9.3) посетитель окажется на странице обработки отзывов, в данном случае otziv.php. Можно поместить на ней, например, фразу с благодарностью за добавленное сообщение. Однако куда лучше будет, если после добавления нового сообщения посетитель автоматически вернется в гостевую книгу, куда он только что добавил свое сообщение. Для того чтобы это сделать, можно поместить вконец обработчика строчку Header ("Location: имя_меЬ-страницы_с_гостевой_книгой"); указав имя нужной страницы (например, передав его в форме вместе с остальными переменными, т. е. количеством отзывов и индексом страницы), или просто включить обработчик в сам файл niz.php, а в качестве страницы-обработчика формы указать ту же самую страницу с гостевой книгой.
    В таком случае после отправки формы просто загрузится та же самая гостевая книга, но уже с добавленным новым сообщением. В результате весь код гостевой книги уместится в одном файле (а обслуживать он может хоть пару десятков отдельных гостевых книг!).
    Итак, вот полный, готовый к употреблению код сценария гостевой книги. Попробуйте разобраться в нем самостоятельно - это будет легко, ведь все его строки уже были подробно разобраны выше.
    В каждую страницу, на которой располагается гостевая книга, следует включить такой сценарий:

    <?php
    $пот="имя (без расширения) web-страницы, на которой расположена гостевая книга";
    include ("niz.php"); ?>
    Ну а файл niz.php должен содержать весь остальной код:
    <?рпр
    $dirct="gb"; if ($otziv!="")
    {
    $otznam=$nom.time();
    $hdl = fopen("$dirct/$otznam", "w+"); fwrite($hdl,nl2br(strip_tags($HT TP_POST_VARS['ot ziv'])));
    fclose($hdl);
    }
    $hdl=opendir($dirct); while ($file = readdir($hdl))
    {
    if (strstr($file, $nom)==True) { $a[]=$file;
    $l=sizeof($a); if ($l!=0)
    {
    rsort($a);
    foreach ($a as $k)
    include ("$dirct/$k");
    echo ("<br>(разделитель сообщений)");
    Ваш комментарий:
    <form method="post" action="<?php echo ("$nom".".php"); ?>" name="form">
    <textarea name="otziv" cols="60" rows="10" wrap="virtual"></textarea>
    <input name="submit" type="submit" value="Послать отзыв"></form>

    В отличие от разобранного нами кода тут нет необходимости передавать в форме индекс гостевой книги (так как он все равно устанавливается на странице гостевой книги и тем самым доступен и на всем протяжении включенного в нее niz.php), однако необходимо сообщить имя содержащего эту гостевую книгу файла - дабы именно его указать в качестве обработчика формы ввода сообщения. Проще всего именно это имя и указывать в качестве индекса гостевой книги.
    Хотя в принципе указывать в сценарии имя файла в качестве индекса гостевой книги не надо. В начало кода в файле niz.php можно включить код, который бы этот самый индекс определял бы автоматически. Скажем, брал бы значение переменной $PHP_SELF - она содержит имя текущего файла вместе с путем к нему от корневой директории сайта (даже если она находится в файле, включенном в текущий с помощью оператора include), скажем, "/guestbooks/gbOl.php", а затем вытаскивал из него само это имя.
    В РНР версии 4.1 и выше имя файла без расширения можно узнать командой basename (), указав в ее параметрах это самое расширение:

    $nom=basename($PHP_SELF, ".php");

    Примечание:
    Команда basename выделяет имя файла из его полного имени, указанного в ее параметре - вместе с путем по дереву директорий. Начиная с РНР версии 4.1, в ней можно также указывать расширение, которое должно быть отброшено в том случае, если оно будет найдено в имени файла. До версии 4.1 возможности только с помощью этой команды узнавать имя файла без расширения нет

    В РНР версии до 4.1 команда basename () имя файла без расширения выдать не сможет, однако расширение можно отбросить путем использования команды substr, указав в ее третьем параметре отрицательную величину - число символов от конца строки, которые не должны включаться в выделяемую строку (подробнее см. гл. 8):

    $nom=substr(basename($PHP_SELF), 0, -4);

    Если эту команду определения имени файла без расширения включить в самое начало кода файла niz.php, то установку значения переменной Snom на web-страницах, содержащих гостевые книги, можно убрать - достаточно одного оператора include:

    <?php include ("niz.php"); "?>

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

    <?php
    $dirct="gb";
    $nom=substr(basename($PHP_SELF), 0, -4);
    if ($otziv!=B")
    {
    $otznam=$nom.time();
    $hdl = fopen("$dirct/$otznam", "w+")
    fwrite($hdl, nl2br(strip_tags($HT TP_POST_VARS['otziv']))
    fclose($hdl); }
    $hdl=opendir($dirct); while ($file = readdir($hdl)) {
    if (strstr($file, $nom)==True) { $a[]=$file;
    $1=sizeof($a); if ($l!=0) {
    rsort($a);
    if ($l>10)
    {
    for ($i = 0; $i < 10; $i++)
    {
    include ("$dirct/$a[$i]n);
    echo ("<br>(разделитель сообщений)");
    else
    foreach ($a as $k)
    {
    include ("$dirct/$kB);
    echo ("<br>(разделитель сообщений)");
    }
    }
    }
    ?>
    Ваш комментарий:
    <form method="post" action="<?php echo ($nom.".php"); ?>" name="form">
    <textarea name="otziv" cols="60" rows="10" wrap="virtual"></textarea>
    <input name="submit" type="submit" value="Послать отзыв">
    </form>

    (Измененная часть кода выделена жирным.)
    Тогда на странице отобразятся лишь последние 10 сообщений. (Код, выводящий остальные сообщения так же, по десяткам, сделайте самостоятельно.)
    Так что, как видите, сделать гостевую книгу на РНР не просто, а очень просто. Весь ее код уместится на одном экране, даже на мониторах с небольшим разрешением. Но даже такой простой скрипт таит в себе немало возможностей для творчества.
     

    Вложения:

    • 1.gif
      1.gif
      Размер файла:
      7.5 КБ
      Просмотров:
      340
    • 2.gif
      2.gif
      Размер файла:
      37.2 КБ
      Просмотров:
      322
    • 3.gif
      3.gif
      Размер файла:
      33.4 КБ
      Просмотров:
      343
  10. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    Модератор, я все понимаю что разбитие на несколько частей не есть хорошо. Но текст более чем в 2к символов не помещается. Так как же быть? Зачем удалили то? Могли бы снять балы, я бы против ничего не говорил. А тут вы именно удалили сами сообщения....
     
  11. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ГЛАВА 10. РНР: СИСТЕМА ОЦЕНКИ МАТЕРИАЛОВ


    PHP: СИСТЕМА ОЦЕНКИ МАТЕРИАЛОВ

    В этой главе будет разобран сценарий, позволяющий посетителям выставлять оценки размещенным на сайте материалам. Ранее не использованных команд в нем почти нет, так что просто следите за логикой программы.
    Сначала подумаем. Что должен делать код выставления оценки? Ну вначале, наверное, принимать от посетителя значение оценки (скажем, из формы с элементами <select. . .>. . .<option>. . ..). Однако, если эта оценка является первой за всю историю существования статьи, то необходимо записать ее в файл. Если же ранее статья уже была оценена, то следует считать имеющееся значение из файла и вычислить среднее арифметическое всех оценок, включая только что добавленную. В самом деле, нам ведь нужна именно средняя оценка, не так ли? А затем это новое значение средней оценки необходимо в тот же файл и записать.
    Среднюю оценку можно посчитать по очевидной формуле

    (средний балл*количество оценок)+новодобавленная оценка /
    количество оценок + 1

    Кроме того, среднюю оценку желательно показать и посетителю. Простая вставка файла с оценкой в страницу со статьей с помощью команды include не является изящным решением, так как значение средней оценки может быть выражено и довольно длинной десятичной дробью. Следовательно, оценку желательно округлить хотя бы до сотых, а лучше - до десятых.
    Далее. Что должно произойти, когда посетитель выставит статье оценку? Первое, что приходит в голову - это отправить его назад на статью, которую он оценивал. Ведь направляли же мы в сценарии в прошлой главе посетителя назад в гостевую книгу после отправки им в.нее сообщения? Однако посетитель уже ведь прочитал статью, - зачем ему ее выводить снова, тратя его время в Сети, а, значит, и деньги. Куда как лучше после выставления оценки отправлять посетителя на специальную страницу с благодарностью о выполненном им действии и каталогом статей или разделов сайта.
    Желательна также и реализация "защиты от накруток", т. е. нельзя давать одному и тому же посетителю возможность голосовать несколько раз. Для этого можно использовать cookie, т. е. помечать с помощью cookie браузер посетителя при выставлении им оценки и впоследствии позволять выставлять оценку только при отсутствии такого cookie.

    Комментарий:
    Cookie - это файл в специальном формате, который присылается сервером браузеру посетителя сайта, расположенном на этом сервере. Браузер, если он поддерживает cookie (и эта поддержка в нем не отключена), помещает его в особое место и впоследствии отправляет назад на сервер при поступлении от него запроса. Иными словами, cookie позволяет серверу хранить свою информацию на компьютерах посетителей и считывать ее оттуда при необходимости. Подробнее о cookie читайте в гл. 8.

    Бесспорно, использование cookie - не очень надежная подобная защита. Ничего не мешает посетителю удалять cookie перед каждой новой попыткой выставления оценки или использовать разные браузеры, да и на общедоступных компьютерах проголосовать можно будет лишь единожды независимо от числа их пользователей до тех пор, пока cookie не будет удален. Но хоть что-то...
    Наверняка на сайте будет находиться немало статей, к которым стоит добавить форму выставления оценок. Для того чтобы не вставлять в каждый файл множество строк одинакового кода, стоит выполнить весь код выставления оценки в отдельном модуле и включать его с помощью команды include в статьи, оценка которых посетителями необходима.
    Итак, код выставления оценок разместится в двух файлах, один из которых предназначен для вставки в страницы со статьями, а второй содержит в себе текст благодарности посетителю за оценку. Допустим, первый файл будет называться niz.php, а второй - otziv.php. Что ж, приступим к самому тексту кода.
    В каждый файл со статьей, в то место, где должна располагаться форма для выбора оценки, следует вставить одну строчку кода:

    <?php include ("niz.php"); ?>


    ФАЙЛ NIZ.PHP

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

    <?php

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

    $dirct="cnt";

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

    $nom=substr(basename($PHP_SELF), 0, -4);

    ...а сами файлы назовем на основе этого имени, получив имя файла с количеством оценок прибавлением к нему окончания "kol", а имя файла со средним баллом - окончания "est" (рис. 10.1):

    $kolvooc="$nom"."kol"; $ocenka="$nom"."est";


    Слева - статьи, файлы со сценариями и папка с файлами оценок, справа -содержимое этой папки


    Теперь выведем сведения об уже выставленных оценках.

    echo ("Оценок этой статье - ");

    Если файл со сведениями о количестве оценок существует (он создается при первом оценивании)...

    if (file_exists("$dirct/$kolvooc")==True)
    {

    ...то вставим его значение в документ.

    include ("$dirct/$kolvooc");

    Если же такового файла нет, т. е. документ ни разу не оценивался...

    }
    else
    {

    ...выведем значение "0".

    echo ( " 0 " ) ;
    }

    Если файл со средним баллом существует...

    if (file_exists("$dirct/$ocenka")==True)
    {

    ...то надо вывести его значение.

    echo (". Средний балл - ");

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

    $hdl в fopen("$dirct/$ocenka", "r+");

    ...и считаем в переменную Ssred все содержимое этого файла.

    $sred = fread($hdl, filesize("$dirct/$ocenka"));

    Примечание:
    Функция fread (дескриптор файла, длина считываемого фрагмента) считывает из открытого файла, для которого получен указанный в ее первом параметре дескриптор, столько байт, сколько указано в ее втором параметре (чтение начинается с местонахождения так называемого указателя файла — отметки, показывающей текущее место работы с файлом; указатель двигается при чтении или записи в файл, а также при использовании команды fseek).
    Функция filesize (полный путь к файлу) возвращает размер указанного в ее параметре файла в байтах.

    Файл можно закрыть...

    fclose($hdl);

    ...а переменную $sred - округлить до десятых

    $sred=round ($sred, 1);

    Примечание:
    Функция round (число, количество разрядов) округляет дробное число в ее первом параметре до количества разрядов, указанного в ее втором параметре. Скажем, round (число, 1) округлит число до десятых, round (число, 2) - до сотых и т. д.

    В РНР до четвертой версии функция round могла округлять числа только до целых, поэтому в том случае, если вы располагаете только такой версией РНР, то команда округления до десятых должна выглядеть как

    $sred=(round ($sred*10))/10; ...и вывести на страницу.
    echo ("$sred.");
    }

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

    $haveestim=$nom."haveest";

    ...и проверим, определена ли переменная с таким именем - т. е. установлен ли одноименный cookie или нет (рис. 10.2). Можно было бы также проверять, какое значение имеет данная переменная, но для нашего сценария это неважно - если переменная установлена и cookie определен, то посетитель уже голосовал за данную статью: ведь cookie с данным именем устанавливается ему в этом и только в этом случае.

    if ($$haveestim=="")

    Обратите внимание на имя проверяемой переменной - это имя само является значением переменной Shaveestim (подобную конструкцию допускают правила РНР, подробнее смотрите в гл. 3).



    Поскольку значения cookies доступны и через массив $HT TP_COOKIE_VARS[], то проверить наличие cookie можно и на основе анализа значений этого массива:

    if ($HT TP_COOKIE_VARS[$haveestim]=="")

    или в РНР версии 4.1 и выше

    if ($_COOKIE[$haveestim]==" ")

    Комментарий:
    Помните, что доступность данных cookie зависит от настроек в файле php.ini (рис.10.3) - если в файле php.ini установлен в on параметр register_globals, то содержимое cookie доступно в сценарии в переменной с тем же именем, что и cookie, а если ephp.ini установлен в on параметр trackjvars, то содержимое cookie доступно в сценарии в одноименном с этим cookie элементе массива SHT TPCOOKIEVARSfJ (с РНР 4.1 -и $_СООК1Е[]).

    Использовать массивы $HT TP_COOKIE_VARS[] и $_СООК1Е[] лучше с точки зрения безопасности. Если в сценарии используются одноименные cookie переменные, а не элементы этих массивов, то в том случае, если cookie не установлен, злоумышленник все равно может передать сценарию значение такой переменной, попросту указав его в адресной строке браузера. В указанные же массивы попадают исключительно полученные с cookie данные. Однако в рассматриваемом в данной главе сценарии это несущественно. 118


    Если cookie не установлен - т. е. посетитель ранее не голосовал за данную статью...

    {

    то выведем ему форму для голосования

    . ?>
    <form method="post" action="otziv.php">

    Передадим в скрытом поле формы имя файла со статьей без расширения - для определения на основе него сценарием-обработчиком имен файлов со сведениями о количестве оценок и среднем балле, а также полное имя, вместе с путем, файла со статьей - для вывода ссылки "Назад" на странице со сценарием-обработчиком. В принципе можно было бы передавать через форму только полное имя файла со статьей, а "чистое" имя файла статьи определять в сценарии-обработчике точно так же, как и в сценарии из niz.php - на основе функции basename, но для сокращения длины кода в обработчике воспользуемся передачей его через форму.

    <input name="nom" type="hidden" value="<?php echo $nom; ?>">
    <input type=hidden name=nazad value=<?php echo ($PHP_SELF); ?>>

    Выведем форму ввода оценки:
    Поставьте оценку статье:

    <SELECT NAME=ocen>
    <OPTION VALUE=5>5 (Отлично)
    «DPTION VALUE=4>4 (Хорошо)
    <OPTION VALUE=3>3 (Удовлетворительно)
    <OPTION VALUE=2>2 (Плохо)
    <OPTION VALOE=1>1 (Очень плохо)
    </SELECT>

    В результате в сценарий-обработчик будет передана переменная Socen (и одноименные элементы массивов $HT TP_POST_VARS, $_POST при соответствующих версиях РНР и настройках в php.ini) со значением, равным параметру value выбранного пользователем пункта выпадающего списка.
    Выведем кнопку отправки формы (рис. 10.4).


    <input name="submit" type="submit" value="Послать оценку"></form>
    <?php

    А если посетитель уже голосовал за данную статью - т. е. cookie с соответствующим именем у него установлен...

    }
    else {

    ...то сообщим ему об этом (рис. 10.5).

    echo ("Вы уже голосовали за эту статью!");



    ФАЙЛ OTZIV.PHP

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

    <?php

    Поскольку изменять значения среднего балла и количества оценок имеет смысл лишь в том случае, если посетитель еще не голосовал за статью, то вновь составим имя cookie, служащего "пометкой" свершившегося голосования...

    $namecook=$nom."haveest";

    ...и весь дальнейший код выполним только в том случае, если такого cookie установлено не было.

    if ($$namecook=="")

    Примечание:
    Вместо этой строки можно использовать строку
    i f ($HT TP_COOKIE_VARS[$haveestim]=="") или в PHP версии 4.1 и выше — строку
    if ($_COOKIE[$haveestim]=="") как уже указывалось выше.

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

    Итак, если посетитель еще не голосовал за данную статью...

    {

    ...установим cookie, говорящий, что такое голосование наконец совершилось. Время жизни cookie установим в месяц - пожалуй, хватит. (Пояснение по функции установки cookie смотрите в гл. 8).

    SetCookie("$namecook","1",time()+2 592000);

    Запишем в переменные имена директории с файлами оценок и самих этих файлов:

    $dirct="cnt";
    $kolvooc="$nom"."kol";
    $ocenka="$nom"."est";

    Если файлы оценок не существуют (т. е. выставляемая оценка - вообще первая по счету)...

    if ((file_exists("$dirct/$kolvooc")!=True)||
    (file_exists("$dirct/$name2")!=True)) {

    ...то запишем в файл со сведениями о количестве оценивших число 1 (так ведь и есть, не правда ли?)...

    $hdll = fopen("$dirct/$kolvooc", "a+"); fwrite($hdll,l); fclose($hdll);

    ...а в файл со сведениями о среднем балле - выставленную посетителем оценку (она ведь и есть "среднее" от самой себя):

    $hdl2 = fopen("$dirct/$ocenka", "a+");
    fwrite($hdl2,$ocen);
    fclose($hdl2);

    Если же файлы со сведениями об оценке уже существуют...

    else

    ...то считаем для начала содержимое файла с количеством оценок в переменную

    kvo...
    $hdll = fopen("$dirct/$kolvooc", "r+");
    $kvo ¦ fread($hdll, filesize("cnt/$kolvooc"));

    ...а затем увеличим значение этой переменной на 1 - что и будет новым количеством оценок, с учетом последней выставленной:

    $kvo++;

    Теперь нам надо вернуть точку считывания (так называемый "указатель") в начало файла - для того, чтобы записать в файл новое значение количества оценок. Ведь в результате проведения операции чтения количества оценок из файла точка считывания - указатель - переместилась в его конец. Для совершения данной операции воспользуемся командой rewind:

    rewind($hdll);

    Примечание:
    Команда rewind (дескриптор открытого файла) перемещает точку считывания и записи данных в файл (т. е. указатель файла), в начало этого файла. Если вы записываете что-либо в файл после считывания из него данных, то вам необходимо перед записью воспользоваться этой командой.
    Следует помнить, что если файл был открыт командой fopen с параметром а или a+, то независимо от положения указателя запись новых данных командой fwrite будет осуществляться вконец файла.

    Запишем новое значение количества оценок в предназначенный для хранения этой величины файл...

    fwrite($hdll,$kvo);

    ...и закроем его.

    fclose($hdll);

    Теперь разберемся со средним баллом. Откроем файл, где хранится его значение...

    $hdl2 = fopen("$dirct/$ocenka", "r+");

    ...запишем это значение в переменную...

    $sred= fread($hdl2, filesize("cnt/$ocenka"));

    ...и рассчитаем новую величину среднего балла - на основе его старого значения, а также информации о количестве оценок и новой оценки.

    $sred=($sred*($kvo-l)+$ocen)/$kvo;

    Теперь запишем эти сведения в предназначенный для них файл -точно так же, как и парой абзацев выше.

    rewind($hdl2); fwrite($hdl2,$sred); fclose($hdl2);

    Собственно, и все.
    Можно выводить информацию посетителю об итоговом результате (рис. 10.6) или краткую благодарность.

    echo ("Благодарим вас за оценку!");



    Если же посетитель уже голосовал за данную статью...

    }
    else {

    ...то сообщим ему об этом (рис. 10.7) - и ничего делать не станем, echo ("Вы уже голосовали за эту статью!");

    }
    Сценарий закончен. ?>

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

    <?php echo ("<a href=$nazad>Ha3afl</a>"); ?>

    Переменная Snazad была передана через форму, помните?

    Комментарий:
    В данном сценарии для упрощения восприятия значения переменных, передаваемых через форму, брались из одноименных переменных в сценарии-обработчике - так как на безопасность работы программы это здесь не влияет: даже если злоумышленник подставит значение переменной cookie в адресную строку, то он только потеряет возможность проголосовать, и ничего больше. Если вы желаете сделать код лучше соответствующим правилам РНР - замените их на одноименные элементы массива $HT TP_POST_VARS[] (в РНР версии до 4.1) или SPOSTfJ (в РНР версии 4.1 и старше).

    Как всегда, сценарий можно совершенствовать до бесконечности. Можно, например, совместить его с разбиравшемся в предыдущей главе сценарием гостевой книги - тогда посетители наряду с оценкой статьи могут оставить и свой отзыв на нее. Можно увеличить количество возможных оценок, которые посетители могут выставлять статьям -использовать 10-балльную или иную систему. Все в вашей власти - творите...




    ТЕКСТ СЦЕНАРИЯ

    Для большей наглядности ниже приводится текст сценария целиком, без разрывов.

    Вставка в файлы со статьями:

    <?php include ("niz.php"); ?>

    Файл niz.php

    <?php
    $dirct="cnt";
    $nom=substr(basename($PHP_SELF), 0, -4); $kolvooc="$nom"."kol"; $ocenka="$nom"."est"; echo ("Оценок этой статье - "); if (file_exists("$dirct/$kolvooc")==True) {
    include ("$dirct/$kolvooc"); }
    else {
    echo (" 0") ; }
    if (file_exists("$dirct/$ocenka")==True) {
    echo (". Средний балл - "); $hdl = fopen("$dirct/$ocenka", "r+"); $sred = fread($hdl, filesize("$dirct/$ocenka")); fclose($hdl); $sred=round ($sred, 1); echo ("$sred."); }
    $haveestim=$nom."haveest"; if ($$haveestim=="")
    <form method="post" action="otziv.php">
    <input name="nom" type="hidden" value="<?php echo $nom; ?>">
    <input type=hidden name=nazad value=<?php echo ($PHP_SELF); ?>>
    Поставьте оценку статье:
    <SELECT NAME=ocen>
    <OPTION VALUE=5>5 (Отлично)
    <OPTION VALUE=4>4 (Хорошо)
    <OPTION VALUE=3>3 (Удовлетворительно)
    <OPTION VALUE=2>2 (Плохо)
    <OPTION VALUE=1>1 (Очень плохо)
    </SELECT>
    <input name="submit" type="submit" value="Пocлaть оценку"></form>
    <?php
    }
    else {
    echo ("Вы уже голосовали за*эту статью!"); } ?>

    Файл otziv.php

    <?php
    $namecook=$nom."haveest"; if ($$namecook=="") {
    SetCookie("$namecook","1",time()+2592000);
    $dirct="cnt";
    $kolvooc="$nom"."kol";
    $ocenka="$nom"."est";
    if ((file_exists("$dirct/$kolvooc")!=True) ||(file_exists("$dirct/$name2")!=True))
    {
    $hdll = fopen("$dirct/$kolvooc", "a+");
    fwrite($hdll,1)j
    128
    fclose($hdll);
    $hdl2 = fopen("$dirct/$ocenka", "a+");
    fwrite($hdl2,$ocen);
    fclose($hdl2);
    else
    $hdll = fopen("$dirct/$kolvooc", "r+");
    $kvo = fread($hdll, filesize("cnt/$kolvooc"))
    $kvo++;
    rewind($hdll);
    fwrite($hdll,$kvo); .
    fclose($hdll);
    $hdl2 = fopen("$dirct/$ocenka", "r+");
    $sred= fread($hdl2, filesize("cnt/$ocenka"));
    $sred=($sred*($kvo-l)+$ocen)/$kvo;
    rewind($hdl2);
    fwrite($hdl2,$sred);
    fclose($hdl2);
    echo ("Благодарим вас за оценку!"); else echo ("Вы уже голосовали за эту статью!");

    Ниже в этом же файле:

    <?php echo ("<a href=$nazad>Ha3afl</a>"); ?>
     

    Вложения:

    • 1.gif
      1.gif
      Размер файла:
      9.4 КБ
      Просмотров:
      329
    • 2.gif
      2.gif
      Размер файла:
      4.7 КБ
      Просмотров:
      300
    • 3.gif
      3.gif
      Размер файла:
      28.2 КБ
      Просмотров:
      332
    • 4.gif
      4.gif
      Размер файла:
      20.7 КБ
      Просмотров:
      311
    • 5.gif
      5.gif
      Размер файла:
      18.8 КБ
      Просмотров:
      318
  12. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ГЛАВА 11. РНР: ФАЙЛОВЫЙ МЕНЕДЖЕР 1 часть


    PHP: ФАЙЛОВЫЙ МЕНЕДЖЕР

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


    ПРОЕКТИРОВАНИЕ

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

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

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

    Как все это сделать?
    Как посетителю выбрать вид действия над файлами? Можно, конечно, выделить для каждого указанного выше действия по отдельной web-странице, разместить на этих страницах соответствующие сценарии, при этом для их выполнения посетителю придется заходить на нужную страницу. Однако это весьма неудобно. Лучше дать посетителю возможность выбирать вид действия прямо на той же самой странице, где отображается список файлов.
    Как осуществить такой выбор действия? Можно, конечно, создать группу единственного выбора, состоящую из нескольких radio buttons (она представляет собой группу кружков, отметить из которых можно только один - рис. 11.1, слева), а в сценарии выполнения действия определять, какой пункт был отмечен. Однако интереснее будет для выбора действия использовать кнопки типа submit (рис. 11.1, справа), нажатие которых вызовет переход на страницу-обработчик формы, содержащей эти кнопки. Посетитель, отметив файлы, просто нажмет нужную кнопку и будет ждать результата.


    Комментарий:
    Возникает вопрос: а как сценарий-обработчик различит, какая кнопка из четырех была нажата? Очень просто. Каждой кнопке необходимо присвоить имя и проверять в сценарии-обработчике значение переменной с этим именем. Кнопка - это часть формы, следовательно, для нее тоже создается переменная с тем же именем, а также элементы массивов $ HT TP_POST_VARS[имя кнопки] и в РНР версии 4.1 и старше - и $ POST [имя кнопки]. Обработка формы происходит так, что в ту переменную, имя которой совпадает с именем нажатой кнопки, будет помещено значение value этой кнопки (т. е. то, что было надписью на ней), переменные же остальных трех кнопок будут пустыми. На основании «пустоты» или «непустоты» соответствующих переменных и будем судить о том, какое действие выбрал посетитель.

    Для того, чтобы посетитель имел возможность указать сценарию объекты действий - т. е. над какими файлами эти действия должны производиться - достаточно против каждого имени файла поставить checkbox (пункт, который можно отметить галочкой, см. на рис. 11.3-11.6), разместив все checkbox'bi в единой форме, а затем анализировать состояние checkbox`ов в программе-обработчике формы.
    Итак, в первом файле нашего файлового менеджера должна располагаться форма, содержащая список файлов и папок в текущей директории (выводимый специальным сценарием, позволяющим также перемещаться по вложенным папкам) со спескЬох'ами возле каждого названия файла или папки, а в низу формы должны располагаться четыре кнопки типа submit с различными именами.
    Но простого выбора действия недостаточно для начала его выполнения. Перед тем, как совершать работу, у посетителя необходимо еще выяснить:

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

    основной, отображающий список файлов в директории, позволяющий также перемещаться по дереву папок, отмечать нужные и выбирать тип действия над ними. Назовем его index.php.
    файл запросов, запрашивающий у посетителя информацию для совершения выбранного действия - место назначения копирования, новые имена для переименованных файлов, имя для новосозданной папки или выдающий запрос на подтверждение удаления. Назовем его zapros.php.
    файл действия, собственно выполняющий выбранное действие, а после его выполнения - автоматически перенаправляющий посетителя на основной файл.
    Графическую схему смотрите на рис. 11.2.



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


    ФАЙЛ INDEX.PHP

    Сценарий в этом файле отображает список файлов и предоставляет посетителю возможность выбрать файлы для совершения над ними действия и вид этого действия.
    Сначала в сценарии производится вывод на страницу списка файлов и папок в текущей директории и предоставляется возможность открыть любой файл или перейти в другую папку.
    Просканировать папку и вывести список файлов можно с помощью сценария наподобие "Папкопотрошилки", описанного в 6-й главе. Поскольку планируется использовать одну и ту же страницу для отображения содержимого как корневой, так и любой из вложенных папок, то сценарию на этой странице нужно знать, список файлов в какой конкретно папке ему отображать, а также как составить ссылки на эти файлы, с указанием какого пути -"чтобы из файлового менеджера их можно было просматривать.
    Проще всего передавать сценарию информацию о том, список содержимого какой папки подлежит выводу на экран, через переменную в адресной строке - попросту указав в ней путь от корневой папки к текущей. Скажем, если корневая папка имеет название files, то она будет открываться по ссылке index.php?f old=f iles, а вложенная в нее папка folded - по ссылке index. php?f old= files /folder 1. (Как видно из текста ссылок, информация о пути к текущей папке будет доступна сценарию на странице из значения переменной Sfold, и именно значение этой переменной и будет подставляться в сценарии в качестве имени папки для сканирования.)
    Например, на рис. 11.3 файловый менеджер отображает содержимое папки f iles/Folder2/Folder3. Обратите внимание на адресную строку браузера.


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

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

    <htmlx?php

    Укажем корневую папку аккаунта посетителя - т. е. ту, с файлами и папками в которой ему разрешено работать, и запишем ее имя в переменную для дальнейшего использования в сценарии. Пусть эта папка называется files.

    $begin="files";

    Комментарий:
    Разумеется, можно не записывать имя корневой папки аккаунта в переменную, а просто использовать это имя в сценарии там, где это потребуется. Но тогда в том случае, если вам потребуется переименовать корневую папку, вам придется просматривать все тексты сценариев и заменять старое имя папки на новое везде, где оно встречается. Если же имя записано в переменную, то достаточно будет изменить лишь ту строчку, где эта запись производится.

    Теперь проверим:

    определена ли вообще содержащая путь к отображаемой папке переменная $fold (т. е. присутствует ли она в адресной строке - ее там не будет, если к странице с файловым менеджером обратились по внешней ссылке, а не с этой же страницы по ссылке на какую-либо папку из списка файлов и папок);
    не содержит ли она двух точек подряд - признака попытки взлома;
    начинается ли наличествующий в ней путь с имени корневой папки аккаунта (помещенного строчкой выше в переменную Sbegin):
    if ((strpos($fold,$begin)!=0)| (strpos($fold,"..")!=False)||($fold==""))
    {
    Примечание:
    Функция strpos (строка - объект поиска, искомая комбинация символов) возвращает либо номер позиции, на которой в указанной в ее первом параметре строке находится указанная во втором параметре комбинация символов, либо False - если таковая не найдена вообще.
    Чтобы различить возможные результаты работы функции "комбинация символов найдена в строке на позиции 0" и "комбинация символов в строке не найдена", можно использовать при сравнении сочетание трех знаков равенства — это означает проверку на "тождественность ":
    if (strpos ("строка", "символы") ===0) {... будет верно, если "строка" начинается с "символов".
    Можно также проверять результат на принадлежность к целым числам:
    if (is_integer (strpos ("строка ", "символы")==false) {...
    выполнится, только если в "строке" "символы" не найдены.

    и если переменная не определена или путь в ней не начинается с имени корневой папки или содержит две точки подряд, то выведем содержимое корневой папки - для удобства запишем ее имя в переменную $dirct, с которой мы и будем в дальнейшем работать как с содержащей путь к текущей папке:

    $dirct=$begin;
    }
    else
    {

    а если переменная Sfold "в порядке", то в переменную Sdirct поместим именно ее значение:

    $dirct=$fold;
    }

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

    echo ("<form action=zapros.php?folder=$dirct method=post>");

    В том случае, если текущая папка не является корневой, выведем ссылку на родительскую папку - т. е. ту, которая содержит в себе текущую...

    if ($dirct!=$begin) {

    для чего выделим из пути к текущей папке его часть с начала вплоть до последнего слэша - разделителя директорий; это и будет путь к родительской папке (скажем, если путь к текущей папке -f iles/folderl/papkal, то путь к родительской папке будет выглядеть как f iles/f olderl):

    $back=substr ($dirct, 0, strrpos($dirct, "/"));

    ГЛАВА 11. РНР: ФАЙЛОВЫЙ МЕНЕДЖЕР 2 часть

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

    и выведем ссылку на родительскую папку, попросту передав полученный путь к ней через переменную $fold:

    echo ("<a href=index.рbр?:?о1с1=$bаск>Корневая папка</а><br>");

    Все это делается, естественно, лишь в том случае, если текущая папка - не корневая.
    }
    Теперь можно и сканировать текущую папку. Получаем список файлов в ней (пояснения смотрите в гл. 6 - в описании сценария "Папкопотрошилка"):

    $hdl=opendir($dirct); while ($file = readdir($hdl)) {
    if (($file!="..")&&($file!=".")) { $a[]=$file;
    } }
    closedir($hdl);

    В том случае, если файлы в папке есть...

    if (sizeof($a)>0) {

    отсортируем массив с их именами по алфавиту. К сожалению, при этом имена папок окажутся перемешанными с именами файлов, но делать специальную функцию сортировки пока не будем: asort($a);
    Теперь надо вывести на страницу имена файлов и папок, причем каждое имя должно быть ссылкой на соответствующий файл или папку, а перед именем должен стоять checkbox для возможности выбора соответствующих файлов и папок для совершения над ними действий.
    С каждым именем файла или папки...
    foreach ($a as $k) { поступим следующим образом.

    Примечание:
    Оператор foreach считывает указанную в его параметрах переменную, в данном случае $к, все элементы массива, в данном случае $а, по очереди выполняя каждый раз указанный после него в фигурных скобках код, в котором может использоваться указанная переменная. Foreach будет работать только в РНР 4.0 и выше. Если вы можете использовать лишь РНРЗ, то вместо него можно использовать цикл for, указав в его параметрах величину массива $1.

    Вначале запишем в переменную путь к данному файлу или папке -относительный от той директории, где находятся файлы самого файлового менеджера. Для этого просто прибавим имя данного файла или папки к пути к текущей директории:
    $full=$dirct."/". $k; Теперь выведем checkbox:

    echo ("<input name=fl[] value=$k type=checkbox>");

    При передаче формы странице-обработчику будет передан массив $fl, состоящий из значений атрибутов value отмеченных checkbox'oe (только отмеченных - неотмеченные игнорируются). А в качестве значений атрибутов value мы указываем имена файлов. Так что сценарию-обработчику будет полностью ясно, с какими файлами ему работать - путь к текущей папке будет передан в переменной в ссылке на обработчик, указанной в заголовке формы, а имена файлов передадутся в массиве $fl.
    Если очередной элемент массива с именами файлов в текущей директории является папкой...

    if (is__dir ($full)==True)

    Примечание:
    Функция is_dir возвращает True, если указанный в ее параметре объект существует и является папкой.

    то выведем ссылку на нее. Вернее, не на нее, а на этот же файл нашего файлового менеджера - index.php, передав ему в качестве пути к текущей папке - в значении переменной Sfold - записанный нами ранее в переменную Sfull полный путь к данной папке:

    echo ("<a href=index.php?fold=$full><b>nariKa $k</bx/a>") ;

    Ну и укажем в качестве текста ссылки название папки, пояснив, что эта ссылка ведет именно на папку (см. рис. 11.4).
    В результате перехода по такой ссылке файлу index.php будет передан новый путь - путь к "открываемой" папке - и посетитель сможет увидеть список файлов в ней.
    Если же очередной элемент массива с именами файлов в текущей директории - всего лишь файл...

    }
    else {

    то просто выведем ссылку на него. Тем более что полный путь к нему мы уже ранее записали в переменную. Ну и, естественно, укажем в качестве текста ссылки его имя.

    echo ("<a href=$full>$k</a>");
    }

    После вывода ссылки - либо на файл, либо на папку - выведем разделитель строк, чтобы список имен файлов и папок представлял из себя аккуратный столбик:
    echo ("<br>");
    и перейдем к следующему элементу с именами файлов в текущей директории.
    }
    Все эти действия производятся, если в текущей папке есть файлы. Ну а если файлов нет - то и делать ничего не надо.

    } ?>

    Теперь отобразим кнопки выбора действия над выделенными файлами. Их будет четыре - "Удалить", "Переименовать", "Копировать", "Создать папку" с именами "udal", "ren", "copy", "md" соответственно.

    <br><input type=submit value="Удaлить" name=udal><br><input type=submit | value="nepeименовать" name=renxbrxinput type=submit value="Koпировать" name=copy><br><input type=submit value="Создать папку" name=md>

    Собственно, сам текст сценария закончен...

    < / f ormx /html>

    хотя, бесспорно, внешний вид страницы с ним будет весьма аскетичным (рис. 11.4, 11.5). Но художественное оформление страницы - уже ваша прерогатива.


    ФАЙЛ ZAPROS.PHP

    Сценарии этого файла запрашивают от посетителя дополнительную информацию для проведения действия. Начало сценария:

    <html><?php

    Сразу же выведем заголовок формы, общий для всех четырех вариантов запросов. В нем точно так же передадим выполняющему собственно действия сценарию на странице do.php имя текущей папки:

    echo ("<form action=do.php?folder=$folder method=post>");

    Бесспорно, можно было бы и не передавать имя текущей папки, а сообщать обработчику конкретные имена файлов, над которыми совершается действие, с полным путем к ним, однако так все-таки проще.

    УДАЛЕНИЕ, ЗАПРОС ИНФОРМАЦИИ

    Если на основной странице файлового менеджера - index.php - была нажата кнопка "Удалить", имя которой - "udal", то значение переменной $udal' в сценарии на странице-обработчике будет отличным от нуля (вернее, оно будет представлять собой значение атрибута value кнопки "Удалить" на основной странице -^собственно слово "Удалить"). Если была нажата какая-нибудь другая кнопка, то значение переменной $udal определено не будет. Поэтому для того, чтобы узнать, было ли посетителем выбрано в качестве желаемого действия удаление, проверим содержимое этой переменной:

    if ($udal!="")

    Выведем небольшое пояснение посетителю...

    echo ("Удалить файлы?<bг>");

    и список файлов, которые планируется удалить. Их список передан в форму в массиве $fl. В этот массив включены параметры value тех checkbox'oB, которые были отмечены посетителем на основной странице менеджера файлов перед тем, как нажать кнопку с названием действия (а в эти параметры, как вы наверняка помните, были помещены имена файлов и папок, отображавшихся на основной странице файлового менеджера - путь к ним передан через переменную Sfolder в адресной строке). Переберем все элементы массива $ f 1...

    foreach ($fl as $i)
    {

    и выведем их значения - имена файлов, подлежащих удалению. Вместе с именем папки, в которой они расположены - его сценарий на этой странице получил через адресную строку.
    Ну а для того, чтобы иметь возможность эти имена передать сценарию на следующей странице, выполняющему собственно действие,
    Строго говоря, вместо имен переменных, равных именам элементов формы, обрабатываемой сценарием на этой странице, следовало бы использовать имена соответствующих элементов массивов SHT TP_POST_VARS[] и (в РНР начиная с версии 4.1) $_POST[]. Однако для более легкого понимания кода выбран первый вариант. При использовании настоящего сценария на практике вы можете сами заменить имена переменных на имена элементов упомянутых массивов.
    рядом с каждым именем удаляемого файла поместим скрытое поле, в которое поместим это самое имя. Сценарию, выполняющему удаление, останется только совершить эту операцию над теми файлами, имена которых ему будут переданы.
    Имя же папки, в которой эти файлы располагаются, передается сценарию - исполнителю действия через адресную строку, указанную в заголовке формы запроса информации - точно так же, как оно было передано данному сценарию, запрашивающему дополнительную информацию. Вы могли видеть этот заголовок несколькими абзацами выше.


    Как и на первой странице, все эти скрытые поля сделаем массивом, для удобства - даже присвоим ему то же имя flf ]:

    echo ("<input type=hidden name=fl[] value=$i>$i из папки $folder<br>");
    }

    И наконец, выведем кнопку, запускающую собственно удаление. Назовем ее точно так же, как и расположенную на основной странице - для единообразия:

    echo ("<input type=submit value = \"Удалить" name=udal>");

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

    КОПИРОВАНИЕ, ЗАПРОС ИНФОРМАЦИИ

    Для того, чтобы произвести копирование файлов и папок из одной папки в другую, простого согласия пользователя на это действие мало. Нужно еще узнать, а в какую папку необходимо производить копирование.
    А что нужно, чтобы это узнать? Необходимо выдать запрос на получение имени этой папки у пользователя. Можно, конечно, предоставить пользователю возможность просто ввести новый путь в поле ввода текста, как при использовании команды сору в командной строке MS-DOS. Но это представляется весьма неудобным. Лучше, наверное, вывести пользователю список всех имеющихся на его аккаунте папок, из которых он сможет выбрать нужную. Пометить имя каждой папки радиокнопкой (кружком из группы единственного выбора, см. рис. 11.1, 11.7) - и для выбора папки назначения копирования достаточно будет только ткнуть мышью в нужном месте).
    Но как вывести список всех папок? Ведь они могут быть вложены друг в друга, так что простое сканирование корневой директории не поможет... А команд в нашем распоряжении для достижения данной цели не так и много. Считать список содержимого каталога, определить, является ли тот или иной элемент, содержащийся в каталоге, так же директорией, - вот, собственно, и все, что нам может предложить РНР.
    И тут придет на помощь принцип рекурсии.
    Под рекурсией понимается запуск программы из самой этой программы. Иными словами - вот программа запускается, исполняется, исполняется - а затем очередная команда представляет собой не что иное, как вызов этой самой программы! и вновь программа исполняется с начала, исполняется... и опять доходит до вызова самой программы, и опять исполняется с начала.
    Разумеется, для того чтобы программа с рекурсией имела какой-то смысл, а не представляла из себя бесконечно повторяемые действия, на каком-то этапе данный процесс должен прерваться. Иными словами, запуск программы изнутри самой программы должен происходить не каждый раз при ее работе, а в зависимости от того, выполняется ли определенное условие. Естественно, рано или поздно в ходе работы программы условие должно перестать выполняться, и тогда рекурсия прервется - исходная программа изнутри нее самой запущена при невыполнении условия не будет.
    Как же принцип рекурсии можно использовать для построения списка всех папок на аккаунте? А алгоритм построения этого списка при использовании рекурсии прост:

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

    if ($copy!="")
    {

    Для удобства запишем в переменную название корневой папки аккаунта пользователя. Впоследствии мы будем ее неоднократно использовать в коде.

    $begin="files";

    Выводим запрос пользователю...

    echo ("Объекты для копирования:<br>");

    и, точно так же, как в блоке кода, посвященном удалению файлов, выводим список объектов, подлежащих копированию (сравните - код практически такой же):

    foreach ($fl as $i)
    {
    echo ("<input type=hidden name=fl[] value=$i>$folder/$i<br>") ;

    Еще один запрос...

    echo ("<bг>Выберите папку для копирования :<br>") ;
    и начинаем вывод дерева папок - вызываем функцию tree.
    tree($begin);
     

    Вложения:

    • 1.gif
      1.gif
      Размер файла:
      3 КБ
      Просмотров:
      329
    • 2.gif
      2.gif
      Размер файла:
      30 КБ
      Просмотров:
      296
    • 3.gif
      3.gif
      Размер файла:
      10.3 КБ
      Просмотров:
      303
    • 4.gif
      4.gif
      Размер файла:
      11.8 КБ
      Просмотров:
      299
    • 5.gif
      5.gif
      Размер файла:
      12.8 КБ
      Просмотров:
      284
    Последнее редактирование модератором: 26/11/15
  13. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    РЕКУРСИВНАЯ ФУНКЦИЯ ВЫВОДА СПИСКА ДОСТУПНЫХ ДЛЯ КОПИРОВАНИЯ ПАПОК НА АККАУНТЕ

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

    function tree($fId)

    Поскольку в функции будут использоваться переменные еще и из других частей программы на странице, такие как Sfolder (путь к текущей папке) и массив $fl (список копируемых объектов; имена тех папок, что перечислены в нем, выводиться на страницу не будут, так как папку нельзя скопировать саму в себя или в свою же вложенную папку), то эти переменные необходимо объявить как глобальные в самой функции, указав их в ее начале после слова global:

    global $folder; global $fl;

    Комментарий:
    Массив Sfl был передан сценарию запроса дополнительной информации с помощью формы на основной странице файлового менеджера — методом POST. Поэтому он также доступен через массив $HT TP_POST_VARS - как его элемент $HT TP_POST_VARS['fl'J (если в файле конфигурации РНР установлен в on параметр track_vars). Для использования этого массива в функции его надо также объявить глобальным - командой global $HT TP_POST_VARS;.

    В РНР 4.1 версий и выше массив Sfl доступен и через массив $_POST. В отличие от $HT TPJPOST_VARS этот массив автоглобальный — т. е. для использования в функциях его элементов объявление самого массива в функциях производить не надо.
    Если вы пожелаете заменить в рассматриваемой программе все вхождения переменной-массива Sfl на соответствующие им элементы массивов SHT TPPOSTVARS или SPOST, то помните, что последние нельзя для вставки их значений в строку указывать в тексте строки — для этого следует использовать оператор конкатенации (точку).
    Начинаем сканировать папку, имя которой было передано в вызове функции, при помощи того же сценария, который мы уже неоднократно использовали, он разбирался еще в главе "Папкопотрошилка". При первом вызове функции ей передается имя корневой папки аккаунта, с нее функция и начинает свою работу.

    $hdl=opendir($fld);
    while ($file = readdir($hdl)) if ( ($file!=°.")&&($file!=".."))
    Для удобства запишем полное имя - вместе с путем - очередного взятого из папки объекта в переменную $f llnm:
    $fllnm=$fld."/".$file;

    Если этот объект - тоже папка...

    if (is_dir($fllnm)==True)

    то выясним:

    не является ли данная папка одновременно и объектом копирования? Если является - то, во-первых, в списке папок она появиться не должна - папку нельзя скопировать саму в себя, а, во-вторых, сканировать ее вложенные папки тоже незачем - копировать одну папку в другую, вложенную в нее, еще никому не удавалось;
    не в этой ли самой папке находится копируемый файл? Если в этой же самой папке - то выводить ее имя бессмысленно: копирование файла на свое же место возможно, но никаких за собой последствий не влечет.
    Для начала сравним полное имя (вместе с путем от корневой директории аккаунта) очередной найденной в сканируемой директории папки со всеми именами копируемых объектов (естественно, тоже полными). Если хоть одно такое имя совпадет с именем папки - то выводить имя этой папки в список доступных для копирования нельзя.

    $по=0;
    foreach ($fl as $i)
    if ($fllnm==$folder."/".$i) $no=l;

    Переменная $по примет значение 0, если совпадений не было, и 1, если были.

    Комментарий:
    Обратите внимание на способ фиксирования совпадения имен папок при их переборе - при помощи изменения значения ранее установленной переменной: в данном случае - $nо.
    Используйте такой же способ, если вам надо узнать, произошло ли то или иное событие внутри какого-нибудь цикла - установите до цикла переменную в ноль, а внутри цикла в случае совершения события присвойте ей значение 1. Тогда после окончания цикла переменная будет равна 1, если событие произошло, и 0, если нет.

    Итак - если очередная папка из сканируемой директории не является объектом копирования...

    if ($no==0)

    { и эти объекты копирования расположены не в ней...

    if ($fllnm!=$folder)

    то ее имя можно вывести в качестве возможного пункта назначения копирования, снабдив его radio button - т. е. "кружком" для единственного выбора. (После отправки формы результат выбора окажется в переменной $rd в сценарии выполнения действия.)

    echo ("<input name=rd type=radio value=$fllnm>$fllnm<br>");

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

    То, что папка содержит копируемые файлы, является препятствием к выводу имени этой папки на экран как возможнего пункта назначения копирования. Но это отнюдь не значит, что в данной папке не должны сканироваться вложенные папки. Поэтому оператор i f определяет, не содержит ли рассматриваемая папка копируемых файлов, завершаем...

    } и вот он - рекурсивный вызов функции tree:

    tree ($fllnm);

    Осталось закрыть все незавершенные операторы и циклы,

    }
    }
    }
    }

    и "потрошимую" директорию.

    closedir($hdl);

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

    Как уже было сказано, функция tree () должна находиться в коде перед блоком запроса дополнительной информации для копирования.


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

    if ($begin!=$folder) {
    echo ("<brxinput name=rd type=radio value=$begin>$begin<br>");

    и вывести кнопку запуска копирования.

    echo ("<input type=submit value=\"Скопировать\" name=copy>");

    Все.

    }

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

    ПЕРЕИМЕНОВАНИЕ, ЗАПРОС ИНФОРМАЦИИ

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

    if ($ren!="") { то выведем пояснение пользователю...
    echo ("Переименовать файлы?<bг>");

    и для каждого файла или папки, чье имя было отмечено в соответствующем checkbox'e на главной странице...

    foreach ($fl as $i)
    {

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

    echo ("<input type=hidden name=afl[] value=$i>");

    Выведем старое имя файла...

    echo ("$i");

    и текстовое поле для ввода нового имени. Для удобства поместим в это текстовое поле старое имя - если пользователю надо было его изменить совсем немного, то ему сделать это будет легче.

    echo ("<input type=text size=30 name=rfl[] value=$ixbr>") ;

    Такие поля выведем для каждого файла или папки, подлежащего переименованию.
    }
    И выведем кнопку, запускающую процесс переименования путем перехода на страницу со сценарием-обработчиком с передачей этому сценарию отличного от пустой строки значения переменной $rеn:

    echo ("<input type=submit value=\"Переименовать\" name=ren>");

    Блок запроса дополнительной информации по переименованию файлов или папок закончен.
    }
    В результате работы данного сценария (а это произойдет только в том случае, если на основной странице файлового менеджера была нажата кнопка "Переименовать") посетителю будет отображен список выбранных им для переименования файлов, для каждого из которых он сможет ввести новое имя (рис. 11.8)
    После нажатия кнопки "Переименовать" на странице запроса дополнительной информации сценарию-исполнителю действия будут переданы два массива - $afl и $rfl - со старыми и новыми именами файлов и папок, причем их элементы, относящиеся к одному и тому же файлу или папке, будут иметь один и тот же порядковый номер.
    Полные же пути к переименовываемым файлам и папкам сценарий сможет восстановить на основе значения переменной Sfolder, переданной ему в ссылке на страницу со сценарием-обработчиком, указанной в заголовке формы (см. ранее).


    СОЗДАНИЕ НОВОЙ ПАПКИ, ЗАПРОС ИНФОРМАЦИИ

    Для создания новой папки нужно получить от пользователя всего одно слово - имя этой самой новой папки.
    Если на основной странице файлового менеджера было выбрано действие "Создание папки"...

    if ($md!="")

    то выведем на страницу поле для его ввода (его содержимое передастся сценарию-обработчику в переменной Snewname):

    echo ("Введите имя папки: <brxinput type=text size=30 name=newname>");

    и кнопку, запускающую это самое создание:

    echo ("<input type=submit value=\"Создать папку \ " name=md>");

    Собственно, и все.

    }
    ?>

    Посетитель увидит поле ввода для имени новой папки (рис. 11.9)

    КНОПКА ОТМЕНЫ

    Для того, чтобы со страницы запроса информации можно было уйти без последствий, если посетитель передумает что-либо делать со своими файлами, поместим на эту страницу кнопку "Отмена" (см. рис. 11.6-11.9):

    <brxinput type=submit value="OTMeHa" name=otmena>

    Собственно, это и есть весь текст этой страницы:

    </form></html>

    Графическое оформление - уже на вкус сайтостроителя.


    ФАЙЛ DO.PHP

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

    <?php
    $begin="files";

    Целесообразность проверки содержимого переменной Sfolder на предмет возможности попытки взлома сайта может представиться сомнительной. Эта переменная передается посредством заголовка формы и в адресной строке не отображается, однако ничто не мешает злоумышленнику сохрацить страницу с формой запроса информации на свой жесткий диск, исправить ее содержимое и, заменив относительные ссылки на абсолютные, перейти с сохраненного варианта на страницу выполнения действия. Так что проверять переменную Sfolder на наличие в ней ссылки на родительский каталог (двух точек подряд), а также удостовериться, что путь, записанный в ней, начинается с имени корневой папки аккаунта, всё же необходимо. Если последнее неверно или в Sfolder можно найти две точки подряд, то дальнейшее выполнение кода прекращается:

    If
    ((strpos($folder,$begin)!=0)||(strpos($folder,"..")
    !=False))
    158
    exit; }

    Примечание:
    Команда exi t полностью прекращает выполнение кода и выведение текста на странице, на которой она расположена - как если бы именно на ней страница заканчивалась. Обратите внимание, что эта команда завершает не выполнение РНР-программы, а вывод страницы - т. е. HTML-код после завершающего тэга РНР-сценария, если таковой есть, выводиться также не будет.

    Хотя, бесспорно, если посетитель может загружать на свой аккаунт файлы с PHP-программами, и эти программы могут выполняться, никакие "защиты" в файловом менеджере не спасут сайт от взлома. Так что "защита" в этом сценарии является скорее демонстрацией.

    УДАЛЕНИЕ, ВЫПОЛНЕНИЕ ДЕЙСТВИЯ

    Для удаления файлов в РНР существует специальная команда - unlink.

    Примечание:
    Команда unlink (имя файла с полным путем к нему) удаляет файл, указанный в ее параметре. Если этого сделать не удастся - выводит на страницу сообщение об ошибке.
    Команда rmdir (имя директории с полным путем к ней) удаляет указанную в ее параметре директорию, если она пустая. Если удаляемая папка не пуста или сценарий не имеет прав на удаление директории, то на страницу выводится сообщение об ошибке.

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

    function delfiles($fId)
    $hdl=opendir($fld); while ($file = readdir($hdl)) {
    if (($file!=".")&&($file!="..")) {
    if (is_dir($fld."/".$file)==True) {
    delfiles ($fId.»/".$file); rmdir ($fld."/".$file); }
    else {
    unlink ($fld."/".$file); } } }
    closedir($hdl);
    }

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

    if ($udal!="")

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

    foreach ($fl as $i)

    проверим на то, не является ли он директорией.

    if (is_dir($folder."/".$i)==True)
    {

    Если является, то удалим все файлы в этой директории - рекурсивной функцией delf iles...

    delfiles ($folder."/".$i); а затем и саму, уже опустошенную директорию - командой rmdir.
    rmdir ($folder."/".$i); } else

    А если этот объект, подлежащий удалению, является обычным файлом...
    то для него припасена уже упомянутая выше команда unlink: unlink ($folder."/".$i); }
    И так поступим с каждым объектом, имя которого передано сценарию через массив $fl, а путь к нему - через переменную Sfolder в адресной строке.
    } Собственно, и все (рис. 11.10).

    ГЛАВА 11. РНР: ФАЙЛОВЫЙ МЕНЕДЖЕР 3 часть
    КОПИРОВАНИЕ, ВЫПОЛНЕНИЕ ДЕЙСТВИЯ

    С копированием будет посложнее. Напомню, что из сценария запроса дополнительной информации передан массив Sfl, состоящий из имен копируемых файлов и папок, и переменная $rd, содержащая имя с полным путем к той папке, в которую планируется осуществить копирование. Ну и, разумеется, путь к текущей папке, в которой изначально и находятся копируемые файлы - $folder.
    Сначала напишем функцию копирования целой папки со всеми вложенными в нее папками на новое место. Эта функция, как и функции удаления папки и вывода списка всех папок на аккаунте, будет рекурсивной - т. е. с вызовом самой себя из своего кода. Алгоритм ее прост:

    1. Создать в папке назначения папку с тем же именем, что и у копируемой.
    2. Копировать из копируемой папки в новосозданную папку все ее содержимое.
    3. Если очередной копируемый объект - папка, то перейти к пункту 1, приняв в качестве папки назначения - новосозданную папку, а в качестве копируемой папки - этот самый очередной копируемый объект, оказавшийся папкой.
    Рано или поздно функция дойдет до папок, содержащих только файлы, которые и станут прерывать рекурсию.
    Функция будет получать полное имя (вместе с путем) папки, в которой находится копируемая папка, имя этой самой копируемой папки, и имя (вместе с путем) папки назначения копирования (т. е. той, в которую будет производиться копирование).
    function copyfold ($fld, $nm, $tgt)
    Внутри функции эти данные будут доступны в переменных $fld, $nm, $tgt соответственно.
    Сначала создадим в папке назначения копирования папку с таким же именем, что и имя копируемой папки. Естественно, если там таковой еще нет:

    if (file_exists($tgt."/".$nm)!=True)
    mkdir ($tgt."/".$nm, 0666);

    Примечание:
    Команда mkdir (имя новой папки вместе с путем к ней, параметры доступа) создает новую папку. Если создать папку невозможно (например, уже есть папка с таким именем), то выдается сообщение об ошибке.

    Параметры доступа, или атрибуты файла или папки - это восьмеричное число, сообщающее web-серверу о том, что можно делать с файлом, которому эти параметры установлены. Например позволить его читать только другим сценариям на том же аккаунте, но не посетителям из Сети. Узнать о соответствии значений параметров доступа их восьмеричному представлению можно, например в FTP-клиенте CuteFTP, воспользовавшись его окном выставления атрибутов файла (рис.11.11), доступном через пункт "Chmod" меню правой кнопки мыши любого файла на сайте. "Owner permissions" - это раз решения для других программ на том же аккаунте, a "Public permissions" - для посетителей из Интернета. Вы можете разрешить или запретить три вида действий: чтение, запись и запуск на исполнение (последнее имеет смысл только для программ).


    Теперь начнем копировать файлы из исходной папки в новосоздан-ную (используем старый добрый сценарий "папкопотрошилки"): исходная папка при этом - $f Id. " /" . $шп, а новосозданная -

    $tgt."/".$nm.
    $hdl=opendir($fld."/".$nm) ; while ($file = readdir($hdl)) { if (($file!=" . .")&&($file! = "."))

    Если очередной объект из "потрошимой" папки $f Id. " / " . $nm -директория...

    if (is_dir($fld."/".$nm."/".$file)==True) {

    о применим рекурсию - вновь вызовем функцию с ору fold, только араметры ей уже передадим несколько другие:

    copyfold($fld."/".$nm, $file, tgt."/".$nm);

    Другими словами, в качестве имени копируемой папки - указываем мя очередного обьекта, найденного в "потрошимой" папке. Остальные передаваемые функции параметры представляют собой соответственно имя "родительской" папки для копируемой (это имя "потрошимой" папки), имя папки назначения (составлено из исходного имени апки назначения и имени копируемой папки, эта папка, кстати, как вы, наверное, помните, была создана командой mkdir в начале работы функции).
    Если же очередной объект из "потрошимой" папки $f Id." /" . $nm является обычным файлом...

    }
    else
    {

    то просто скопируем его из исходной папки в папку назначения -и дело с концом.
    copy ($fld."/".$nm."/".$file, $tgt."/".$nm."/".$file);

    Примечание:
    Функция copy (исходный файл, файл на месте назначения) копирует файл, полный путь к которому указан в первом параметре, в тот файл, полный путь к которому указан во втором параметре. Если копирование не удается, то функция выводит сообщение об ошибке (можно отключить, поместив символ @ перед командой) и возвращает false.
    Если файл назначения уже существует, он будет перезаписан без вывода какого-либо подтверждения.

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

    copy ("/files/data/filel.htm", "/files/last/'filel.htm");

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

    }
    } }

    и открытую "потрошимую" директорию:

    closedir($hdl); }

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

    if ($copy!="")
    {

    Переберем все объекты, подлежащие копированию: foreach ($fl as $i)
    { Если очередной объект - папка...

    if (is_dir($folder."/".$i)==True)

    то запустим функцию копирования папки, разобранную выше, передав ей нужные параметры.

    copyfold($folder, $i, $rd);

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

    Однако исключение вложенных папок из списка возможных пунктов назначения на странице запроса дополнительной информации не гарантирует невозможности начала такого копирования! Злоумышленник может сохранить страницу файлового менеджера со списком пунктов назначения копирования на своем компьютере, а потом, исправив относительные ссылки на абсолютные, добавить в локальную копию страницы новый возможный пункт назначения копирования, т. е. имя папки, вложенной в копируемую папку, а затем, пометив именно эту папку, запустить копирование, тем самым навредив владельцу сайта, на котором расположен файловый менеджер.
    Чтобы сделать такие действия невозможными, на странице выполнения действия можно проверять, не вложена ли папка назначения копирования в копируемую папку. Для этого проще всего сравнить полные имена этих папок. Если полное имя копируемой папки можно найти в начале полного имени папки назначения, то копирование выполнять нельзя. Для сравнения проще всего воспользоваться функцией strpos (справку по ней смотрите в начале этой главы):

    if (!(strpos ($rd, $?older."/".$i)===0)) { copyfold($folder, $i, $rd);
    }

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

    }
    else {
    то его скопируем.
    copy ($folder."/".$i, $rd."/".$i);

    Осталось закрыть фигурными скобками запущенные циклы и условные операторы.

    } }
    }
     
    Последнее редактирование модератором: 26/11/15
  14. Iskander36

    Iskander36 Богач

    Регистрация:
    12/10/15
    Сообщения:
    8,909
    Симпатии:
    134
    Баллы:
    71
    Пол:
    Мужской
    Вывел, $:
    214
    4.10.Плагиат категорически запрещён! В случае потребности раскрыть тему, оригинальный текст должен быть оформлен в виде цитаты, содержащей только главные мысли и занимать не более 25% сообщения по объёму. Второстепенную информацию заменяйте ... многоточием.
    # Сообщение было дополнено 26/11/15
    Gizmo, для чего тут нужен этот копипаст?
     
  15. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    1) Я не где не сказал что это уникальный текст.
    2) Я не выдаю его за свой. Это с одного из самоучителей. Самоучитель очень хороший, в нем все просто и понятно описано.
    3) Создал тему. Выкладываю уроки. Что я не так сделал? Разве плохо что на форуме будет присутствовать данная статья? Тем более веб технологии у вас пусты. А данная статья может кому то пригодиться. Если уж не очень сильно, так хотя бы для общего развития. А может кто то и плотно займется этим.

    Так мне продолжать или так и оставить?
     
  16. Iskander36

    Iskander36 Богач

    Регистрация:
    12/10/15
    Сообщения:
    8,909
    Симпатии:
    134
    Баллы:
    71
    Пол:
    Мужской
    Вывел, $:
    214
    Gizmo, я вообще не пойму в чем толк скопировать и вставить 500 стр. текста?
     
  17. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    Iskander36,
    1)Наполнение форума контентом.
    2)Если кто то захочет обучаться php то он будет это читать
    3)Многие из нас ленивые и мало кто захочет качать какие то самоучители. А тут уже есть, все просто и понятно.
     
  18. Iskander36

    Iskander36 Богач

    Регистрация:
    12/10/15
    Сообщения:
    8,909
    Симпатии:
    134
    Баллы:
    71
    Пол:
    Мужской
    Вывел, $:
    214
    Gizmo, да я что спорю? Только смотрите ссылки в тексте убирайте.
    Привет сайтостроителям!. :kas*|
     
  19. Gizmo

    Gizmo В бегах

    Регистрация:
    24/11/15
    Сообщения:
    41
    Симпатии:
    6
    Баллы:
    5
    Пол:
    Мужской
    ГЛАВА 12. РНР: ПОЛЕЗНЫЕ МЕЛОЧИ


    PHP: ПОЛЕЗНЫЕ МЕЛОЧИ

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


    СЧЕТЧИК ПОСЕЩЕНИЙ

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

    <?php

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

    $dirct="foldcount"; $cnt="counter.php";

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

    if (file_exists("$dirct/$cnt")==True) {

    считаем число из файла и запишем его в переменную $sr. Ее мы потом выведем на страницу в качестве показателя числа посещений, а также, увеличив на 1, получим число посещений, включая данное.

    $hdl = fopen("$dirct/$cnt", "r+");
    $sr = fread($hdl, filesize("$dirct/$cnt"));
    fclose($hdl);
    $sr++;
    }



    Примечание:
    Для того чтобы из программы на РНР считать содержимое какого-либо файла или записать в него данные, этот файл нужно сначала открыть - командой fopen (так уж устроен РНР). При этом открытому файлу присваивается некое "внутреннее имя"' - так называемый дескриптор, и именно его возвращает функция /open. Первый параметр /open - имя файла (вместе с относительным или абсолютным путем к нему), второй - способ открытия файла.
    В зависимости от второго параметра функции fopen файл может быть открыт по-разному - для чтения, для записи, с очисткой содержимого или нет. Возможные параметры fopen такие:
    • г - открыть файл только для чтения и приготовиться читать его с начала.
    • г+ - открыть файл для чтения и для записи и приготовиться работать с ним с его начала.
    • w - открыть файл только для записи, предварительно удалив из него все содержимое, причем если файл с указанным именем не существует, то создается новый файл с таким именем.
    • w+ - открыть файл как для записи, так и для возможного последующего чтения, предварительно удалив из него все содержимое, причем если файл с указанным именем не существует, то создается новый файл с таким именем.
    • а - открыть файл только для записи и приготовиться дописывать данные в его конец. Если файл с указанным именем не существует, то создается новый файл с таким именем.
    • а+ - открыть файл для записи и для чтения и приготовиться дописывать данные в его конец. Если файл с указанным именем не существует, то создается новый файл с таким именем.
    Открываемый файл может располагаться и на удаленном сервере - в этом случае oft будет доступен только для чтения независимо от параметров открытия файла. Путь к файлу в таком случае следует указывать полностью - начиная с ht tp:// или ftp://.

    Если же файла со счетчиком нет, т. е. посещений раньше не было...

    else

    Справедливости ради стоит сказать, что такая фраза не совсем корректна по сути, но для практической работы подобный взгляд вполне можно использовать. 182
    Глава 12. PHP: полезные мелочи то просто присвоим переменной со сведениями о количестве посещений значение 1.

    $sr=l;

    Выведем на страницу данные о числе посетителей... echo ("Посетителей - $sr");
    и, снова открыв файл счетчика, но теперь уже для записи и очистив все его содержимое (видите параметр "w+"?), запишем в него значение переменной со сведениями о количестве посещений:

    $hdl2 = fopen("$dirct/$cnt", "w+");
    fwrite($hdl2, $sr);
    fclose($hdl2);

    Вот, собственно, и все (рис. 12.1).


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

    $cnt="counter.php";

    следует вставить строку, определяющую имя текущего файла на основе значения переменной $PHP_SELF:

    $cnt=substr(basename($PHP_SELF), 0, -4). "_cnt.php";

    Этот код выделяет из адреса страницы ее имя (без расширения) и создает на его основе уникальное имя файла счетчика (просто добавляя в конец имени страницы комбинацию символов "_cnt .php").


    ПАРТНЕРСКАЯ ПРОГРАММА

    Если вы когда-нибудь посещали Интернет-магазины, то наверняка видели в некоторых из них раздел "Партнерская программа". Суть такой программы проста - это предложение web-мастерам различных сайтов размещать на их страницах ссылки на магазин, и в том случае, если совершивший покупку посетитель пришел именно по такой ссылке, то тот, кто разместил ссылку, получает определенный процент от денег, выплаченных посетителем за товар.
    Если вы на своем сайте также осуществляете прием заказов на что-либо от посетителей (например, у вас есть простой Интернет-магазин вроде описанного в гл. 5), то организовать партнерскую программу вы сможете буквально четырьмя строками кода на РНР.
    Через гиперссылку, ведущую на какую-нибудь web-страницу, можно передать программе на этой web-странице значения переменных. Для этого следует после адреса web-страницы, на которую ссылка ведет, поместить знак вопроса, имя переменной и ее значение после знака равенства - www. domen. ru?perem=znach (можно передать и несколько переменных, записывая их одну за другой и разделяя амперсандом - &:

    domen.ru?pereml=znachl&perem2=znach2).

    В результате в сценарии на странице окажется доступной переменная с соответствующими именем и значением.
    Понятно, что для того чтобы иметь возможность выделять среди всего потока приходящих на сайт тех, кто пришел от партнеров, достаточно указывать в партнерской ссылке значение определенной переменной, естественно, уникальное для каждого партнёра. Например, что-то вроде www. domen. ru?partner=ivanov.
    Если в сценарии на той странице, куда ведет такая ссылка, имеется команда отправки письма, то можно значение этой переменной включить в отправляемое письмо. Однако довольно трудно представить себе такую ситуацию, так как обычно команда mail обрабатывает данные, переданные на содержащую ее страницу из формы, расположенной на другой странице того же сайта. Поэтому возникает вопрос - как "отловить" переданную переменную - партнерский идентификатор на той странице, на которую приходят посетители от этого партнера, и потом включить ее в письмо-заказ на странице с командой отправки почты. При условии, разумеется, что до отправки заказа посетитель, возможно, обойдет еще множество других страниц сайта?
    Самым простым, но достаточно действенным способом решения такой проблемы будет использование cookies (подробнее о cookies рассказано в гл. 8). На тех страницах сайта, на которые будут указывать размещаемые партнерами ссылки, следует разместить код:

    <?php
    if ($partner!="")
    { SetCookie("prtn",$partner, ""); }
    ?>

    В результате в том случае, если в ссылке окажется переменная partner, в браузер посетителя будет отправлен cookie под названием prtn с ее значением. Помните, что установка cookie должна предшествовать любому выводу в выдаваемый документ - поэтому данный код должен стоять в самом начале документа, до каких-либо тэгов HTML.
    Ну а в код той страницы, в которой составляется и отправляется письмо с заказом, достаточно включить переменную, сохраненную в cookie. Например, команда отправки почты из рассмотренного в гл. 5 примера будет выглядеть так:

    mail ("mail @ harchikov.ru", "Заказ на кассеты", "С адреса $email пришла заявка на приобретение $kolv кассет на общую сумму $summa рублей: $zak. Контактные данные заказчика: $cont, партнерский идентификатор - $HT TP_COOKIE_VARS['prtn']", "From: $email\nReply-To: $email\nContent-Type: text/plain; charset=windows-1251");
    Вот и все. Если посетитель зашел на ваш сайт от партнера, то вы об этом узнаете из письма с заказом и сможете отправить партнеру причитающийся ему процент.
    При желании вы можете вместе с отправкой письма подсчитывать количество заказов, сделанных через партнера, с помощью скрипта наподобие рассмотренного чуть выше счетчика посещений - вызывая его в момент отправки письма с партнерским идентификатором. Выводить же данные этого счетчика можно на особую страницу, доступ на которую партнер будет иметь лишь после авторизации - как ее сделать, см. гл. 8. В зависимости от различных значений логина партнера на эту страницу будут выводиться данные различных счетчиков - соответственно логину.
    # Сообщение было дополнено 26/11/15
    Моя личная просьба к админу: Уберите пожалуйста ограничения по вводу ссылок. Так как не получается даже оформить запрос HTTP и www. просто получается так, что система пишет что я пытаюсь разместить ссылки. Но это запросы либо текст, а не адрес сайта... В итоге получается так, что я как будто публикую ссылку.... И приходиться делать пробелы. Для примера запрос: $HT TP_COOKIE_VARS['prtn']" ... вот и приходиться ставить пробел...:(
     

    Вложения:

    • 1.gif
      1.gif
      Размер файла:
      15.7 КБ
      Просмотров:
      278
  20. sh0x1

    sh0x1 В бегах

    Регистрация:
    23/1/18
    Сообщения:
    13
    Симпатии:
    1
    Баллы:
    2
    Пол:
    Мужской
    Если кто-то вообще прочитал всю эту тему и видит эту надпись то можешь написать мне свой вопрос я постараюсь тебе помочь в сфере разработки уже давно)