Обновление курса валют в Битрикс
Для Битрикса есть популярное решение для обновление курса валют - 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 в зависимости от неё.
Решение, конечно, не самое быстрое. Но для тестирования на небольшом проекте подходит как нельзя лучше.



