Абсолютный путь без разрешения символической ссылки / Сохранить пользователя в домашнем каталоге - PullRequest
5 голосов
/ 29 июня 2011

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

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

Спасибо!

Ответы [ 3 ]

2 голосов
/ 29 июня 2011

Я не знаю нативного решения PHP для этого, но одна хорошая реализация абсолютного пути здесь: http://www.php.net/manual/en/function.realpath.php#84012

0 голосов
/ 10 мая 2015

Вот мой подход, имитирующий оригинальную realpath(), которая также:

  1. Добавляет / удаляет буквы дисков Windows, как в c:.
  2. Удаляет завершающие косые черты.
  3. Предварительно добавляет текущий рабочий каталог к ​​относительным путям.
  4. Дополнительно проверяет существование файла.В случае несуществующего файла A) ничего не делать, B) возвращать значение FALSE или C) выдавать ошибку.
  5. При желании следовать символическим ссылкам.

Примечание: этот подход используетрегулярные выражения, которые, как известно, дорогостоящие, поэтому мне нравится метод, использующий массивы из http://www.php.net/manual/en/function.realpath.php#84012.

// Set constants for when a file does not exist.
// 0: Check file existence, set FALSE when file not exists.
define('FILE_EXISTENCE_CHECK', 0);
// 1: Require file existence, throw error when file not exists.
define('FILE_EXISTENCE_CHECK_REQUIRE_FILE', 1);
// 2: Do not check file existence.
define('FILE_EXISTENCE_CHECK_SKIP', 2);
// Windows flag.
define('IS_WINDOWS', preg_match('#WIN(DOWS|\d+|_?NT)#i', PHP_OS));
// Directory separator shortcuts.
define('DIR_SEP', DIRECTORY_SEPARATOR);
define('PREG_DIR_SEP', preg_quote(DIR_SEP));

/**
 * The original realpath() follows symbolic links which makes it harder to check
 * their paths.
 *
 * Options
 *   file_existence_check:
 *   - FILE_EXISTENCE_CHECK_REQUIRE_FILE: Script will break if the checked
 *     file does not exist (default).
 *   - FILE_EXISTENCE_CHECK: If a file does not exist, a FALSE value will be
 *     returned.
 *   - FILE_EXISTENCE_CHECK_SKIP: File existence will not be checked at all.
 *
 *   follow_link: Resolve a symbolic link or not (default: FALSE).
 */
function _realpath($path = NULL, $options = array()) {
  // Merge default options with user options.
  $options = array_merge(array(
    'file_existence_check' => FILE_EXISTENCE_CHECK_REQUIRE_FILE,
    'follow_link' => FALSE,
  ), $options);

  // Use current working directory if path has not been defined.
  $path = $path ? $path : getcwd();
  // Replace slashes with OS specific slashes.
  $path = preg_replace('#[\\\/]#', DIR_SEP, $path);

  // Handle `./`. Another great approach using arrays can be found at:
  // @link p://php.net/manual/en/function.realpath.php#84012
  $path = preg_replace('#' . PREG_DIR_SEP . '(\.?' . PREG_DIR_SEP . ')+#', DIR_SEP, $path);
  // Handle `../`.
  while (preg_match('#^(.*?)' . PREG_DIR_SEP . '[^' . PREG_DIR_SEP . ']+' . PREG_DIR_SEP . '\.\.($|' . PREG_DIR_SEP . '.*)#', $path, $m)) {
    $path = $m[1] . $m[2];
  }
  // Remove trailing slash.
  $path = rtrim($path, DIR_SEP);

  // If we are on Windows.
  if (IS_WINDOWS) {
    // If path starts with a lowercase drive letter.
    if (preg_match('#^([a-z]:)(.*)#', $path, $m)) {
      $path = strtoupper($m[1]) . $m[2];
    }
    // If path starts with a slash instead of a drive letter.
    elseif ($path[0] === DIR_SEP) {
      // Add current working directory's drive letter, ie. "D:".
      $path = substr(getcwd(), 0, 2) . $path;
    }
  }
  else {
    // Remove drive letter.
    if (preg_match('#^[A-Z]:(' . PREG_DIR_SEP . '.*)#i', $path, $m)) {
      $path = $m[1];
    }
  }

  // If path is relative.
  if (!preg_match('#^([A-Z]:)?' . PREG_DIR_SEP . '#', $path)) {
    // Add current working directory to path.
    $path = getcwd() . DIR_SEP . $path;
  }

  // If file existence has to be checked and file does not exist.
  if ($options['file_existence_check'] !== DSC_FILE_EXISTENCE_CHECK_SKIP && !file_exists($path)) {
    // Return FALSE value.
    if ($options['file_existence_check'] === DSC_FILE_EXISTENCE_CHECK) {
      return FALSE;
    }
    // Or throw error.
    else {
      dsc_print_error('File does not exist: ' . $path);
    }
  }

  // Follow sybmolic links, but only if the file exists.
  if (!empty($options['follow_link']) && file_exists($path)) {
    $path = readlink($path);
  }

  return $path;
}
0 голосов
/ 29 июня 2011

Вы можете использовать open_basedir с настройкой ini php.ini или в объявлении виртуального хоста (как директива php_admin_value).

...