Jump to content

Локаль при импорте - невозврат при проверке


Recommended Posts

В админке на странице  импорта в ImportAdmin.php  проверяется возможность установки локали таким кодом

		// Проверяем локаль
		$old_locale = setlocale(LC_ALL, 0);
		setlocale(LC_ALL, $this->locale);
		if(setlocale(LC_ALL, 0) != $this->locale)
		{
			$this->design->assign('message_error', 'locale_error');
			$this->design->assign('locale', $this->locale);			
		}
		setlocale(LC_ALL, $old_locale);

При этом значение $old_locale есть строка типа

LC_CTYPE=en_US.UTF-8;LC_NUMERIC=C;LC_TIME=en_US.UTF-8;LC_COLLATE=en_US.UTF-8;LC_MONETARY=en_US.UTF-8;LC_MESSAGES=en_US.UTF-8;LC_PAPER=en_US.UTF-8;LC_NAME=en_US.UTF-8;LC_ADDRESS=en_US.UTF-8;LC_TELEPHONE=en_US.UTF-8;LC_MEASUREMENT=en_US.UTF-8;LC_IDENTIFICATION=en_US.UTF-8

Поэтому оператор в  последней строке заранее обречен на неудачу, так как в такой ситуации 

передаваемая переменная никак не может содержать верное имя локали.

Последний оператор тем самым никогда не восстанавливает исходную локаль, как задумано и как быть должно.

А иногда, при соответствующих настройках, и дает предупреждения, о которых  сообщалось в темах

http://forum.simplacms.ru/topic/8123-%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0-%D0%B2-%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8/

http://forum.simplacms.ru/topic/1231-%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0-specified-locale-name/

 

У меня локально работает правильно, если меняю код на

		// Проверяем локаль
		$old_locale = setlocale(LC_ALL, 0);
		setlocale(LC_ALL, $this->locale);
		if(setlocale(LC_ALL, 0) != $this->locale)
		{
			$this->design->assign('message_error', 'locale_error');
			$this->design->assign('locale', $this->locale);			
		}
		$old_locale=preg_replace("/.*=([^;]+).*/", '\\1', $old_locale) ;
		setlocale(LC_ALL, $old_locale);

Link to post
Share on other sites

По сути Ваш способ тоже не правильный...

Поскольку даже на вашем примере он установит LC_ALL в последнее значение перед =. То есть это будет en_US.UTF-8.

 

Я думаю так лучше будет:

 



        $old_locale = explode(';', setlocale(LC_ALL, 0));
        $new_locale = setlocale(LC_ALL, $this->locale);
        if(!$new_locale || $new_locale != $this->locale)
        {
            $this->design->assign('message_error', 'locale_error');
            $this->design->assign('locale', $this->locale);            
        }else{
            foreach($old_locale as $locale_str){
                if(strpos($locale_str, '=') !== false) {
                    list ($category, $locale) = explode('=', $locale_str);
                }else{
                    $category = 'LC_ALL';
                    $locale = $locale_str;
                }
                setlocale(constant($category), $locale);
            }
        }



 
 
Link to post
Share on other sites

Я думаю так лучше будет:

        $old_locale = explode(';', setlocale(LC_ALL, 0));
        $new_locale = setlocale(LC_ALL, $this->locale);
        if(!$new_locale || $new_locale != $this->locale)
        {
            $this->design->assign('message_error', 'locale_error');
            $this->design->assign('locale', $this->locale);            
        }else{
            foreach($old_locale as $locale_str){
                if(strpos($locale_str, '=') !== false) {
                    list ($category, $locale) = explode('=', $locale_str);
                }else{
                    $category = 'LC_ALL';
                    $locale = $locale_str;
                }
                setlocale(constant($category), $locale);
            }
        }



 
 

 

 

 

Судя по "Я думаю", Вы не проверили, прежде чем постить...

 

А если бы затратили пару минут для проверки, то убедились бы, что не только так лучше не будет, а так просто никуда не годится.

$new_locale != $this->locale  - всегда true, так как сравнивает строку и массив. Следовательно, Ваш код ВСЕГДА будет выводить ошибку. А часть else с циклом просто  не будет выполняться НИКОГДА. ТО есть даже если у пользователя все нормально с локалью, Ваш метод ВСЕГДА будет гарантированно пугать его красной надписью! И уж точно не будет никогда возвращать исходную локаль... 

 

А вот идея Ваша с перебором всех значений, несомненно, очень даже хороша.

Link to post
Share on other sites

Судя по "Я думаю", Вы не проверили, прежде чем постить...

 

А если бы затратили пару минут для проверки, то убедились бы, что не только так лучше не будет, а так просто никуда не годится.

 

Вот тут Вы ошиблись. Код - рабочий!

$new_locale != $this->locale - всегда true, так как сравнивает строку и массив. Следовательно, Ваш код ВСЕГДА будет выводить ошибку. А часть else с циклом просто не будет выполняться НИКОГДА. ТО есть даже если у пользователя все нормально с локалью, Ваш метод ВСЕГДА будет гарантированно пугать его красной надписью! И уж точно не будет никогда возвращать исходную локаль...

Где Вы тут массив увидели? Почитайте прежде описание функции http://php.net/manual/ru/function.setlocale.php

setlocale - возвращает имя локали (если она установилась) и false в случае ошибки. Соответственно и проверка

 if(!$new_locale || $new_locale != $this->locale)

если $new_locale отрицательный или локаль не равна требуемой то выводим ошибку. Если все ок то восстанавливаем прежнюю...

Link to post
Share on other sites

Да, с массивом я промахнулся, признаю свою ошибку.

 

Но я бы не спешил с категоричными утверждения типа "Код - рабочий!"...

 

Запускаю Ваш код, предварительно установив private $locale = 'rus';

Получаю для  $new_locale  строку  'Russian_Russia.1251'. 

Локаль прекрасно работает, а Ваш код дает в результате красное предупреждение...

 


 

Link to post
Share on other sites




		$old_locale = explode(';', setlocale(LC_ALL, 0));
		$new_locale = setlocale(LC_ALL, $this->locale);
		if($new_locale==false){
			$this->design->assign('message_error', 'locale_error');
			$this->design->assign('locale', $this->locale);			
		}else{
			foreach($old_locale as $locale_str){
				if(strpos($locale_str, '=') !== false) {
					list ($category, $locale) = explode('=', $locale_str);
				}else{
					$category = 'LC_ALL';
					$locale   = $locale_str;
				}
				setlocale(constant($category), $locale);
			}
		}

 

Думаю можно убрать 2-ю проверку. По сути если вернет не false то можно считать что локаль та что нужно...

Link to post
Share on other sites

Убрать не "можно", а НУЖНО!

Вы ведь сами написали  "возвращает имя локали (если она установилась) и false в случае ошибки", а проверяете совсем другое!

 

А еще в цикле могут устанавливаться как отдельные категории, так и LC_ALL.  Возможны конфликты, когда несколько раз переустанавливается одна и та же категория - один раз сама по себе, и несколько раз  LC_ALL с непонятно какими значениями...

Link to post
Share on other sites

Ну на счет "нужно" - не совсем уверен. Поскольку в разных системах бывают разные локали.
Хотя с точки зрения универсальности данная проверка (на false) лучше всего подходит. 
 
 

А еще в цикле могут устанавливаться как отдельные категории, так и LC_ALL. Возможны конфликты, когда несколько раз переустанавливается одна и та же категория - один раз сама по себе, и несколько раз LC_ALL с непонятно какими значениями...

 
Нет LC_ALL не передастся туда. Результатом setlocale(LC_ALL, 0) может быть либо строка вида en_US.UTF-8 (если установлена LC_ALL) либо набор локалей в виде того что вы показали в 1 посте.

Правда на всех системах я этого не проверял. Но для большей надежности можно еще поставить break при установке LC_ALL.

Или можно сделать массив с разрешенными группами. И при переборе проверять можно ли ее ставить...

Но я думаю это лишнее... 

Лучше всего поставить проверку на присутствие константы перед установкой setlocale(constant($category), $locale); и на этом все. 

Link to post
Share on other sites

Ну на счет "нужно" - не совсем уверен. Поскольку в разных системах бывают разные локали.

Хотя с точки зрения универсальности данная проверка (на false) лучше всего подходит.

Странная аргументация. А с какой точки зрения она подходит НЕ ЛУЧШЕ ВСЕГО?

 

 


		$old_locale = explode(';', setlocale(LC_ALL, 0));
		$new_locale = setlocale(LC_ALL, $this->locale);
		if($new_locale!==false){
			$this->design->assign('message_error', 'locale_error');
			$this->design->assign('locale', $this->locale);			
		}else{
			foreach($old_locale as $locale_str){
				if(strpos($locale_str, '=') !== false) {
					list ($category, $locale) = explode('=', $locale_str);
				}else{
					$category = 'LC_ALL';
					$locale   = $locale_str;
				}
				setlocale(constant($category), $locale);
			}
		}

А в этом варианте условный оператор

if($new_locale!==false)

работает не правильно, а как раз с точностью до наоборот...

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...