Продолжая писать компонент медиасурса (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); } }
Нашел чуть более элегантное решение:
$name = rawurldecode(basename(rawurlencode($name)));
Пока работает без нареканий.
Круто! Возьму на заметку.
Нифига оно не работает, я поторопился от радости и недотестировал. Тогда вот такой вариант:
$name = array_pop(explode(DIRECTORY_SEPARATOR, $name))
Собственно, и это гораздо меньше по объему, чем представленная в топике функция.