PHPFAQ  
Начинающим   Технологии   MySQL   Ошибки   Ссылки   Юмор   О сайте   Форум   PHP Club  

Различие между абсолютными и относительными путями. В файловой системе и на сайте.


твой сайт существует в как бы в двух измерениях.
Реальном и виртуальном.

Для всех посетителей - это виртуальный веб-сервер. Который отличается, в числе прочего, тем, что на нем НЕ СУЩЕСТВУЕТ ФАЙЛОВ. если ты пишешь http://site.ru/file.html - это не файл. Это URI, виртуальный адрес. Никакого файла с именем file.html на сервере может вообще не быть. Это все виртуальные адреса, а не файлы.
И браузер работает именно с адресами.

Для разработчика же сайт - это программа, выполняющаяся на совершенно конкретном реальном компьютере. С совершенно конкретным жестким диском, каталогами и файлами. И скрипт, работая со своими данными, подгружая другие скрипты, работает именно с реальными ФАЙЛАМИ, на физическом ДИСКЕ.

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

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

Начнем со второго.
Это очень просто. Если путь указывается от корня системы, то это путь абсолютный. Это как почтовый адрес в реальной жизни - откуда бы ты не шел, но по точному адресу ты всегда точно найдешь нужное место.
примеры абсолютных путей:
/var/www/site/forum/index.php
/img/frame.gif
с:\windows\command.com

В юникс-системах и на веб сайтах корень обозначается косой чертой - "/".
Это важно. Это не просто палочка, а самостоятельный АДРЕС, путь.
В адресе http://www.site.ru/ последняя косая черта - не для красоты! Она обозначает вполне конкретный адрес - начало сайта.
На диске в юникс системах так же можно набрать "cd /" и ты попадешь в корневой каталог.
В виндоус системах файловая система разбивается по дискам, поэтому, в абсолютном адресе надо указывать имя диска. Абсолютного корня всей файловой системы в виндоус нет, у каждого диска - свой. Например, C:\ E:\
поэтому, даже если путь в виндоус начинается с косой черты, то это не абсолютный путь, а относительный. Относительно текущего диска. А абсолютный начинается с буквы.

Если в начале пути корень не указать, то этот путь будет относительным, и он достаивается от текущего положения. В реальной жизни это напоминает дорогу к винному магазину - "два квартала налево и там все время прямо". Дойти по такому пути можно только из конкретной точки. Из другой ты попадешь уже в совсем другое место.
Самый простой пример относительного пути - это просто имя файла.
Если файл находится в том же каталоге, с которым работает программа - она его найдет, добавив текущий путь к имени файла.
примеры относительных путей:
file.php (фал лежит в той же папке)
./file.php (фал лежит в той же папке. такая запись иногда требуется в некоторых юникс системах)
images/picture.jpg (файл лежит в капке images, которая находится в текущей)
../file.php (файл лежит в папке, которая расположена на один уровень выше от текущей)
../../file.php (файл лежит в папке, которая расположена на два уровня выше от текущей)

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

Теперь перейдём к первому пункту.
Различие корня веб-сервера, как его видит браузер, и корень файловой системы на диске.
В общем-то, из предыдущих объяснений уже все должно быть понятно.
На диске путь к файлу скрипта может быть таким:
/var/www/site/forum/index.php
В то же время, виртуальный адрес этого скрипта при просмотре через браузер, будет:
http://www.site.ru/forum/index.php
На этом примере легко увидеть, где пересекаются два измерения: у этих двух адресов есть общая часть - /forum/index.php - и она-то и служит причиной путаницы.
Для браузера это самый полный путь, который только может быть. Он начинается от корня сайта.
Для скрипта же, исполняющегося на сервере - это всего лишь ЧАСТЬ пути.
для скрипта путь /forum/index.php окажется несуществующим - в корне диска нет каталога forum!
чтобы получить полный путь для того, что на сайте выглядит, как /forum/index.php, надо приставить слева к нему путь к папке, которая считается корневаой для всего веб сервера.
в нашем примере - это
/var/www/site
Этот путь задается в кофигурации веб-сервера и именно он содержится в системной переменной PHP $_SERVER['DOCUMENT_ROOT']

В виртуальном же сервере - том, который видит пользователь - наоборот, нет никакого диска. Есть корень сайта. То есть, для того, чтобы любая ссылка гарантированно работала, независимо от того, из какого места сайта она вызывается, она должна быть абсолютной.
Если у вас на сайте есть, допустим, два раздела:
http://www.site.ru/about/info.php
и
http://www.site.ru/job/vacancy.php
то, если в файле info.php сделать ссылку просто на vacancy.php, то браузер ее не найдет - он будет искать адрес http://www.site.ru/about/vacancy.php, достраивая путь от текущего каталога.
Поэтому надо писать полный путь от корня сайта - /job/vacancy.php
Всё это касается, естественно, не только тегов <a> но и <img> и любых других, где используются ссылки на другие файлы.

Ссылки на локальные адреса следует писать без указания протокола и домена - только путь от корня сайта - /job/vacancy.php. Ссылки же на другие сайты следует писать полностью - http://www.site1.ru/job/vacancy.php.


PHP предоставляет множество средств для работы с файлами, каталогами и URL-ами.

Во-первых, это многочисленные предопределённые переменные, которые описаны в документации и значения которых в своём скрипте пможно посмотрев с помощью phpinfo():

Константа __FILE__ содержит имя текущего исполняемого файла.
В отличие от PHP_SELF она содержит имя файла, исполяющегося в данный момент.
очень полезной представляется конструкция dirname(__FILE__), на которую желательно заменить все вызовы файлов, лежащих в том же каталоге, что и вызывающий скрипт. Например:
require dirname(__FILE__)."/init.php"
функция dirname(), наряду с basename() является одними из наиболее употребительных для работы с файлами и каталогами.

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


Другие материалы раздела:
Хочу изучать PHP и Mysql. С чего начать?
Самые основы. Как работает PHP.
Документация по PHP. Мануал по PHP, книги.
Не передаются переменные! Проблема Undefined variable
Решение проблемы "Cannot add header information - headers already sent"
Пример системы управления сайтом
Что такое PHP?
Как писать музыку на PHP


Комментарии

Проходимец 24.11.11 14:42
Ну на самом деле посмотреть разницу между
echo dirname(__FILE__);
echo getcwd();
можно проще :)
Заходим в папку, например, /usr/local/sbin/1 и создаёт там скрипт, содержащий данные строки.
Запускаем, получаем:
/usr/local/sbin/1# ./testing.php
/usr/local/sbin/1
/usr/local/sbin/1

Переходим в папку, скажем, /srv, запускаем тот же скрипт и смотрим результат:
monitor:/srv# /usr/local/sbin/1/testing.php
/usr/local/sbin/1
/srv


Спасибо за статью, давно искал способ определения текущей папки :)
Andrey 06.08.11 13:10
ВЫ написали "очень полезной представляется конструкция dirname(__FILE__), на которую желательно заменить все вызовы файлов, лежащих в том же каталоге, что и вызывающий скрипт. Например:
require dirname(__FILE__)."/init.php" "
Полезно в смысле того чтоб при изменении катлогов или чего бы то ни было не было путанницы , или возможно полезно в плане безопасности тоже? если да укажите плз краткий пример .
Благодарю.
Наталия 21.06.11 14:48
:) сами напросились еще на один коммент, хотя общение с вами приносит действительно_реальную_пользу )))
у меня обе функции приводят к одному и тому же результату (показывают путь, включая папку, в которой лежит текущий документ):
и echo getcwd();
и echo dirname(__FILE__);
Вопрос - есть разница, какую из них предпочесть в том или другом случае? ) Вот если бы у вас еще появилась возможность уведомления пользователя об ответе на его комментарий, было бы вообще здорово )
Ответ: Так я не против :)
Наоборот - чем больше комментов, тем лучше. Особенно, если с вопросами. Для того ведь сайт и делался - чтобы отвечать на вопросы. Тем более, что польза получается обоюдная - вопросы помогают улучшить материалы на сайте.
Получить разный результат очень несложно.
сделаем в корне сайта две папки, вложенные одна в другую:
/one/
/one/two/
и в них - два PHP файла:
/one/main.php
/one/two/include.php
в main.php пишем
<?
include 'two/include.php';
а в include.php
<?
echo getcwd()."<br>\n";
echo dirname(__FILE__)."<br>\n";
и смотрим вывод :)

Насчет комментариев на почту хорошая мысль, надо будет сделать.
Наталия 21.06.11 11:44
пардон, поторопилась ) Конечно же, echo ($_SERVER['DOCUMENT_ROOT']); а то кто-нибудь "скопирует не глядя" и получит не то, что ожидалось )
Ответ: Ну, строго говоря, он получит только сообщение об ошибке, но сам результат не изменится.

Скобки, кстати, ставить совершенно необязательно. echo $_SERVER['DOCUMENT_ROOT']; вполне достаточно.

Спасибо за вопросы, кстати. Пишите ещё :)
Наталия 21.06.11 11:34
echo ($_SERVER['DOCUMENT_ROOT']); тоже, конечно, попробовала. В результате увидела путь ДО текущей папки, в которой лежит документ: /home/папка сайта/имя-поддомена.ru/public_html ))) Так что теперь знаю нюансы результата вывода описанной вами константы и переменной ))) Очень полезно знание о таких нюансах )))
Ответ: Маленькое уточнение. "путь до текущей папки" $_SERVER['DOCUMENT_ROOT'] покажет только если текущая папка - корневая для сайта, та, которую видит клиент сайта. Этим она и ценна - зная DOCUMENT_ROOT, от него можно построить пути к любым файлам в любых папках на сайте.

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

Если же хочется узнать путь до папки, в которой лежит исполняющийся в данный момент скрипт, то dirname(__FILE__)

Я даже сейчас пример, наверное, напишу, который проиллюстрирует, что для всех трёх способов можно получить разные значения в одном и том же скрипте :)
Наталия 21.06.11 10:56
Полагаю, что это все же не есть совершенно абсолютный путь. Думаю, что перед /home/ на самом деле есть еще что-то. К тому же выяснила, что ftp сервер меня обманывать особо не собирался. Просто показывал кусок пути, а именно: 0:/имя-поддомена.ru/public_html/следующая папка(в которой лежит нужный документ)/*.* Теперь знаю, что достаточно чуть подкорректировать путь, видимый через ftp сервер, поставив вместо "0:/" ваше волшебное "../", а вместо "*.*" имя нужного документа с его расширением, конечно ))) По крайней мере, у меня так тоже сработало ) Так что пользы от взаимодействия с вами оказался целый вагон! ))
Ответ: Нет, это и есть самый что ни на есть абсолютный путь :) Ничего больше перед ним нет, можно смело пользоваться.
Наталия 21.06.11 10:51
Хорошо, пишу подробнее - очень интересно узнать и о других вариантах )) Эксперимент заключался в том, что как вы и рекомендовали, в php-документе поставила строчку echo dirname(__FILE__); В результате получила путь: /home/папка сайта/имя-поддомена.ru/public_html/следующая папка(где и лежит нужный документ).
Наталия 17.06.11 09:35
Не отказала себе в удовольствии поэкспериментировать, согласно вашим рекомендациям. Специально вернулась, чтобы поблагодарить за подробные комментарии, за вашу работу и за то, что вы есть. Спасибо вам, яркие звезды инета! кабы не вы, я б, наверное, еще долго "во тьме блуждала" )))
Ответ: Ну вот, самое интересное-то так и не рассказали - что получилось в результате экспериментов :)
Вообще, разных вариантов много. И для каждого случая могут подходить совершенно разные. Если напишете подробнее, то можно будет посоветовать самый оптимальный вариант.
Наталия 14.06.11 21:31
о сайте на веб сервере; у меня доступ начинается не с самого глубинного уровня, => начала абсолютного пути даже через ftp не видно, по крайней мере, у меня тот путь не сработал ))
Ответ: как раз ftp сервер может и врать.
но начало пути видно всегда - иначе скрипт не сможет работать. Самый простой способ посмотреть полный путь - это вывести на экран константу __FILE__. Если написать
echo dirname(__FILE__);
то выведется полный путь на диске к текущему скрипту.
Его можно использовать для обращения к другим файлам.
Наталия 14.06.11 20:09
уточнение к предыдущему сообщению - "гадать" пришлось, поскольку доступа к корню нет, а людей по пустякам напрягать неудобно )) инет побороздить проще, про ../ знала, но вот так просто, что это и есть подъем на один уровень, только вы и сказали ))
Ответ: доступ к корню есть всегда. Нужно только его определить. И это вполне возможно. Речь о пути на диске или на сайте?

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

© phpfaq.ru, 2012
Rambler's Top100 0.021 sec.