PHP – конвертировать путь к файловой системе в URL

Я часто обнаруживаю, что у меня есть файлы в моих проектах, к которым нужно получить доступ как из файловой системы, так и из браузера пользователей. Одним из примеров является загрузка фотографий. Мне нужен доступ к файлам в файловой системе, чтобы я мог использовать GD для изменения изображений или их перемещения. Но мои пользователи также должны иметь доступ к файлам с URL-адреса, например example.com/uploads/myphoto.jpg .

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

Файловая система /var/www/example.com/uploads/myphoto.jpg

URL http://example.com/uploads/myphoto.jpg

Если бы у меня была переменная, установленная на что-то вроде /var/www/example.com/ то я мог бы вычесть ее из пути файловой системы, а затем использовать ее как URL-адрес изображения.

 /** * Remove a given file system path from the file/path string. * If the file/path does not contain the given path - return FALSE. * @param string $file * @param string $path * @return mixed */ function remove_path($file, $path = UPLOAD_PATH) { if(strpos($file, $path) !== FALSE) { return substr($file, strlen($path)); } } $file = /var/www/example.com/uploads/myphoto.jpg; print remove_path($file, /var/www/site.com/); //prints "uploads/myphoto.jpg" 

Кто-нибудь знает, как лучше справиться с этим?

Предположим, что каталог находится в каталоге /path/to/root/document_root/user/file а адрес – site.com/user/file

Первая функция, которую я показываю, получит имя текущего файла относительно World Wide Web Address.

 $path = $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF']; 

и приведет к:

 site.com/user/file 

Вторая функция разделяет данный путь корня документа.

 $path = str_replace($_SERVER['DOCUMENT_ROOT'], '', $path) 

Учитывая, что я прошел в /path/to/root/document_root/user/file , я получил бы

 /user/file 

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

 // Some "pseudo code" $file = UploadedFile::copy($_FILES['foo']); $file->getPath(); // /var/www/example.org/uploads/foo.ext $file->getUri(); // http://example.org/uploads/foo.ext 

Более точный способ (включая порт хоста) – использовать это

 function path2url($file, $Protocol='http://') { return $Protocol.$_SERVER['HTTP_HOST'].str_replace($_SERVER['DOCUMENT_ROOT'], '', $file); } 

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

Где-то вы заявляете:

 define('PATH_IMAGES_FS', '/var/www/example.com/uploads/'); define('PATH_IMAGES_WEB', 'uploads/'); 

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

 $image_file = 'myphoto.jpg'; $file = PATH_IMAGES_FS.$image_file; //-- stores: /var/www/example.com/uploads/myphoto.jpg print PATH_IMAGES_WEB.$image_file; //-- prints: uploads/myphoto.jpg 

Попробуй это:

 $imgUrl = str_replace($_SERVER['DOCUMENT_ROOT'], '', $imgPath) 

Например, я использовал этот для преобразования C:\WAMP\WWW\myfolder\document.txt в http://example.com/myfolder/document.txt используя этот:

 $file_path=str_replace('\\','/',$file_path); $file_path=str_replace($_SERVER['DOCUMENT_ROOT'],'',$file_path); $file_path='http://'.$_SERVER['HTTP_HOST'].$file_path; 

Я использовал это и работал со мной:

 $file_path=str_replace('\\','/',__file__); $file_path=str_replace($_SERVER['DOCUMENT_ROOT'],'',$file_path); $path='http://'.$_SERVER['HTTP_HOST'].'/'.$file_path; 

И если вам нужно имя каталога в URL-адресе, добавьте эту строку:

 define('URL_DIR',dirname($path)); 

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

  $filePath = str_replace('\\','/',$filePath); $ssl = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? true : false; $sp = strtolower($_SERVER['SERVER_PROTOCOL']); $protocol = substr($sp, 0, strpos($sp, '/')) . (($ssl) ? 's' : ''); $port = $_SERVER['SERVER_PORT']; $stringPort = ((!$ssl && $port == '80') || ($ssl && $port == '443')) ? '' : ':' . $port; $host = isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']; $fileUrl = str_replace($_SERVER['DOCUMENT_ROOT'] ,$protocol . '://' . $host . $stringPort, $filePath); 

Код, приведенный ниже, хорошо прокомментирован:

 function pathToURL($path) { //Replace backslashes to slashes if exists, because no URL use backslashes $path = str_replace("\\", "/", realpath($path)); //if the $path does not contain the document root in it, then it is not reachable $pos = strpos($path, $_SERVER['DOCUMENT_ROOT']); if ($pos === false) return false; //just cut the DOCUMENT_ROOT part of the $path return substr($path, strlen($_SERVER['DOCUMENT_ROOT'])); //Note: usually /images is the same with http://somedomain.com/images, // So let's not bother adding domain name here. } echo pathToURL('some/path/on/public/html'); 

Я всегда использую символические ссылки в своей локальной среде разработки, и подход @ George не подходит в этом случае:

DOCUMENT_ROOT установлен в /Library/WebServer/Documents и есть symlink /Library/WebServer/Documents/repo1 -> /Users/me/dev/web/repo1

Предположим, что следующие коды находятся в /Users/me/dev/web/repo1/example.php

 $_SERVER['DOCUMENT_ROOT'] == "/Library/WebServer/Documents" //default on OS X 

в то время как

 realpath('./some/relative.file') == "/Users/me/dev/web/repo1/some/relative.file" 

Таким образом, замена DOCUMENT_ROOT на HTTP_HOST не работает.

Я придумал этот маленький трюк:

 function path2url($path) { $pos = strrpos(__FILE__, $_SERVER['PHP_SELF']); return substr(realpath($path), $pos); } // where __FILE__ == "/Users/me/dev/web/repo1/example.php" $_SERVER['PHP_SELF'] == "/web/repo1/example.php" realpath("./some/relative.file") == "/Users/me/dev/web/repo1/some/relative.file" // If I cut off the pre-fix part from realpath($path), // the remainder will be full path relative to virtual host root path2url("./some/relative.file") == "/web/repo1/some/relative.file" 

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