Показаны сообщения с ярлыком php. Показать все сообщения
Показаны сообщения с ярлыком php. Показать все сообщения

среда, 2 ноября 2011 г.

PHP определение языка пользователя

Если вы делаете сайт на нескольких языках, то вы обязательно столкнётесь с задачей:
Как определить язык пользователя на стороне сервера (в PHP)?
Один из часто используемых вариантов - использовать Geo IP и дальше уже по стране определять язык.
Но на мой взгляд более правильный способ - это использовать заголовки, которые для этого предназначены, а именно Accept-Language, в котором перечислены с указанием приоритета предпочитаемые языки.
Ниже представлена функция на PHP, которая парсит заголовок Accept-Language и находит наиболее подходящий язык для пользователя из тех, что переданы массивом (параметр $languages).
При этом, если ни одного языка не нашлось в заголовке, то будет использоваться первый из массива $languages.
function getAcceptLanguage($languages)
{
    if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) || 
        !$_SERVER['HTTP_ACCEPT_LANGUAGE']) {
        return $languages[0];
    }  
   
    /*
     * Разбираем заголовок Accept-Language
     *
     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
     * 14.4 Accept-Language
     * Accept-Language = "Accept-Language" ":"
     *                   1#( language-range [ ";" "q" "=" qvalue ] )
     * language-range  = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
     *
     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.9
     * 3.9 Quality Values
     * qvalue         = ( "0" [ "." 0*3DIGIT ] )
     *                | ( "1" [ "." 0*3("0") ] )
     */
    preg_match_all("/([a-z]{1,8})(?:-([a-z]{1,8}))?(?:\s*;\s*q\s*=\s*(1|1\.0{0,3}|0|0\.[0-9]{0,3}))?\s*(?:,|$)/i",
                   $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);

    // Результат по умолчанию - первый из доступных языков
    $result = $languages[0];
    $max_q = 0;
   
    for ($i = 0; $i < count($matches); $i++) {
        // Выделяем очередной язык
        $lang = $matches[1][$i];
        if (!empty($matches[2][$i])) {
            // Переводим ru-RU в ru_RU (т.к. локаль ru_RU)
            $lang .= '_'.$matches[2][$i]; 
        }
        // Определяем приоритет
        if (!empty($matches[3][$i])) {
            $q = (float)$matches[3][$i];   
        } else {
            $q = 1.0;
        }  
        // Проверяем есть ли проверяемый язык в массиве доступных
        if (in_array($lang, $languages) && ($q > $max_q)) {
            $result = $lang;
            $max_q = $q;
        }
        // Если язык только из первой части (например, просто ru, а не ru-RU) и более приоритетный язык еще не найден, 
        // то пробуем найти в массиве доступых языков тот, который начинается так же   
        elseif (empty($matches[2][$i]) && ($q * 0.8 > $max_q)) {
            $n = strlen($lang);
            foreach ($languages as $l) {
                if (!strncmp($l, $lang, $n)) {
                    $result = $l;
                    // Поскольку не точное совпадение, то уменьшаем q на 20%
                    $max_q = $q * 0.8;
                    break;
                }
            }
        }
    }
    return $result;
}
Пример использования:
$locale = getAcceptLanguage(array('en_US', 'ru_RU', 'de_DE'));

суббота, 9 июля 2011 г.

Функции json_encode() и json_decode() на PHP

Я занимаюсь разработкой разработкой веб-приложений на PHP, которые пользователи могут скачать и поставить у себя на хостинге. А поскольку на виртуальных хостингах в России PHP обновляется очень медленно, то нет возможности пользоваться многими полезными расширениями PHP, т.к. их может не быть.
Один из таких примеров - это функции для работы с JSON: json_encode() и json_decode(). Подробнее об этих функциях можно прочитать в документации http://www.php.net/manual/ru/ref.json.php
Проблема в том, что JSON extension входит в состав PHP по умолчанию только, начиная с версии 5.2.0
В реальности на сегодняшний день до сих пор на многих хостингах в рунете установлен PHP 5.1.6

Довольно сложно представить современное веб-приложение/сайт без использования ajax, и функция json_encode() становится просто необходимой для формирования JSON.
И если у вас нет json extension вы получите одну из ошибок:
Fatal error: Call to undefined function json_encode() in ...
Fatal error: Call to undefined function json_decode() in ...
Что же делать?
Нужно реализовать эти функции на PHP!
Можно, конечно, использовать уже готовое, например: http://pear.php.net/package/Services_JSON/
Но! Я встретил уже два сервера, где Service_JSON работал некорректно с русским языком. Тогда не было времени разбираться с причинами и было решено написать свою функцию json_encode() собрав воедино все полезное из комментариев на php.net.

Чтобы не приходилось думать о наличии json в PHP лучше всего делать так:
if (!function_exists('json_encode')) {
      function json_encode($value)
      {
           // Тут реализация функции json_encode на PHP
      }
}

if (!function_exists('json_decode')) {
      function json_encode($json, $assoc = false)
      {
           // Тут реализация функции json_encode на PHP
      }
}
После этого вы можете спокойно везде использовать функции json_encode() и json_decode() вне зависимости от версии PHP и наличия json extension.

Все исходники выложены на гитхабе: https://github.com/alexmuz/php-json
Функции реализованы как по отдельности в процедурном стиле (файлы json_encode.php и json_decode.php - можно подключать только то, что нужно), так и отдельным статическим классом phpJson.

Простейший вариант использования:
require_once("phpJson.class.php");
После этого функции json_encode и json_decode станут доступны.