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 有关。您需要指定一个完整路径,并且您只指定一个文件名。在使用之前尝试echoing $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 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如果在 while 循环内,则无法跳出 while 循环

Java JDBC Single Statement 对象在 while 循环之前和 while 循环内

C ++在while循环内更​​改变量

布尔条件内带有函数的while循环

如何在 while 循环内更新 api 调用?

无限while循环内的Sleep()函数