PHP unlink()函数和西里尔字母

4

我在使用unlink()函数删除文件时遇到了问题。当文件名为西里尔字母时,该函数无法正常工作。

[2012年7月24日00:33:35 UTC] PHP警告: unlink(/home/gtsvetan/public_html/мениджър.doc) [function.unlink]:没有这样的文件或目录 在/home/gtsvetan/public_html/deleter.php的第114行

那么如何在文件名为西里尔字母时删除文件呢?

以下是代码:

$dir = is_array($dir) ? $dir : explode(',', $dir);
foreach($dir as $dirv) {
    if(is_dir($dirv)) {
        $objects = scandir($dirv);
        foreach($objects as $object) {
            if($object != "." && $object != "..") {
                if(filetype($dirv."/".$object) == "dir") {
                    $this->delete($dirv."/".$object); 
                }
                else {
                    unlink($dirv."/".$object);
                }
            }
        }
    reset($objects);
    rmdir($dirv);
    }
    else {
        unlink($dirv);
    }
}

解决方案:
public function delete($dir) {
        $dir = is_array($dir) ? $dir : explode(',', $dir);
        foreach($dir as $dirv) {
            if(is_dir($dirv)) {
                $d = @dir($dirv) or die();
                while(false !== ($entry = $d->read())) {
                    if($entry[0] == ".") {
                        continue;
                    }
                    if(is_dir($dirv.$entry.'/')) {
                        $this->delete($dirv.$entry.'/');
                        @rmdir($dirv.$entry);
                    }
                    elseif(is_readable($dirv.$entry)) {
                        @unlink($dirv.$entry);
                    }
                }
                $d->close();
            }
            else {
                @unlink($dirv);
            }
            @rmdir($dirv);
        }
    }

这里是ajax.php,它创建了该类的实例:)

case 'delete':
$location = $_POST['location'];
if(is_array($location)) {
    foreach($location as $v) {
    $loc[] = iconv('utf-8', 'cp1251', $v);
    }
    $pfm->delete($loc);
}
else {
    $location = iconv('utf-8', 'cp1251', $location);
    $pfm->delete($location);
}
break;

对我来说它完美地运作了 :)


1
@T0m3kk:is_file()检查文件是否存在,而不仅仅是它是否为文件。这就是@alex的意思。 - user405725
@VladLazarenko 和 @alex,我尝试使用 is_file(),但它无法将其检测为文件。 - user546774
@VladLazarenko 如果使用is_file()作为条件执行unlink(),就不应该出现竞争条件。 - alex
1
@alex:不是的,这是两个不同的系统调用。在这些调用之间,文件可能已经消失了(即被其他应用程序删除)。 - user405725
@drew010,解决方案已添加 :) - user546774
显示剩余8条评论
4个回答

0

unlink 在 PHP 中只是转发到相应的系统调用。文件名将原样传递给该函数,因为 PHP 字符串只是不透明的字节序列。这意味着名称需要使用系统调用理解的编码方式。换句话说,这取决于您的操作系统。您还需要知道文件名的当前编码方式;这取决于输入来源。

如果您知道系统调用想要 UTF-8(在 Linux 上是正确的),并且当前名称在 ISO-8859-5 中,则使用 iconv 的解决方案如下:

unlink(iconv('iso-8859-5', 'utf-8', $dirv."/".$object));

当然,你也可以使用mb_convert_encoding来做同样的事情。对于所有其他与文件系统相关的调用,也需要进行相同的处理。

0

嗯,我做了这个,可能会有用。

    <?php
function delete($link) {
    foreach($link as $u) {
        if(is_dir($u)) {
            delete(glob($u . DIRECTORY_SEPARATOR . "*"));
            rmdir($u);
        } else; unlink($u);
    }
    return;
}

delete(glob(__DIR__ . DIRECTORY_SEPARATOR . "*"));
?>

0

我发现清理文件名总是一个好主意。个人喜欢让脚本命名文件,而不是用户(尤其是上传的文件)。创建一个清洁函数,将西里尔字母转换为其它字符。可以看一下 convert_cyr_string :: http://php.net/manual/en/function.convert-cyr-string.php

另一个想法是,重命名文件是否和删除文件一样会有问题?如果不是,将其重命名为类似 tobedeleted.ext 的东西,然后取消链接它。


0

如果它运行不良,我建议先将其重命名。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接