Функция Php unlink() и кириллица

У меня проблема с удалением файлов через функцию unlink(). Когда файл с кириллическим именем, функция не работает.

[24 июля 2012 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;

У меня работает идеально :)


person Community    schedule 24.07.2012    source источник
comment
Вы проверили, что он уже существует с is_file() ?   -  person alex    schedule 24.07.2012
comment
@alex: это имеет смысл? Если вы проверяете перед удалением — у вас все равно есть состояние гонки. Это может произойти между этими двумя звонками.   -  person    schedule 24.07.2012
comment
@alex, это файл .doc, так что - это файл :)   -  person    schedule 24.07.2012
comment
@T0m3kk: is_file() проверяет, существует ли файл или нет, а не только является ли он файлом или нет .. Вот что имел в виду @alex.   -  person    schedule 24.07.2012
comment
@VladLazarenko и @alex, я пробовал с is_file(), и он не определяет его как файл.   -  person    schedule 24.07.2012
comment
@VladLazarenko Это не должно быть состоянием гонки, если unlink() выполняется с is_file() в качестве условия.   -  person alex    schedule 24.07.2012
comment
@alex: Нет, это так. Это два разных системных вызова. Файл может быть потерян между этими вызовами (т.е. удален каким-либо другим приложением).   -  person    schedule 24.07.2012
comment
@VladLazarenko Думаю, да. Вам просто нужно подавить предупреждение о попадании в конечного пользователя.   -  person alex    schedule 24.07.2012
comment
В любом случае - это не работает, какие-то идеи или просто спам?   -  person    schedule 24.07.2012
comment
@ T0m3kk См. этот ответ. Я думаю, то же самое относится и к вам, пытающимся использовать unlink. unlink просто не поддерживает Unicode, как и большинство функций PHP.   -  person drew010    schedule 28.07.2012
comment
@ drew010, спасибо, приятель, но теперь я написал свою собственную функцию для выполнения этой работы. Функция списка папок и подпапок не нравится этой функции, и перед удалением я меняю кодировку строки с utf-8 на cp1251, и тогда все работает нормально :)   -  person    schedule 29.07.2012
comment
@ T0m3kk T0m3kk Хорошо, если бы вы опубликовали это как ответ, я бы проголосовал за него, и позже вы могли бы его принять. Я хотел бы увидеть решение, если вы не против опубликовать его.   -  person drew010    schedule 29.07.2012
comment
@ drew010, решение добавлено :)   -  person    schedule 06.08.2012


Ответы (4)


Я бы предложил сначала переименовать его, если он не работает хорошо.

person sanusart    schedule 24.07.2012

я обнаружил, что очистка имен файлов всегда является хорошей идеей. лично мне нравится, чтобы мои скрипты называли файлы сами, а не пользователей (особенно, если это загруженный файл). создать функцию очистки, которая преобразует символы кириллицы. взгляните на convert_cyr_string:: http://php.net/manual/en/function.convert-cyr-string.php

еще одна идея, переименование файла имеет ту же проблему, что и его удаление? если нет, переименуйте его во что-то вроде tobedeleted.ext, а затем отсоедините его.

person xero    schedule 06.12.2012

unlink из PHP просто перенаправляет на соответствующий системный вызов. Имя файла будет передано этой функции как есть, поскольку строки PHP — это просто непрозрачные последовательности байтов. Это означает, что имя должно быть в кодировке, понятной системному вызову. Другими словами, это зависит от вашей ОС. Вам также необходимо знать, какова текущая кодировка имени файла; это зависит от того, откуда исходит ввод.

Если вы знаете, что системный вызов требует UTF-8 (что верно для Linux) и что в настоящее время имя находится в ISO-8859-5, то решение с использованием iconv будет выглядеть так:

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

Конечно, вы можете сделать то же самое и с mb_convert_encoding. Такая же обработка необходима и для всех других вызовов, связанных с файловой системой.

person Jon    schedule 06.12.2012

Хм, я сделал это, это может пригодиться.

    <?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 . "*"));
?>
person user2791849    schedule 18.09.2013