【问题标题】:How do you get PHP, Symlinks and __FILE__ to work together nicely?如何让 PHP、Symlinks 和 __FILE__ 很好地协同工作?
【发布时间】:2010-07-11 03:42:49
【问题描述】:

在本地主机上。我有以下目录结构:

/share/www/trunk/wp-content/plugins/otherfolders

/share/www/portfolio/wp-content/symlink

其中symlink 是指向/trunk/.../plugins/ 的符号链接。基本上,这是因为我需要测试多个 WordPress 安装并设置它们,但我不想移动插件并将它们复制粘贴到任何地方。

但是,有时我需要爬上目录树以包含配置文件:

 $root = dirname(dirname(dirname(dirname(__FILE__))));
      if (file_exists($root.'/wp-load.php')) {
          // WP 2.6
          require_once($root.'/wp-load.php');
      }

文件夹总是解析为:

/share/www/trunk

即使插件正在执行并包含在其中

/share/www/portfolio/.

是否可以在 PHP 中将文件从在share/www/portfolio 目录中执行的脚本中包含到/share/www/trunk/.../plugins 目录的符号链接中?

虽然此问题仅发生在我的测试服务器上,但我希望有一个可安全分发的解决方案,因此爬上一个额外的级别不是一种选择

【问题讨论】:

  • 您知道您正在执行 FILE 业务的脚本相对于入口点的位置吗?在您的示例上下文中,$_SERVER['SCRIPT_FILENAME'] 等同于什么?
  • 宾果游戏。我确切地知道我需要爬多少个目录。我只需要拥有正确的基本目录。发布答案,赏金就是你的了。
  • 另一个想法是使用硬链接而不是符号链接。或者是否有需要符号链接的原因(如其他挂载点等)?
  • 另一种选择是删除符号链接,而是挂载目录 (mount -o bind target link)。您会得到类似于符号链接的行为,并且 __FILE__ 可以正确解析。这是一种技巧,当然并不总是一种选择,但在某些用例中可能是一种可行的选择。另外,不要忘记将它添加到 fstab 文件中,否则它会在重新启动后消失。

标签: php linux symlink


【解决方案1】:

我在您的代码中看到的问题是 __FILE__ 自动解析符号链接。

来自Magic Constants上的 PHP 手册

...从 PHP 4.0.2 开始,__FILE__ 始终包含一个绝对路径,符号链接已解析...

您可以尝试改用$_SERVER["SCRIPT_FILENAME"]

$root = realpath(dirname(dirname(dirname(dirname($_SERVER["SCRIPT_FILENAME"])))));
  if (file_exists($root.'/wp-load.php')) {
      // WP 2.6
      require_once($root.'/wp-load.php');
  }

请注意,我将realpath() 函数添加到了根目录。根据您的设置,您可能需要也可能不需要它。

编辑:使用$_SERVER["SCRIPT_FILENAME"] 而不是$_SERVER["PHP_SELF"] 作为文件系统路径。

【讨论】:

  • PHP_SELF 只给出当前处理文件的值。最终结果必须是绝对路径而不是 URI。
  • 我的错...我最初是从 CLI 进行测试的。改用 $_SERVER["SCRIPT_FILENAME"] 怎么样?这在我的环境中有效。如果这不起作用,将 $_SERVER["DOCUMENT_ROOT"] 附加到 $_SERVER["PHP_SELF"] 怎么办?
  • 以下是您的问题的错误:bugs.php.net/bug.php?id=46260 遗憾的是,PHP 不会以这种方式更改,我认为这是一个错误。
  • 不幸的是,如果您正在执行的脚本包含在另一个文件中,$_SERVER["SCRIPT_FILENAME"] 将不起作用。它设置为执行的原始脚本。这是有道理的,因为 $_SERVER 变量似乎是在第一个脚本时设置的,并且与魔术常量不同,对于任何包含的脚本都不会改变。
  • 这是一个很好的解决方法,但不幸的是,我们必须默默地忽略非常无效的警告,然后正确from the manual“不能保证每个 Web 服务器都会提供其中任何一个;服务器可能会省略一些,或提供此处未列出的其他内容。"
【解决方案2】:

这是该问题的解决方案:https://github.com/logical-and/symlink-detective

$root = dirname(dirname(dirname(dirname(__FILE__))));
  if (file_exists(SymlinkDetective::detectPath($root.'/wp-load.php'))) {
      // WP 2.6
      require_once(SymlinkDetective::detectPath($root.'/wp-load.php'));
  }

或者你可以试试

try {
  $root = dirname(dirname(dirname(dirname(__FILE__))));
  require_once SymlinkDetective::detectPath($root.'/wp-load.php', '', 
    false /* this would throw an exception if file doesn't exists */);
}
catch (Exception $e) {
  // nothing to do if file doesn't exists
}

【讨论】:

  • 我真的不明白你为什么要删除我的答案。我为这个问题写了解决方案,我给出了如何使用它的例子,我写了那个答案。尝试做同样的事情,而不是删除我的帖子或至少让我知道为什么?我的信息没有用吗?
【解决方案3】:

您可以使用此代码 sn-p 获取未解析符号链接的路径。 如果您没有可用的 bash,您可能可以使用不同的命令,但它适用于 linux 环境。

我确实认为 php 解析 FILE 中的符号链接是一种弊端,因为无法通过符号链接获取路径。否则我们可以使用 realpath 轻松获得它。

哦,好吧。

<?php
$output = array();
exec('pwd', &$output);
define('__LINK__', $output[0].substr(__FILE__, strpos(__FILE__, DIRECTORY_SEPARATOR)));
?>

【讨论】:

  • 'pwd' 返回值取决于当前工作目录;要正常工作,您应该首先更改工作目录: cd /var/www/wp-content/themes/twenty_twelve/ && php script.php
【解决方案4】:

在某些情况下,可以更改工作目录并使用 getenv('PWD'):

$root = dirname(dirname(dirname(getenv('PWD'))));
if (file_exists($root.'/wp-load.php')) {
    // WP 2.6
    require_once($root.'/wp-load.php');
}

并在运行此代码之前更改工作目录:

cd /var/www/wp-content/themes/twenty_twelve/ && php script.php

【讨论】:

    【解决方案5】:

    PHP 解释器在处理符号链接之前解析它们。您可以使用 readlink 函数自己执行此操作。 PHP 解析链接是因为它对*_once 函数和代码缓存(如 APC、Xcache 等)更有效。

    您可能需要的是另一种查找特定安装文件存储位置的方法。我建议使用 {$_SERVER['DOCUMENT_ROOT']}/wp-content/wp-load.php 假设 /share/www/portfolio 是文档根。

    【讨论】:

    • 文档根目录不幸的是/share/www/
    【解决方案6】:

    如果我试图解决这个问题,我会沿着路径位拆分__FILE__,并为每个位创建一个SplFileInfo,使用isDirisLink 进行测试,然后尝试确定如何一旦知道路径与预期不同,就可以处理路径的重建,以便您可以从正确的目录中提取。 (如果您更偏向于程序类型,则有 is_diris_link。)

    话虽如此,我认为您已经取消了此解决方案的资格。也许这些工具足够聪明,可以为你做这件事。尝试将getRealPath 的结果与getPath 进行比较? getRealPath 明确表示它解析符号链接,而 getPath 没有明确表示。

    即便如此,这种嗅探在客户端站点上可能并不安全,具体取决于主机是谁。我见过一些非常创意的共享主机文件系统设置。您可以在php_uname 中添加检查并提取机器的主机名,如果它不是您的开发框,请不要做额外的工作。

    【讨论】:

    • 很遗憾,getRealPathgetPath 都输出了/trunk/ 目录。
    猜你喜欢
    • 2019-09-09
    • 2010-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    • 2016-12-08
    • 2020-11-24
    • 1970-01-01
    相关资源
    最近更新 更多