Обновление курса валют в Битрикс
Для Битрикса есть популярное решение для обновление курса валют - https://marketplace.1c-bitrix.ru/solutions/asd.currencyrate/
Однако, решение не работает, если базовая валюта не рубли.
В моём случае, когда это фунты(GBP), решаю это вот таким куском гавнокода:
<?php include __DIR__ . '/bitrix.php'; $contents = file_get_contents('http://www.cbr.ru/scripts/XML_daily.asp'); $neededCurrency = 'GBP'; // Глупая проверка на то, что нам вернули что-то нормальное if (stripos($contents,$neededCurrency) > 0) { $xml = simplexml_load_string($contents); $date = $xml->attributes()->Date; CModule::IncludeModule('currency'); $format = "DD.MM.YYYY"; // получим формат текущего сайта $new_format = CSite::GetDateFormat("SHORT"); // переведем дату из одного формата в другой $new_date = $DB->FormatDate($date, $format, $new_format); // в результате получим дату в новом формате echo "Date $date - $new_date\n"; $arFilter = [ "CURRENCY" => "RUB", 'DATE_RATE' => $new_date, ]; $by = "date"; $order = "desc"; $row = CCurrencyRates::GetList($by, $order, $arFilter)->Fetch(); if ($row === false) { foreach ($xml->Valute as $valute) { if (((string)$valute->CharCode) === $neededCurrency) { $value = (float)str_replace(',', '.', ((string)$valute->Value) ?? 0); if ($value > 0) { $value = number_format(1 / $value * 1.05, 4, '.', ''); $arFields = [ "RATE" => $value, "RATE_CNT" => 1, "CURRENCY" => "RUB", "DATE_RATE" => $new_date, ]; if (!CCurrencyRates::Add($arFields)) { echo "Ошибка добавления курса $date - $value\n"; echo $APPLICATION->GetException() . "\n\n"; } else { echo "Обновили курс $date - $value\n"; } return; } } } } else { echo "Курс на $date уже есть\n"; } }
Достигаем цели статистики просто в AjaxForm MODX
Чтобы засчитывались цели Яндекс.Метрики или Google Analytics в MODX при использовании FormIt и AjaxForm достаточно трёх простых шагов:
Шаг 1. Заводим цели как Javascript событие:
Шаг 2. В вёрстке каждой форме добавляем data-атрибут data-goal="название вашей цели", например
<form data-goal="zakaz">
Шаг 3. Добавляем простой обработчик:
$(document).on('af_complete', function(event, response) { var form = response.form; var goal = form.data('goal') || null; if (goal) { try { window.yaCounter48925430.reachGoal(goal); } catch (e) {} } });
try-catch нужен для того, чтобы если вдруг у нас не прогрузилась метрика(привет, РКН) - у нас ничего не сломалось.
Установка Zimbra на Ubuntu 16.04 + StartSSL
Примерный список must-have действий для успешной установки Zimbra на Ubuntu 16.04. Не для безумного копипаста.
Приведём сервер в порядок
1. В /etc/apt/sources.list
включаем все необходимые репозитории.
2. Установим временную зону, локаль, включим обновления безопасности и поставим пакеты первой необходимости(от рута):
locale-gen en_US.UTF-8 ru_RU.UTF-8
apt-get install locales man dialog htop silversearcher-ag bzip2 pigz pbzip2 mc grc pydf bash-completion vim-nox zsh tmux ncdu unattended-upgrades nano screen
dpkg-reconfigure unattended-upgrades
dpkg-reconfigure tzdata
Установка libssh2-php в Mac OS X
Для установки расширения ssh2 для php под маком, можно воспользоваться командой:
sudo
pecl
install
channel:
//pecl
.php.net
/ssh2-0
.12
Однако, как правило, она ругается нам следующим:
configure: error: The required libssh2 library was not found. You can obtain that package from http://sourceforge.net/projects/libssh2/
ERROR: `/private/tmp/pear/temp/ssh2/configure --with-ssh2' failed
Значит нам надо поставить libssh2 из портов MacPorts
sudo
port
install
libssh2
Затем повторяем pecl install..., но когда нас спросят про libssh2 prefix, надо ввести /opt/local.
Всё. Перезапускаем apache и всё работает!
NetPlant — простая хостинговая панель
В силу необходимости, решил написать свою хостинговую панель для shared хостинга.
Почему свою? Всё просто.
Ни одна из тех панелей, что я нашел, не умеет:
- Работать с несколькими серверами из одной панели
- Давать возможность создавать сайты со своими конфигами
- Работать в конфигурации nginx+php-fpm, nginx+apache одновременно
Результат моего 2.5 дневного творения уже можно пощупать на github: https://github.com/DevGroup-ru/NetPlant.
Пока что умеет только создавать сайты на серверах из конфигов, но лично мне это уже хорошо упрощает жизнь.
Основано на:
- Yii framework 1.x
- Предыдущих наработках для движка CMS
- Интерфейс - twitter bootstrap (via YiiBooster)
По поводу лицензии пока не задумывался - сначала надо довести до более-менее стабильной версии.
Обход ограничения max_input_vars в PHP без php.ini
Сегодня столкнулся с ограничением на количество входящих из формы в скрипт переменных в PHP.
Отвечает за это параметр max_input_vars, который по-умолчанию равен 1000.
Поскольку я разрабатываю CMS, то было бы не правильным в .htaccess менять это значение. Поэтому я решил обойти это.
С данной проблемой у меня сталкивается админка. А поскольку она не работает и не должна работать без JS, то я использовал такой JavaScript:
$("#editSaveButton").on('click', function(){ form = $("<form method=\"POST\"></form>") .attr('action', $('#editForm').attr('action')) .append( $("<input type=\"hidden\" name=\"serializedData\">").val( $("#editForm").serialize() ) ) .append( $("#editForm input[name=token]").clone() //@todo token name can be different ) .appendTo($("body")) .submit(); return false; }); |
И вот такой код в PHP, чтобы заменить $_POST нужными данными:
private function prepareSerializedData() { if (isset($_POST['serializedData'])) { $_POST = CMap::mergeArray($_POST, $this->parse_str($_POST['serializedData'])); unset($_POST['serializedData']); } } private function parse_str($string) { $parts = explode("&", $string); $result = array(); foreach ($parts as $part) { $parsed = array(); parse_str($part, $parsed); $result = array_merge_recursive($result, $parsed); } return $result; } |
Яндекс сменил принцип расчета тИЦ?
Все мы знаем, что ТИЦ расчитывается как бы для сайта целиком, а не для страницы, как это делается в алгоритме PageRank.
Собственно в хелпе Яндекс так и пишет:
Наш тематический индекс цитирования (тИЦ) определяет «авторитетность» интернет-ресурсов с учетом качественной характеристики ссылок на них с других сайтов.
Казалось бы, всё предельно понятно. Интернет-ресурс это сайт.
Но не тут то было. Сегодня внезапно случайно обнаружил, что Яндекс пытается мутить и определять на сайте разделы(ссылка "Все подразделы" в яке). Пока что, видимо, у него это не очень то получается:
Это собственно всё. Всего-то две категории. Что самое интересное - у этих категорий свой тиц. И всё бы хорошо, для ленты вроде бы это более-менее логично.
Но вот, что творится, например, с facebook:
Странно? Более чем. Видимо это какой то глюк в алгоритмах.
Less.js и кеширование
Есть такой замечательный скрипт less.js, который позволяет компилировать LessCSS прямо в браузере. Скрипт поддерживает кеширование скомпонованного less средствами HTML5 Local storage.
Но есть одна неприятная особенность - подключенные через @include файлы не проверяются на изменения, что в свою очередь ведет к некоторым неудобствам при разработке.
Для очистки кеша я нашел на просторах интернета такой скрипт:
function destroyLessCache(pathToCss) { // e.g. '/css/' or '/stylesheets/' var host = window.location.host; var protocol = window.location.protocol; var keyPrefix = protocol + '//' + host + pathToCss; for (var key in window.localStorage) { if (key.indexOf(keyPrefix) === 0) { delete window.localStorage[key]; } } } |
Собственно используя destroyLessCache("/bootstrap/less");
вместе с загрузкой страницы, мы сбрасываем весь кеш less.js.
В качестве параметра функция принимает путь к less файлам, относительно хоста.
Локаль Ubuntu 12.04
Устанавливаем кошерную русскую локаль в Ubuntu из консоли:
locale-gen ru_RU.UTF-8 |
В /etc/default/locale пишем:
LANG="ru_RU.UTF-8" LANGUAGE="ru_RU:en" LC_NUMERIC="ru_RU.UTF-8" LC_TIME="ru_RU.UTF-8" LC_MONETARY="ru_RU.UTF-8" LC_PAPER="ru_RU.UTF-8" LC_IDENTIFICATION="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" |
logout и вуаля! Русский язык на месте.
Настройка nginx для A/B тестирования с помощью lua
Возникла жесткая необходимость настройки сплит-тестирования (A/B тестирование) сайта.
Поскольку в моем случае разные версии сайта были даже на разных движках, то самым логичным было менять document root в зависимости от куки пользователя.
Но вот незадача - эту куку надо ещё как то установить. Делать для этого отдельный бекенд, как советует mixlr мне не хотелось.
Как установить рандомную куку средствами самого nginx, я так и не понял.
Решено было использовать сборку nginx - OpenResty, поскольку в ней уже встроен модуль HttpLuaModule.
Да, я знаю, что это извращение, но писать модуль для nginx на C не было никакого желания.
В результате получился вот такой вот скрипт на lua, который нужно вставить в нужное место в своём конфиге:
set $target ''; access_by_lua ' local abtest = 0 local abtestMax = 1 local userAgent = ngx.req.get_headers()["User-Agent"] local cookie = ngx.var.cookie_abtest if ngx.re.match(userAgent, "(yandex|google|MSIE|bot)", "i") then cookie = 0 end if cookie == nil then math.randomseed( os.time() ) abtest = math.random(0, abtestMax) ngx.header["Set-Cookie"] = {"abtest=" .. abtest .. "; path=/", "abReason=nil"} else if tonumber(cookie) >= 0 and tonumber(cookie) <= abtestMax then abtest = cookie else abtest = 0 ngx.header["Set-Cookie"] = {"abtest=" .. abtest .. "; path=/", "abReason=badRange"} end end ngx.var.target = abtest '; root /var/www/meta$target; |
Логика проста - скрипт смотрит, есть ли кука.
- если user-agent содержит yandex, google, MSIE или bot -- кука с тестом 0 -- это для того, чтобы поисковики и IE видели старую версию сайта(№0). Поисковики тем самым не обвинят нас в клоакинге.
- если кука nil, т.е. её нет - выбираем случайную куку от 0 до abtestMax и передаём её в браузер. Таким образом вероятность выпадения при abtestMax=1 - 50%/50%
- если кука не в нашем диапозое [0;abtestMax] - кука будет 0(версия сайта №0)
- если в диапозоне, то всё ок
Далее устанавливается переменная $target равная номеру теста и ниже уже ставится documentRoot в зависимости от неё.
Решение, конечно, не самое быстрое. Но для тестирования на небольшом проекте подходит как нельзя лучше.