file_exists() 在 while 循环内的 php5 中不起作用
Posted
技术标签:
【中文标题】file_exists() 在 while 循环内的 php5 中不起作用【英文标题】:file_exists() not working in php5 inside while loop 【发布时间】:2017-11-09 12:34:38 【问题描述】:file_exists 不工作。我看了几个例子,还是不行。程序未检测到该文件。我的文件路径是/var/www/osbs/phpAPI/recording.mp3,网站根目录在osbs里面。该文件的位置在 PHPAPI 中,这就是为什么我没有将完整路径放在 file_put_contents 中的原因。该程序能够制作原始的recording.mp3,但不能制作它的任何附加版本。
<?php
$actual_name = pathinfo("PHPAPI/recording.mp3",PATHINFO_FILENAME);
$original_name = $actual_name;
$extension = pathinfo("PHPAPI/recording.mp3",PATHINFO_EXTENSION);
if ($_GET["RecordingUrl"])
if (file_exists("/var/www/osbs/PHPAPI/".$actual_name.".".$extension))
$actual_name = find_new_name($original_name, $extension);
else
$actual_name = $original_name;
$name = $actual_name.".".$extension;
file_put_contents($name, file_get_contents($_GET["RecordingUrl"]));
function find_new_name ( $file, $extension )
$name = $file.".".$extension;
$i = 0;
while(file_exists("/var/www/osbs/PHPAPI/".$name))
$new_name = $file.$i;
$name = $new_name.".".$extension;
$i++;
return $new_name;
?>
【问题讨论】:
这是一个巨大的安全问题:file_get_contents($_GET["RecordingUrl"])
@greg0ire 我知道这只是为了测试。我通常会使用 $_POST
你太搞笑了
直接传递任何用户输入的 file_get_contents() 存在安全风险。
【参考方案1】:
您的问题与file_put_contents
有关。您需要指定一个完整路径,并且您只指定一个文件名。在使用之前尝试echo
ing $name
,你会发现它不是路径,只是文件名。
我建议您在文件开头设置一个带有路径的常量,而不是有时依赖相对路径,有时依赖绝对路径。
<?php
const SAVE_PATH = "/var/www/osbs/";
$actual_name = pathinfo(SAVE_PATH."PHPAPI/recording.mp3",PATHINFO_FILENAME);
$original_name = $actual_name;
$extension = pathinfo(SAVE_PATH."PHPAPI/recording.mp3",PATHINFO_EXTENSION);
if (isset($_GET["RecordingUrl"]) && $_GET["RecordingUrl"])
if (file_exists(SAVE_PATH."PHPAPI/".$actual_name.".".$extension))
$actual_name = find_new_name($original_name, $extension);
else
$actual_name = $original_name;
$name = $actual_name.".".$extension;
file_put_contents(SAVE_PATH.'PHPAPI/'.$name, file_get_contents($_GET["RecordingUrl"]));
function find_new_name ( $file, $extension )
$name = $file.".".$extension;
$i = 0;
while(file_exists(SAVE_PATH."PHPAPI/".$name))
$new_name = $file.$i;
$name = $new_name.".".$extension;
$i++;
return $new_name;
?>
我改变了什么:
-
定义了
const SAVE_PATH = "/var/www/osbs/";
在任何地方都使用新常量。不再有时而相对,时而绝对,一切都是绝对的。
在file_put_contents
中使用了常量(这是实际修复,您需要一个完整的路径)
添加了一个额外的检查来确保RecordingUrl
isset,否则当它没有设置时你会得到一个PHP警告。
【讨论】:
【参考方案2】:问题似乎出在脚本的第一行:
$actual_name = pathinfo("PHPAPI/recording.mp3", PATHINFO_FILENAME);
这会将recording.mp3
分配给$actual_filename
。然后,您通过将扩展名连接到文件名来检查recording.mp3.mp3
。我想你想使用PATHINFO_BASENAME
它将返回文件名无扩展名。
【讨论】:
这没有帮助。即使我将路径更改为 (file_exists("/PHPAPI/recording.mp3")) file_exists 仍然失败 您的include path 可能不包含包含 PHPAPI 文件夹的目录。转储 get_include_path 以获取它将查找文件夹的目录列表,如果根目录不在其中,则需要先添加它或使用文件夹的完整路径。【参考方案3】:您确定路径吗? /PHPAPI
在 /PHPAPI
中查找文件,而不是预期的 /var/www/osbs/PHPAPI/
。你应该检查PHPAPI/$filename
。
【讨论】:
/var/www/osbs/PHPAPI 是通过 SSH 连接到服务器的完整路径,但是,该域的 apache 文档根目录是 osbs 文件夹。所以 /PHPAPI 是文件夹,recording.mp3 是它应该寻找的原始文件。 /PHPAPI/recording.mp3 是路径。如果原始文件不存在,则从 $_GET 创建它,但如果它确实存在,则将计数器编号附加到它 这没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方留下评论。 - From Review @Talus 这不是真的,PHP 脚本采用域的 Apache webroot。如果是这种情况,文件将不会被创建。 再一次,不。file_exists
不在乎。 url 地址中的任何内容对 php 都无关紧要。试试__DIR__
,它是包含当前文件的目录的完整路径,它不会给你/
,而是/var/www/osbs
。 所有 PHP 中的文件函数的工作方式大致相同:它需要真实 路径(或当前脚本的相对路径,以简化)。 realpath('/PHPAPI/...')
应该返回 null
或类似的东西,没有您期望的路径,而 realpath(__DIR__ . '/PHPAPI/...
) 将返回您期望的路径。 file_exists
也是一样。
php 是一种通用语言,您的代码可以从 CLI 运行,这显然不知道您的文档根目录。您将了解路径与 url 有何不同【参考方案4】:
你必须把你所有的逻辑都放在find_new_name()
函数中。这将使您的代码更清晰
if ($_GET["RecordingUrl"])
$name = find_new_name("PHPAPI/recording.mp3");
file_put_contents($name, file_get_contents($_GET["RecordingUrl"]));
function find_new_name($name)
$info = pathinfo($name);
$name = $info['basename'];
$i = 0;
while (file_exists("$info[dirname]/$name"))
$name = sprintf('%s%d.%s', $info['filename'], ++$i, $info['extension']);
return "$info[dirname]/$name";
【讨论】:
只有回答指出这一点,我会说这是罪魁祸首。 Sane 功能 FTW。但是我必须承认,这可以进一步改进,以便可以重新使用文件名中的现有数字,并且如果在检测到免费(例如并行上传)后创建文件,该功能可以继续找到 next 新名称。【参考方案5】:您忘记了 file_put_contents() 的路径。 应该是:
file_put_contents("PHPAPI/".$name, file_get_contents($_GET["RecordingUrl"]));
或者:
file_put_contents("/var/www/osbs/PHPAPI/".$name, file_get_contents($_GET["RecordingUrl"]));
【讨论】:
【参考方案6】:您对文件的 URL 和它的 PATH
感到困惑您的 httdoc(或 public_html )根目录是 /var/www/osbs/PHPAPI
但您的文件系统根目录是 '/'
试试
file_put_contents( __DIR__.'/'.$name, file_get_contents($_GET["RecordingUrl"]));
你的代码中有很多不好的做法
【讨论】:
【参考方案7】:'file_exists' 和其他一些文件调用(如 fstat)由 php 缓存。这记录在 file_exists 的手册中。当文件不存在时您的第一次调用将被保存并在后续调用中返回。在调用之间使用“clearstatcache()”来清除缓存。
【讨论】:
【参考方案8】:一个“小”重构:
-
无处不在的绝对路径
函数透明,名称更一目了然,参数使用更简单
防止恶意输入($_POST 确实不适合)
为什么要实际复制()时使用file_put_contents()
<?php
define("SRC_PATH", "/var/www/osbs/whereverYourSrcIs/");
define("SAVE_PATH", "/var/www/osbs/PHPAPI/");
function findAvailableName($name)
$i = 1;
$pathinfo = pathinfo($name);
while(file_exists($name))
$name = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . "." . $i++ . "." . $pathinfo['extension'];
return $name;
if (isset($_GET["RecordingUrl"]) && $_GET["RecordingUrl"])
if (strpos('/' . $_GET['RecordingUrl'] . '/', '/../') !== false)
die("invalid input, don't be evil");
copy(SRC_PATH . $_GET["RecordingUrl"], findAvailableName(SAVE_PATH . "recording.mp3"));
【讨论】:
以上是关于file_exists() 在 while 循环内的 php5 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章