Отправляет email-рассылки с помощью сервиса Sendsay

Программирование в Web

  Все выпуски  

Программирование в Web Выпуск 14 от 08/06/2006 Основы PHP - Урок-9


 
Программирование в web

ОСНОВЫ PHP
 

 
Внимание!!!
Все материалы уроков, публикуемых в этом и во всех последующих выпусках рассылки «Программирование в web», являются интеллектуальной собственностью авторов и ведущих рассылки. По всем вопросам размещения или публикации данных материалов на собственных ресурсах или где-либо еще, или иного использования, не связанного с личным ознакомлением и самостоятельным обучением, - обращайтесь на адрес автора. Любое использование этих материалов в коммерческих или иных целях, явно не разрешенное автором, является незаконным.
 

 
У Р О К    9
Здравствуйте уважаемые подписчики!

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


НЕМНОГО О РАБОТЕ С ФАЙЛАМИ:

Инструкции include, include_once, require и require_once мы уже рассмотрели. Теперь немного о работе на более низком уровне.


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



Файл или каталог?

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


is_file($obj) — проверяет, является ли объект файлом и возвращает true если это так;

is_dir($obj) — проверяет, является ли объект каталогом (директорией, папкой), true если это так;

is_link($obj) — возвращает true если это символическая ссылка на файл.

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



Проверка доступа к файлам:

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


is_readable($obj) — возвращает true если из файла можно читать, то есть если файл для чтения доступен;

is_writable($obj) — возвращает true если файл доступен для записи;

is_executable($obj) — возвращает true если файл разрешено исполнять.

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


file_exists($filename) — проверяет существование файла с именем $filename и возвращает true если такой файл существует (если не указан путь, то ищется в текущем каталоге)$

feof($f) — данная функция возвращает возвращает true если достигнут конец файла с дескриптором $f. С помощью этой функции удобно организовывать обработку файлов в циклах.


Информация о файле:

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


filesize($file) — возвращает размер файла в байтах;

fileatime($file) — возвращает дату последнего доступа к файлу;

filemtime($file) — возвращает дату последней модификации файла;

filectime($file) — возвращает дату последнего изменения файла.

Эти три функции возвращают дату в формате timestamp - время всекундах, прошедшее с 1 января 1970 года (эпоха Unix). Подробнее об этом формате и о работе с ним я расскажу в одном из следующих уроков.



Создание, удаление, копирование и переименование файла:

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


touch($filename) — создает пустой файл нулевой длины с именем $filename, но только если у вас есть права записи в каталог, в котором этот файл создается;

unlink($filename) — удаляет файл с именем $filename, но только если у вас есть права на этот файл или на каталог, из которого этот файл удаляется;

copy($startname, $destinationname) — скопирует файл с именем $startname в каталог $destinationname. Здесь вы можете указывать как абсолютный, так и относительный путь, а также и новое имя файла (если это необходимо);

rename($oldname, $newname) — переименовывает или перемещает файл с именем $oldname в имя $newname. Если в $newname указан только путь, то файл будет перемещен по этому пути, если будет указано только имя, то файл останется в том же месте, где и был, но получит другое имя. В общем все точно также, как и в операционных системах.


Чтение из файлов и запись в файлы:

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


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


file($filename) — читает данные из файла с именем $filename целиком за один присест, и помещает содержимое в массив, каждая строка файла — элемент массива. Эту функцию удобно использовать именно для создания массивов, она работает очень быстро и не надо делать никаких других операций по получению содержимого файла, в отличии от функции fopen(). У этой функции, правда, есть один маленький недостаток, она включает в значения элементов массива также и служебные последовательности перевода строк /n, такое не всегда может быть тем, что вам нужно, как этого избежать мы узнаем чуть позже;

file_get_contents($filename) — читает за один прием данные из файла с именем $filename и помещает прочитанное в строку. Возвращаемый этой функцией результат именно строка, какого бы размера ни был файл (в PHP строки могут иметь практически неограниченную длину, правда не перешагивающую барьер ограничений операционных систем на размер файлов). Таким образом полученные данные вы можете поместить в переменную строкового типа и делать потом с ней все, что вам заблагорассудится. Эту функцию иногда удобно применять для чтения различных шаблонов, которые требуют предварительной, до вывода в браузер, обработки. С помощью этой функции, правда с некоторыми ухищрениями, можно легко заменить функции include() и require(), а также и их собратьев с постфиксами _once (здесь надо отметить, что require() не функция, а директива языка, но это уже не так важно);

file_put_contents($filename, $data) — функция записывает за один прием в файл с именем $filename строковые данные $data. Эта функция, по сути, является противоположной для функции file_get_contents($filename);

parse_ini_file($filename, $flag) — эта функция очень может пригодиться вам в ваших проектах, она читает данные из файла $filename, схожего по структуре с .ini-файлами и возвращает ассоциированный массив, в котором ключи и значения - это параметры и значения, прописанные в этом .ini-файле. Если второй, необязательный параметр $flag имеет значение true (по умолчанию false), то будет возвращен двумерный массив, с ключами верхнего уровня - именами секций .ini-файла. Приведу пример:

Допустим у нас есть какой-нибудь .ini-файл такой структуры:


[Settings]
NumCols=3
NumRows=3

Если мы не укажем второй параметр или явно укажем его значение false, то будет возвращен обычный одномерный массив, следующего содержимого - array(NumCols=>3, NumRows=>3). К каждому значению можно будет получить доступ примерно так - $array['NumCols'] и $array['NumRows']. Но если мы явно укажем второй параметр в значении true, то массив на выходе будет уже двумерным и будет выглядеть примерно так: array(Settings=>array(NumCols=>3, NumRows=>3)) и обратиться к каждому элементу мы должны будем уже вот так - $array['Settings']['NumCols'] и $array['Settings']['NumRows']. Тут надо исходить из того, чего вы хотите добиться. Если вы не собираетесь использовать сильно разветвленную структуру в своем .ini-файле, то второй параметр можно не указывать, но, если в вашем .ini-файле будет сложная структура, имеющая множество отдельных секций, то тогда конечно лучше прин имать двумерный массив. Использование .ini-файла с этой функцией очень вам поможет, при написании сложных проектов, и упрощению редактирования в дальнейшем конфигурации этого вашего проекта.


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


fopen($filename, "$rezim") — открывает файл с именем $filename для работы с ним в режиме $rezim. Режимы работы перечислены в таблице:

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


Применяется эта функция следующим образом:


$f=fopen($filename, "$rezim")
где $f — дескриптор открытого файла, с которым вы после этого можете работать. Тут надо сказать, что в PHP нельзя работать напрямую с файлом, можно только через его дескриптор. Но это, впрочем, относится не только к PHP, но и к другим языкам программирования.


А вот эта конструкция, может с легкостью заменить функцию file():


<?php
$f=fopen($filename, "rt");
$array=explode("\n", fread($f, filesize($filename)));
?>
Примечание: Режим «rt» сообщает о том, что будет читаться текстовый файл, а не бинарный (вместо t добавляется b).


Эта последовательность помимо того, что считывает весь файл целиком, возвращая при этом массив, еще и убивает служебные последовательности \n - перевода строки . Есть у этой последовательности и один минус. Хоть работает она и быстрее (именно так, это не опечатка) и значения получает корректнее, но при подсчете количества записей в полученном массиве вернет (в большинстве случаев) количество на единицу большее, чем есть на самом деле. А все потому, что часто, после записи строки в текстовый файл делают и перевод строки (так удобнее с точки зрения перебора строк файла) и вот эта пустая строка также включается в результирующий массив. Функция file() лишена этого недостатка, но..., все символы перевода строки будут включены в соответствующие значения. Так что методом проб и ошибок вы сможете подобрать сами для себя, что вам выбрать, либо получать чистые данные и подсчет количества записей уменьшать на един ицу всегда, либо получать данные со служебными последовательностями. По себе могу сказать, что чаще всего использую именно file($filename).


or die() — эта конструкция предназначена для безаварийного выхода если попытка открыть файл будет неудачной. В качестве параметра в эту функцию вы можете передавать любую текстовую строку (это может быть, например, сообщение о невозможности открыть файл или любое другое). Применяется обычно при проверке удачности открытия файла, так как fopen() возвращает логическое значение (true или false). Например ее можно применять так:

<?php
$f=fopen($filename, "rt") or die("Не могу открыть файл");
$array=explode("\n", fread($f, filesize($filename)));
?>

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


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


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


Вот как схематично можно представить работу с файлами:

  1. Открываем файл для работы с ним и передаем дескриптор открытого файла;
  2. Ставим блокировку в зависимости от того, в каком режиме мы открыли файл;
  3. Работаем с файлом (читаем, пишем и так далее);
  4. Снимаем блокировку;
  5. Закрываем файл.

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


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


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



Блокировки:

flock($f, LOCK_SH); или flock($f, 1); — Рекомендательная блокировка (или еще называют разделяемая, для чтения из файлов),
flock($f, LOCK_EX); или flock($f, 2); — исключительная блокировка (для записи в файлы),
flock($f, LOCK_UN); или flock($f, 3); — Снятие блокировок (сразу после окончания работы с файлом непосредственно до его закрытия),
flock($f, LOCK_NB); или flock($f, 4); — добавляется к одной из предыдущих трех если вы не желаете, чтобы программа подвисала на блокировках в ожидании своей очереди, а сразу возвращала управление вызывающей программе. Но не бойтесь, при чтении не очень больших файлов, на хорошем хостинге подвисания будут не заметны.

Немного о правах доступа к файлам:

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


chmod($filename, $mod) — функция устанавливает права доступа к файлу с именем $filename в значение $mod. $mod - это восьмеричное число предваренное нулем (0777, 0644...). Обо всех этих правах вы можете найти информацию в документации по *Nix-системам, либо немного рассмотрим их в других уроках, если вас это заинтересует;

fileperms($filename) — возвращает числовое значение прав доступа к файлу $filename

stat($filename) — возвращает массив, в котором все значения собраны операционной системой и представляют собой все атрибуты файла $filename, со значениями в следующих ключах-индексах:

0 — устройство
1 — номер узла inode
2 — атрибуты защиты файла
3 — число синонимов (жестких ссылок) файла
4 — идентификатор UID владельца
5 — идентификатор GID группы
6 — тип устройства
7 — размер файла в байтах
8 — время последнего доступа в секундах с эпохи Unix
9 — время последней модификации содержимого файла
10 — время последнего изменения атрибутов файла
11 — размер блока
12 — число занятых блоков

Работа с файлами (чтение, запись...):

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


fread($f, $length) — читает из открытого файла с дескриптором $f $length символов или байт от начала и возвращает результат в виде строки, то есть эта операция применяется справа от оператора присваивания;

fgets($f, $length) — читает из текстового файла одну строку, заканчивающуюся символом перевода строки \n, либо строку длиной $length символов. Но чаще всего лучше использовать функцию file();

fwrite($f, $data) — записывает в ранее открытый файл с дескриптором $f данные из строки $data;

fgetcsv($f, $length, $delim, $quot) — читает данные из файлов csv (текстовое представление файлов Exel), $f — дескриптор ранее открытого файла, $length — длина строки которую мы будем читать, $delim — один символ-разделитель в строке в файле, $quot — символ ограничитель строки. Функция возвращает массив-список полей строки, прочитанной из файла. Данная функция может некорректно работать с русскоязычными символами в версиях PHP ниже 4.3.1;

fseek($f, $num, $param) — устанавливает в ранее открытом файле с дескриптором $f позицию в $num от $param (SEEK_SET — отсчет от начала файла, SEEK_CUR — отсчет от текущей позиции, SEEK_END — от конца файла);

ftell($f) — возвращает текущую позицию курсора в ранее открытом файле с дескриптором $f;

ftruncate($f, $size) — усекает ранее открытый файл с дескриптором $f до размера $size, если $size==0, то файл просто очищается.


Работа с каталогами (создание, удаление, чтение...):

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


mkdir($dirname, $mod) — создает каталог $dirname с правами доступа $mod;

rmdir($dirname) — удаляет каталог $dirname;

chdir($path) — сменяет текущий каталог на указанный в $path;

getcwd() — возвращает полный путь к текущему каталогу;

opendir($dirname) — открывает каталог $dirname для работы с его содержимым;

readdir($dirname) — читает содержимое каталога с дескриптором $dirname;

closedir($dirname) — закрывает ранее открытый каталог с дескриптором $dirname;

rewinddir($dirname) — перематывает на начало указатель содержимого ранее открытого каталога с дескриптором $dirname.

Примечание:


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


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


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


 

 
Объявления!!!

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

Если у вас возникли какие-то вопросы, не стесняйтесь, задавайте. Для этого всего лишь пошлите на мой адрес письмо с вопросом и с темой, в которой обязательно укажите какого урока и какого языка касается вопрос. Например, тема может быть такой - «Основы PHP. Урок 9. Вопрос». Также, с такой же темой и на этот же адрес вы можете прислать и свои дополнения к уроку. Если дополнения будут существенными, то в последующих уроках они обязательно будут учтены.

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

Маленькая просьба. Многие из вас присылают мне запросы на отправку им того или иного, не полученного ранее, выпуска рассылки. У меня не всегда есть возможность это сделать. Поэтому предлагаю вам для начала посмотреть нужный выпуск в архиве рассылки. Рассылка выходит сразу на трех рассыльных сервисах, и по некоторым причинам (мне не известным) некоторые сервисы не принимают адресов, в которых встречаются именя конкурирующих рассыльных сервисов, по этой причине я опубликую только одну ссылку на архив рассылки только одного рассыльного сервиса, а именно Content.mail.ru. Вот ссылка на на этот архив рассылки - http://content.mail.ru/pages/p_21931.html. В обще м-то это объявление наверное лишнее, ведь в каждом выпуске каждой рассылки, вне зависимости от того, на каком сервисе она выходит, всегда указан этот самый адрес архива рассылки. На сабскрайб.ру и на контент.мэйл.ру этот адрес указывается в самом низу выпуска, а на мэйллист.ру - в самом верху выпуска. Так что, при достаточном внимании, вы сами легко сможете найти нужную ссылку на архив рассылки.

 

 
Внимание!!!
Все материалы уроков, публикуемых в этом и во всех последующих выпусках рассылки «Программирование в web», являются интеллектуальной собственностью авторов и ведущих рассылки. По всем вопросам размещения или публикации данных материалов на собственных ресурсах или где-либо еще, или иного использования, не связанного с личным ознакомлением и самостоятельным обучением, - обращайтесь на адрес автора. Любое использование этих материалов в коммерческих или иных целях, явно не разрешенное автором, является незаконным.
 

 
Наш проект
Автор рассылки — Anatolick
Архив рассылки — http://content.mail.ru/pages/p_21931.html
Сайт проекта — «Russian discussions Zone»
Движок для сайтов — «Tanat-Engine»
Дискуссионный лист — «Все для Всех о РС»
Дискуссионный лист — «File Info Masters»
Дискуссионный лист — «Напряги мозги»
Дискуссионный лист — «Ищем все…»
Дискуссионный лист — «Все обо Всем по Email»
Дискуссионный лист — «Внимание! Розыск…»
Дискуссионный лист — «Английский для Всех и каждого»
Группа стандартизации в Web — W3C.org
 

В избранное