Проблемы с русскими именами файлов и участников

Автор erm, 18 февраля 2006, 14:27:40

« назад - далее »

0 Пользователи и 2 гостей просматривают эту тему.

erm

Тема отчасти отностится к проблемам русификации, а отчасти к проблемам движка.

Не работает отправка Личных Сообщений участникам с русским именем регистрации. При попытке отправки имя участника преобразуется к верхнему регистру и выдаётся сообщение "Не могу найти пользователя 'АЛЕКСАНДР ЮРЬЕВИЧ'." Хотя при нажатии ссылки для отправки сообщения в профиле пользователя изначально имя верное "Александр Юрьевич". Участникам с английскими именами сообщения отправляются нормально.

Вложения с русскими именами файлов присутствуют в сообщении к которому прикреплены и видны в списке файлов в разделе администрирования, но при нажатии ссылки на такое вложение получаем "404 - Вложение не найдено", также, если это изображение, то его не видно в сообщении, к которому оно прикреплено, видно только ссылку на файл.

ОС FreeBSD 5.4 и локаль ru_RU.KOI8-R. Но форум в cp1251. Общая причина появления пользователей с русскими именами и русских названий файлов - перенос содержимого формума на движке Invision Board 1.3.1.
Пользователей и файлов много, поэтому переименовать сложно, но даже если и возможно, то основная сложность в том, чтобы не нарушить связность между файлами на диске и их внутренними цифровыми обозначениями. Поэтому предпочтительно научить движок форума корректно работать с русскими символами.

erm

#1
С файлами происходит следующее:
Форум был перенесён на версию 1.0.6, т.к. конвертер не работает с версией 1.1
Все имена файлов приобрели вид ID_имя_расширениеMD5 в том числе и с русскими именами, например, 1_ПЕЙНПД_1001_jpg19fbf15ba6e00c9e67e40ce27236928b
Но в версии 1.1 RC2 в функции getAttachmentFilename в файле Subs.php для русских имён файлов предполагается другое кодирование, а именно dhaeidha_1001.jpg для "чистых" имён и 1_dhaeidha_1001_jpg19fbf15ba6e00c9e67e40ce27236928b для кодированных.

Исправить можно пропустив имена файлов через "фильтр" взятый из вышеуказанной функции.

Скрипт запускать через web интерфейс из корневого каталога форума, один раз.

<?php
// Get the bad filename in the old format
function filter1($filename$attachment_id)
{
        
// Sorry, no spaces, dots, or anything else but letters allowed.
        
$clean_name preg_replace(array('/\s/''/[^\w_\.\-]/'), array('_'''), $filename);

        
$enc_name $attachment_id '_' strtr($clean_name'.''_') . md5($clean_name);
        
$filename 'attachments/' $enc_name;

        return 
$filename;
}

// Get the right filename in the new format
function filter2($filename$attachment_id)
{
        
// Remove special accented characters - ie. sМ.
        
$clean_name strtr($filename'~J~N~Z~^~_юабцдегхийклмноярстужьызшэщЮАБЦДЕГХИЙКЛМНОЯРСТУЖЬЫЗШЭЩЪ''SZszYAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiii
noooooouuuuyy'
);
        
$clean_name strtr($clean_name, array('ч' => 'TH''Ч' => 'th''п' => 'DH''П' => 'dh''ъ' => 'ss''~L' => 'OE''~\' => 'oe', 'ф' => 'AE', 'Ф'
 => '
ae', '' => 'u'));

        // Sorry, no spaces, dots, or anything else but letters allowed.
        $clean_name = preg_replace(array('
/\s/', '/[^\w_\.\-]/'), array('_', ''), $clean_name);

        $enc_name = $attachment_id . '
_' . strtr($clean_name, '.', '_') . md5($clean_name);

        $filename = '
attachments/' . $enc_name;

        return $filename;
}

define('
SMF', 1);
// Load the settings...
require_once(dirname(__FILE__) . '
/Settings.php');
require_once($sourcedir . '
/Subs.php');

// Connect to the MySQL database.
if (empty($db_persist))
        $db_connection = @mysql_connect($db_server, $db_user, $db_passwd);
else
        $db_connection = @mysql_pconnect($db_server, $db_user, $db_passwd);

// Show an error if the connection couldn'
t be made.
if (!
$db_connection || !@mysql_select_db($db_name$db_connection))
        
db_fatal_error();

// Get the all attachments from the MySQL database
$request db_query("SELECT a.filename, a.ID_ATTACH, a.attachmentType, a.size FROM {$db_prefix}attachments AS a"__FILE____LINE__);
if (
mysql_num_rows($request) == 0) { echo 'error1'; exit(1);}

print(
'<html><head><title>attachments</title></head><body><table>');

while(
$row=mysql_fetch_row($request)) {
        
$filename1 filter1($row[0],$row[1]);
        
$filename2 filter2($row[0],$row[1]);
        if(
file_exists($filename1)) rename($filename1,$filename2);
        print(
"<tr><td>$row[0]</td><td>$filename1</td><td>$filename2</td></tr>");
}
print(
'</table></body></html>');
?>


erm

#2
Проблема русских Личных Сообщений гораздо глубже и следует из активного применения функции strtolower. А странное поведение достигается работой функции IN в SELECT запросе MySQL, она находит запись в одном случае и не находит в другом, казалось бы похожем случае. На что надеялись разработчики данного php кода не понятно и по-хорошему он требует глобального переписывания.

В общем, исправил для себя, буду смотреть на счёт глюков.
Основной смысл исправления - убрать strtolower
Для этого в файле Sources/Subs-Auth.php находим строку в функции findMembers()
$names[$i] = addslashes(trim(strtolower($name)));
и меняем на
$names[$i] = addslashes(trim($name));
В файле Sources/PersonalMessage.php находим и меняем строки в функции MessagePost2()
$input[$rec_type][$index] = preg_replace('~&amp;#(\d{4,5}|[2-9]\d{2,4}|1[2-9]\d);~', '&#$1;', htmlspecialchars(strtolower(stripslashes(trim($member)))));
меняем на
$input[$rec_type][$index] = preg_replace('~&amp;#(\d{4,5}|[2-9]\d{2,4}|1[2-9]\d);~', '&#$1;', htmlspecialchars(stripslashes(trim($member))));
Строку
if (array_intersect(array(strtolower($member['username']), strtolower($member['name']), strtolower($member['email'])), $to_members))
меняем на
if (array_intersect(array($member['username'], $member['name'], strtolower($member['email'])), $to_members))
И наконец строку
$input[$rec_type] = array_diff($input[$rec_type], array(strtolower($member['username']), strtolower($member['name'])
, strtolower($member['email'])));

меняем на
$input[$rec_type] = array_diff($input[$rec_type], array($member['username'], $member['name'], strtolower($member['em
ail'])));

Вызов функции findMembers() имеется также в функции JSMembers() и используется для поиска пользователей, но работа этой функции на первый взгляд корректна и поэтому я там ничего не менял.

Mavn

SimpleMachines Russian Community Team
п.1 Пройду курсы гадалок для определения исходного кода по скриншоту.

п.2 У вас нет желания читать правила раздела, у меня нет желания одобрять темы, которые не соответствуют этим правилам.

эНДжей

Цитата: erm от 19 февраля 2006, 00:10:27
В общем, исправил для себя, буду смотреть на счёт глюков.
Огромное спасибо!!! Помогло.