Проблема с upload'ом файлов с русскими именами

Главные вкладки

Аватар пользователя Ustas Ustas 5 апреля 2007 в 18:42

Platform: Gentoo Linux (locale: UTF-8) + Apache2 + PHP5 + MySQL
Drupal version: 5.1

Столкнулся с такой проблемой. При добавлении файлов с русскоязычными именами в названии файла отрезается первое слово до первого пробела или символа подчеркивания. В результате IE не может открывать прикрепленные к нодам файлы. В FF все работает.
С англоязычными именами файлов все ок.

На Drupal.org ничего не нашел по этому поводу. Сталкивался ли кто-нибудь с подобной проблемой?

Комментарии

Аватар пользователя PVasili PVasili 5 апреля 2007 в 19:12

попробкуйте транслитерировать файлы,при сохранении на сервер.
А вообще национальные алфавиты в коммандной строке броузера(без преобразования),а хотят и доменные имена-бред полнейший(imho).
Попробуй найти и отличить mama,мaмa и mамa Smile
======================================================
[url=http://wiki.drupal.ru]Документация[/url],[url=http://wiki.drupal.ru/doc/poleznye_ssylki_dlya_dizainerov]Дизайн[/url],[url=http://wiki.drupal.ru/doc/gotovye_perevody]Переводы[/url]

Аватар пользователя qman qman 5 апреля 2007 в 21:36

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

Аватар пользователя Ustas Ustas 6 апреля 2007 в 15:37

у меня ощущение, что транслитерация должна производиться еще на стороне клиента (если загрузка производится с помощью AJAX'овского интерфейса). Если же транслитерацию делать на стороне сервера, то тогда подскажите, какую функцию использовать - я в стандартной библиотеке PHP такого не помню (только в PECL что-то было, по-моему)..

А вообще, процесс решения проблемы я бы разбил на следующие шаги:

  1. Определить, где происходит потеря первого слова (на стороне клиента или уже на сервере) - для этого надо проанализировать, что приходит из формы на сервер.
  2. В зависимости от того, где происходит потеря слова, добавить преобразование в транслит там, где косяк возникает.

Кто поможет?

Аватар пользователя vitamin vitamin 15 апреля 2007 в 16:40

Ничего предосудительного в национальных алфавитах в URLе не вижу (с доменными именами, действительно, перебор). Патчить модуль надо на предмет urlencode() и urldecode(), чтоб это работало везде. Ну и разобраться кто первое слово отрезает.
Что-то не нашёл на drupal.org issue по этому поводу. Действительно нет, или плохо искал? Проблема-то, похоже, давняя.

Аватар пользователя kiev1 kiev1 15 апреля 2007 в 17:06

а русские буквы и на диске в некоторых файловых системах плохо сохраняются
поэтому надо взять функцию транслита из pathauto и вставить в upload или еще лучше дописать ее в ядро потому что iconv не всегда правильно работает и не у всех есть

Аватар пользователя vitamin vitamin 17 апреля 2007 в 17:37

значит надо использовать нормальные файловые системы, где проблем с алфавитами нет
а транслитерировать всё - это идиотизм
представьте себе бизнес-портал, на котором собираются люди, не разбирающиеся в компьютерах
и дела им нет ни до каких файловых систем и кодировок
а тут имена файлов (например, msword - сплошь и рядом) преобразуются в транслит
неудобно и неимиджево

ps: поглядел upload.module.. там все строковые ф-ии восьмибитные.. не ожидал, что такое будет в ядре, тем более для некоторых есть врапперы (drupal_strlen, drupal_strtolower и drupal_strtoupper)

Аватар пользователя vitamin vitamin 19 апреля 2007 в 12:21

я запостил репорт на drupal.org, пока тишина..
боюсь, придётся самостоятельно патч писать - им-то что, им юникод не нужен

Аватар пользователя vitamin vitamin 19 апреля 2007 в 15:53

хм, продолжаем изыскания
basename нормально отрабатывает и ничего не отрезает в случае, если запускать с локалью ru_RU.UTF-8
короче, quick & dirty hack прилагаю

Аватар пользователя Ustas Ustas 20 апреля 2007 в 19:24

Локаль на сервере была выставлена в POSIX. Поправил на ru_RU.UTF-8 в соответствие с этим мануалом: http://ru.gentoo-wiki.com/HOWTO_ru_RU.utf8_Gentoo_way

$ locale
LANG=ru_RU.UTF-8
LC_CTYPE="ru_RU.UTF-8"
LC_NUMERIC="ru_RU.UTF-8"
LC_TIME="ru_RU.UTF-8"
LC_COLLATE="ru_RU.UTF-8"
LC_MONETARY="ru_RU.UTF-8"
LC_MESSAGES="ru_RU.UTF-8"
LC_PAPER="ru_RU.UTF-8"
LC_NAME="ru_RU.UTF-8"
LC_ADDRESS="ru_RU.UTF-8"
LC_TELEPHONE="ru_RU.UTF-8"
LC_MEASUREMENT="ru_RU.UTF-8"
LC_IDENTIFICATION="ru_RU.UTF-8"
LC_ALL=

Проблема осталась. Sad какие еще могут быть варианты?

Аватар пользователя vitamin vitamin 21 апреля 2007 в 1:09

общесистемную локаль нет смысла выставлять, если патч не помог - то и от этого мало толку
в системе, вообще, присутствует локаль ru_RU.UTF-8? команда date чего показывает?
возможно, надо пересобрать php - не знаю точно, где он локали берёт.. или просто положить их ему
попробуй ещё print_r вставить в file.inc в эту ф-ию после basename - может это не он обрезает, хотя вряд ли..

Аватар пользователя Ustas Ustas 23 апреля 2007 в 14:35

Локаль присутствует:

$ locale -a | grep ru
ru_RU
ru_RU.koi8r
ru_RU.utf8
ru_UA
ru_UA.utf8
$
$ date
Mon Apr 23 14:25:23 MSD 2007

Как посмотреть локаль, используемую php? в phpinfo нашел только:
Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7
Content-Type: text/html; charset=cp-1251

Не в этом ли проблема кроется?

Аватар пользователя vitamin vitamin 25 апреля 2007 в 12:34

пример, демонстрирующий, что я хочу сказать:

user@host:~$ cat test.php
#!/usr/bin/php5
<?php

$var = "раз два три\n";
setlocale(LC_CTYPE, 'C');
print basename($var);
setlocale(LC_CTYPE, 'ru_RU.UTF-8');
print basename($var);

user@host:~$ ./test.php
два три
раз два три
user@host:~$

Аватар пользователя Ustas Ustas 1 мая 2007 в 22:24

Пока не знаю. Завтра посмотрю - там много зависимостией тянулось, поэтой я в screen'е запустил. О результате сообщу. Smile

Аватар пользователя vitamin vitamin 2 мая 2007 в 11:08

хмм.. странно
у меня 5.2.0

user@host:~$ dpkg -l | grep php
ii libapache2-mod-php5 5.2.0-8+etch1 server-side, HTML-embedded scripting language
ii php5 5.2.0-8+etch1 server-side, HTML-embedded scripting language
ii php5-cli 5.2.0-8+etch1 command-line interpreter for the php5 script
ii php5-common 5.2.0-8+etch1 Common files for packages built from the php
ii php5-gd 5.2.0-8+etch1 GD module for php5
ii php5-mcrypt 5.2.0-8+etch1 MCrypt module for php5
ii php5-mysql 5.2.0-8+etch1 MySQL module for php5

Аватар пользователя qman qman 3 мая 2007 в 22:13

уважаемый USTAS не могли бы вы дать описание своих действий а также конфигурации php и OS в которой у вас функционирует сохранение файлов с символами кирилицы???
P.S. большое спасибо.

Аватар пользователя Ustas Ustas 4 мая 2007 в 0:56

Сервер работает под управлением Gentoo Linux.

$ uname -a
Linux bodhidharma 2.6.14-gentoo-r2 #1 SMP PREEMPT Wed Nov 23 10:23:02 Local time zone must be set-- i686 Intel(R) Xeon(TM) CPU 3.06GHz GenuineIntel GNU/Linux

Локаль: ru_RU.UTF-8 (настроена по этому мануалу: http://ru.gentoo-wiki.com/HOWTO_ru_RU.utf8_Gentoo_way - он подходит только для Gentoo)

Apache 2.0.58-r2

$ php -v
PHP 5.2.1-pl3-gentoo (cli) (built: May  2 2007 14:28:54)
Copyright (c) 1997-2007 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2007 Zend Technologies

Все собирал из стандартных портежей Gentoo. USE-Флаги:

net-www/apache          mpm-prefork -ldap threads
dev-lang/php -* cli apache2 ctype expat fastbuild ftp gd hash iconv memlimit mysql nls pcre pic pdo reflection session simplexml sockets spl ssl tokenizer truetype unicode xml xsl zlib
Аватар пользователя kiev1 kiev1 4 мая 2007 в 10:08

все равно надо как-то в друпале сделать транслитезацию при аплоаде файлов, потому что очень большая вероятность их потери при неудачном переносе или бекапе (некоторые фтп клиенты, или архиваторы).

Аватар пользователя dizzz dizzz 19 октября 2007 в 12:33

У меня тоже самое. Как решить эту проблему? ASAP
Версии:
Apache 1.3.37 (Unix)
PHP 5.2.3

Проблема и на этом сервере существует:
имя файла было:
а тут как_эта проблема работает.txt
стало:
тут как_эта проблема работает.txt

Аватар пользователя kiev1 kiev1 19 октября 2007 в 22:14

ну да, там где локаль utf-8 оно работает вроде нормально, но если юзер начнет копировать кривыми ftp клиентами - то они могут подменить имя файла - а в базе он останется под другим именем - и тогда он не будет находиться.

Аватар пользователя dizzz dizzz 24 октября 2007 в 9:27

Так что же тогда делать?
Надо как то решать. так жить нельзя на друпале.

В drupal 6.0beta2 проблема остается...

Аватар пользователя aka aka 23 февраля 2009 в 20:24

По поводу модуля transliteration - добавил обработку прикрепленных файлов в комментариях и некоторую косметику (это для пятой версии, авторам тоже отправил); но если локаль неправильно работает - я не уверен в результате, т.к. тут тоже используется функция basename.

/**
 * Helper function; retroactive transliteration of existing filenames.
 */

function transliteration_install_retroactive() {
  require_once(drupal_get_path('module', 'transliteration') .'/transliteration.inc');

  // Regexp operators differ between database manufacturers.
  switch ($GLOBALS['db_type']) {
    case 'mysql':
    case 'mysqli':
      $op = 'RLIKE';
      break;
    case 'pgsql':
      $op = '~*';
      break;
  }

  // Get all of the files that need to be converted, that is those that
  // contain characters other than alphanumerics, underscores, dots, or
  // hyphens.
  // aka: added routines for 'filename' field
  $result = db_query("SELECT fid, filename, filepath FROM {files} WHERE SUBSTRING_INDEX(filepath, '/', -1) $op '[^0-9A-Za-z_.-]'");
  $errors = array();

  while ($file = db_fetch_object($result)) {
    // Transliterate the file's name.
    $filepath = $file->filepath;
    // aka: new code
    $filename_new = transliteration_clean_filename(basename($filepath));
    $filepath_new = dirname($filepath) .'/'. $filename_new;
    // aka: old version
    //$filepath_new = dirname($filepath) .'/'. transliteration_clean_filename(basename($filepath));

    // Move the file to a new location but do a shortcut check first to avoid
    // unneccessary error messages. It's probably better to not mess with
    // records for missing files.
    $realpath = realpath($filepath);
    if ($realpath && file_exists($realpath) && file_move($filepath, $filepath_new, FILE_EXISTS_RENAME)) {
      // Get the file's new path; it may have changed.
      $filepath_new = $filepath;

      // Update the files table with the new path.
      db_query("UPDATE {files} SET filename = '%s', filepath = '%s' WHERE fid = %d", $filename_new, $filepath_new, $file->fid);
    }
    else {
      $errors[] = 'table files: ' . $file->filepath;
    }
  }

  // aka: repeat routines for comment_upload_files
  $result = db_query("SELECT fid, filename, filepath, description FROM {comment_upload_files} WHERE SUBSTRING_INDEX(filepath, '/', -1) $op '[^0-9A-Za-z_.-]'");
  $errors = array();

  while ($file = db_fetch_object($result)) {
    // Transliterate the file's name.
    $filepath = $file->filepath;
    // aka: new code
    $filename_new = transliteration_clean_filename(basename($filepath));
    $filepath_new = dirname($filepath) .'/'. $filename_new;
    // aka: translate description
    $description_new = ($file->filename == $file->description) ? $filename_new : $file->description;
    // aka: old version
    //$filepath_new = dirname($filepath) .'/'. transliteration_clean_filename(basename($filepath));

    // Move the file to a new location but do a shortcut check first to avoid
    // unneccessary error messages. It's probably better to not mess with
    // records for missing files.
    $realpath = realpath($filepath);
    if ($realpath && file_exists($realpath) && file_move($filepath, $filepath_new, FILE_EXISTS_RENAME)) {
      // Get the file's new path; it may have changed.
      $filepath_new = $filepath;

      // Update the files table with the new path.
      db_query("UPDATE {comment_upload_files} SET filename = '%s', filepath = '%s', description = '%s' WHERE fid = %d", $filename_new, $filepath_new, $description_new, $file->fid);
    }
    else {
      $errors[] = 'table comment_upload_files: ' . $file->filepath;
    }
  }

  return $errors;
}

Аватар пользователя aka aka 23 февраля 2009 в 20:30

После добавления отсутсвующей локали ru_RU.UTF-8 на ubuntu у меня basename не заработал. Точнее, он работал на тестах, а в друпале отказывался. Собака порылась в unique.inc > _unicode_check(). Там выставляется setlocale(LC_CTYPE, 'C');

Т.е. вот этот костыль в bootstrap.inc меня вылечил:

function _drupal_bootstrap($phase) {
...
    case DRUPAL_BOOTSTRAP_FULL:
      require_once './includes/common.inc';
      _drupal_bootstrap_full();
      setlocale(LC_CTYPE, 'ru_RU.UTF-8');
      break;
...
Аватар пользователя hapydoyzer@drupal.org hapydoyzer@drup... 22 июля 2009 в 9:18

Та же проблема. Решилась выставлением LC_ALL=ru_RU.UTF-8 для апача и комментированием setlocale в unicode.inc
Не понимаю, для чего там сбрасывается локаль на C?