Fi1osof 05 декабря 2014 0 4
Продолжая писать компонент медиасурса (mediasource) Dropbox, о котором я говорил вчера (да-да, он пилится и уже сегодня будет опубликован:)), наткнулся на весьма неприятный баг. Собственно, самые наблюдательные могли его заметить еще вчера на этой картинке:

На ней две директории представлены как корневые, то есть имеют только слеш / и все. На самом деле это просто косяк с кириллическими именами файлов. При чем _и_Я — это тоже не полное название, просто после некириллических символов кириллические тоже начинают восприниматься.

Так вот, эта проблема проявилась и в админке при работе с источником файлов:


При этом самая печаль была с перетаскиванием. Если перетащить такую папку, то в новую она запишется с обрезанным именем. Как многие конечно же догадались, виновата в этом была функция basepath(), которая никак не хочет дружить с кириллицей. Ответ нашел здесь. Запись 2011-го года. Уже тогда автор задавался вопросом:
одно не понятно, в PHP этот баг уже несколько лет существует, почему бы не поправить… Пых, одним словом...
На носу 2015-ый, а бага так до сих пор не поправлена…

P.S. повторю спасительный код:
function pcgbasename($param, $suffix=null) { 
        if ( $suffix ) { 
            $tmpstr = ltrim(substr($param, strrpos($param, DIRECTORY_SEPARATOR) ), DIRECTORY_SEPARATOR); 
            if ( (strpos($param, $suffix)+strlen($suffix) )  ==  strlen($param) ) { 
                return str_ireplace( $suffix, '', $tmpstr); 
            } else { 
                return ltrim(substr($param, strrpos($param, DIRECTORY_SEPARATOR) ), DIRECTORY_SEPARATOR); 
            } 
        } else { 
            return ltrim(substr($param, strrpos($param, DIRECTORY_SEPARATOR) ), DIRECTORY_SEPARATOR); 
        } 
    }


P.P.S Переписал на мультибайтовые функции для MODX-а:
protected function basename($param, $suffix=null){
        $charset = $this->xpdo->getOption('charset', 'utf-8');
        if ( $suffix ) { 
            $tmpstr = ltrim(mb_substr($param, mb_strrpos($param, DIRECTORY_SEPARATOR, null, $charset), null, $charset), DIRECTORY_SEPARATOR); 
            if ( (mb_strpos($param, $suffix, null, $charset)+mb_strlen($suffix, $charset) )  ==  mb_strlen($param, $charset) ) { 
                return str_ireplace( $suffix, '', $tmpstr); 
            } else { 
                return ltrim(mb_substr($param, mb_strrpos($param, DIRECTORY_SEPARATOR, null, $charset), null, $charset), DIRECTORY_SEPARATOR); 
            } 
        } else { 
            return ltrim(mb_substr($param, mb_strrpos($param, DIRECTORY_SEPARATOR, null, $charset), null, $charset), DIRECTORY_SEPARATOR); 
        }
    }
4 комментария
b
bezumkin 15 января 2016г в 18:13 #
Нашел чуть более элегантное решение:
$name = rawurldecode(basename(rawurlencode($name)));

Пока работает без нареканий.
Fi1osof1
Fi1osof 15 января 2016г в 18:27 #
Круто! Возьму на заметку.
b
bezumkin 15 января 2016г в 18:32 #
Нифига оно не работает, я поторопился от радости и недотестировал. Тогда вот такой вариант:
$name = array_pop(explode(DIRECTORY_SEPARATOR, $name))
Fi1osof1
Fi1osof 16 января 2016г в 18:34 #
Собственно, и это гораздо меньше по объему, чем представленная в топике функция.
Авторизуйтесь или зарегистрируйтесь (можно через соцсети ), чтобы оставлять комментарии.