# Содержимое command-every-second.sh #!/bin/bash command=$@ # Пробелы и косые в команде заменяются на нижние подчеркивания. no_spaces=`echo $command | sed -e 's/\s/_/g' -e 's|/|_|g'` # Имя файла для блокировки на время выполнения основной команды. lockfile=/tmp/$no_spaces.lock # Раз в секунду пытаемся поставить блокировку на команду и выполнить. for i in {1..60} do /usr/bin/flock -n $lockfile $command /bin/sleep 1 done rm $lockfile # Пример команды для крона. crontab -e * * * * * nice -n 1 ionice -c2 -n4 /var/www/www-root/data/command-every-second.sh /opt/php81/bin/php -f /var/www/www-root/data/www/example.ru/bitrix/php_interface/cron_events.php >/dev/null 2>&1 |
yum install brotli #Сборка динамических модулей для NGINX https://serverdiary.com/linux/how-to-install-and-configure-nginx-brotli/ nginx -V wget http://nginx.org/download/nginx-1.16.1.tar.gz tar zxvf nginx-1.16.1.tar.gz git clone https://github.com/google/ngx_brotli.git cd ngx_brotli/ git submodule update --init cd ../nginx-1.16.1 yum groupinstall 'Development Tools' -y yum install gcc-c++ flex bison yajl yajl-devel curl-devel curl GeoIP-devel doxygen zlib-devel yum install lmdb lmdb-devel libxml2 libxml2-devel ssdeep ssdeep-devel lua lua-devel yum install pcre-devel yum install openssl-devel ./configure --add-dynamic-module=../ngx_brotli ...сюда копируем опции сборки из вывода nginx -V... make modules cp objs/ngx_http_brotli_static_module.so /etc/nginx/modules cp objs/ngx_http_brotli_filter_module.so /etc/nginx/modules chmod 644 /etc/nginx/modules/ngx_http_brotli_static_module.so chmod 644 /etc/nginx/modules/ngx_http_brotli_filter_module.so |
vi /etc/nginx/nginx.conf ...... error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; load_module modules/ngx_http_brotli_filter_module.so; load_module modules/ngx_http_brotli_static_module.so; ...... server { ....... ....... brotli on; brotli_static on; # for static compression brotli_comp_level 6; # this setting can vary from 1-11 brotli_types text/xml image/svg+xml application/x-font-ttf image/vnd.microsoft.icon application/x-font-opentype application/json font/eot application/vnd.ms-fontobject application/javascript font/otf application/xml application/xhtml+xml text/javascript application/x-javascript text/plain application/x-font-truetype application/xml+rss image/x-icon font/opentype text/css image/x-win-bitmap; gzip on; ....... ....... } ....... nginx -t nginx -s reload |
yum install libwebp-tools vi ~/webp-convert.sh # Содержимое ~/webp-convert.sh #!/bin/bash # Скрипт для первоначальной конвертации картинок в конкретной директории. # converting JPEG images find $1 -type f -and \( -iname "*.jpg" -o -iname "*.jpeg" \) \ -exec bash -c ' webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0"); if [ ! -f "$webp_path" ]; then cwebp -quiet -q 90 "$0" -o "$webp_path"; jpg_size=$(wc -c "$0" | cut -d " " -f 1); webp_size=$(wc -c "$webp_path" | cut -d " " -f 1); if [ $jpg_size -lt $webp_size ]; then if [ -f "$webp_path" ]; then $(rm -f "$webp_path"); fi; fi; fi;' {} \; # converting PNG images find $1 -type f -and -iname "*.png" \ -exec bash -c ' webp_path=$(sed 's/\.[^.]*$/.webp/' <<< "$0"); if [ ! -f "$webp_path" ]; then cwebp -quiet -lossless "$0" -o "$webp_path"; png_size=$(wc -c "$0" | cut -d " " -f 1); webp_size=$(wc -c "$webp_path" | cut -d " " -f 1); if [ $png_size -lt $webp_size ]; then if [ -f "$webp_path" ]; then $(rm -f "$webp_path"); fi; fi; fi;' {} \; chmod a+x ~/webp-convert.sh /var/www/www-root/data/webp-convert.sh /var/www/www-root/data/www/example.ru/upload |
yum install epel-release yum install inotify-tools vi /etc/webp_convert.conf # Содержимое /etc/webp_convert.conf MONITOR=/var/www/www-root/data/www/example.ru/ # Пустой файл convert_webp.log создавался заранее. LOG_FILE=/var/www/www-root/data/www/example.ru/logs/convert_webp.log WEB_SERVER_USER=www-root:www-root # Изначально сервис конвертировал картинки в webp. # Позже было добавлено сжатие brotli, а название сервиса не поменялось. vi /etc/rc.d/init.d/webp_convert.sh # Содержимое /etc/rc.d/init.d/webp_convert.sh #!/bin/bash # webp_convert: Start/Stop convertation images to webp # # chkconfig: - 80 20 # description: use inotifywait for track and convert images to webp. # # processname: webp_convert . /etc/rc.d/init.d/functions . /etc/webp_convert.conf LOCK=/var/lock/subsys/webp_convert RETVAL=0 watching() { /usr/bin/inotifywait \ -q -m -r --format '%e %w%f' \ -s $LOG_FILE \ -e close_write -e moved_from -e moved_to -e delete $MONITOR \ | grep -i -E '\.(jpe?g|png|js|css)$' --line-buffered \ | while read operation path; do ts=$(date +"%C%y%m%d%H%M%S") echo "$ts :: $operation :: $path" >> $LOG_FILE; webp_path="$(sed 's/\.[^.]*$/.webp/' <<< "$path")"; brotli_path="${path}.br"; if [ $operation = "MOVED_FROM" ] || [ $operation = "DELETE" ]; then # if the file is moved or deleted if [ $(grep -i -E '\.(css|js)$' <<< "$path") ]; then if [ -f "$brotli_path" ]; then $(rm -f "$brotli_path"); fi; else if [ -f "$webp_path" ]; then $(rm -f "$webp_path"); fi; fi; elif [ $operation = "CLOSE_WRITE,CLOSE" ] || [ $operation = "MOVED_TO" ]; then # if new file is created if [ $(grep -i '\.png$' <<< "$path") ]; then $(cwebp -quiet -lossless "$path" -o "$webp_path"); $(chown "$WEB_SERVER_USER" "$webp_path"); png_size=$(wc -c "$path" | cut -d " " -f 1); webp_size=$(wc -c "$webp_path" | cut -d " " -f 1); if [ $png_size -lt $webp_size ]; then if [ -f "$webp_path" ]; then $(rm -f "$webp_path"); fi; fi; elif [ $(grep -i -E '\.(css|js)$' <<< "$path") ]; then $(brotli -q 11 -k -f "$path"); $(chown "$WEB_SERVER_USER" "$brotli_path"); else $(cwebp -quiet -q 90 "$path" -o "$webp_path"); $(chown "$WEB_SERVER_USER" "$webp_path"); jpg_size=$(wc -c "$path" | cut -d " " -f 1); webp_size=$(wc -c "$webp_path" | cut -d " " -f 1); if [ $jpg_size -lt $webp_size ]; then if [ -f "$webp_path" ]; then $(rm -f "$webp_path"); fi; fi; fi; fi; done; } start() { start_date=$(date +"%C%y%m%d%H%M%S"); echo "$start_date :: Setting up watches." >> $LOG_FILE; echo "Wathing dir: $MONITOR"; echo "Log to file: $LOG_FILE"; echo "Apache user: $WEB_SERVER_USER"; echo "Starting inotifywait for webp_convert..."; watching & status inotifywait RETVAL=$? [ $RETVAL -eq 0 ] && touch $LOCK return $RETVAL } stop() { echo -n $"Stopping inotifywait and webp_convert: " killproc inotifywait RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f $LOCK return $RETVAL } case "$1" in start) start ;; stop) stop ;; status) status inotifywait ;; restart) stop start ;; *) echo $"Usage: $0 {start|stop|status|restart}" exit 1 esac exit $? chmod a+x /etc/rc.d/init.d/webp_convert.sh # По умолчанию количество watches 8192, что не хватит для работы # Устанавливаем максимальное количество watches 524288, но помним, что один watch забирает 1Кб ОЗУ. # Для 524288 потребуется 512 мегабайт оперативной памяти. # https://askubuntu.com/questions/154255/how-can-i-tell-if-i-am-out-of-inotify-watches echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p /etc/rc.d/init.d/webp_convert start chkconfig --add webp_convert chkconfig webp_convert on |
# https://alexey.detr.us/en/posts/2018/2018-08-20-webp-nginx-with-fallback/ http { # ... map $http_accept $webp_ext { default ""; "~image\/webp" ".webp"; } map $uri $file_ext { default ""; "~(\.\w+)$" $1; } # ... } server { # ... location ~* "^(?<path>.+)\.(png|jpeg|jpg|gif)$" { try_files $path$webp_ext $path$file_ext =404; } # ... } # В файл /etc/nginx/mime.types добавить строку image/webp webp; nginx -t nginx -s reload |
yum install redis autoconf gcc make systemctl enable redis systemctl start redis |
wget https://github.com/igbinary/igbinary/archive/refs/tags/3.2.14.zip -O igbinary.zip unzip -o ./igbinary.zip cd igbinary-3.2.14/ /opt/php81/bin/phpize ./configure --with-php-config=/opt/php81/bin/php-config make && make install #Обязательное расширение echo 'extension=igbinary.so' > /opt/php81/etc/php.d/igbinary.ini wget https://github.com/phpredis/phpredis/archive/refs/tags/5.3.7.zip -O phpredis.zip unzip -o ./phpredis.zip cd phpredis-5.3.7/ /opt/php81/bin/phpize ./configure --with-php-config=/opt/php81/bin/php-config --enable-redis-igbinary make && make install echo 'extension=redis.so' > /opt/php81/etc/php.d/redis.ini #Рестарт сервера php, в данном случае apache systemctl restart httpd |
Available serializers php, igbinary |
# путь может отличаться на сервере # не запускать из под root, лучше под своим пользователем. # !! сайт битрикса добавил в путь пробел. #ln -s ../. ./www/local local |
if ($this->StartResultCache($arParams['CACHE_TIME'], [ ...$additionalCacheId ])) { // загрузка данных $this->IncludeComponentTemplate(); // кеширование $arResult и html-шаблона } // установка мета-данных страницы |
if ($this->StartResultCache($arParams['CACHE_TIME'], [ ...$additionalCacheId ])) { // загрузка данных $arResult для кеширования $this->EndResultCache(); // кеширование только $arResult } // обработка запроса пользователя $this->IncludeComponentTemplate(); |
IncludeComponentTemplate | EndResultCache | |
---|---|---|
Примеры компонентов | bitrix:catalog.section bitrix:catalog.element bitrix:news.list bitrix.news.detail | bitrix:catalog.smart.filter bitrix:menu bitrix:form.result.new (похожий подход) |
Назначение | HTML-шаблон одинаков для большой группы пользователей | Пользователь может сделать выбор, ввести данные |
Данные в кеше | HTML-шаблона, $arResult, $templateData | $arResult |
Выполнение result_modifier.php и template.php | Один раз | Каждый хит |
Параметры запроса $_REQUEST, $_GET, $_POST, $_SESSION, $USER в result_modifier.php и template.php | Передавать в параметрах вызова компонента $arParams с приведением значения по допустимому списку вариантов. Пример - вариант отображения списка или сортировка. | Без ограничений. Для вывода использовать функцию htmlspecialcharsbx() (уязвимость XSS). Рекомендуется использовать данные $arResult. |
Глобальные переменные (например, $APPLICATION) в result_modifier.php и template.php | Сохранить данные в $arResult или $templateData. Выполнить в component_epilog.php ^1. Например, установка заголовка страницы ^2. | Без ограничений |
Кеширование дополнительной выборки в result_modifier.php и template.php | Не требуется | Требуется |
<?php // ... header CIBlock::disableTagCache(2); CIBlock::disableTagCache(3); ?><?php $APPLICATION->IncludeComponent('bitrix:catalog', ...); ?><?php CIBlock::enableTagCache(2); CIBlock::enableTagCache(3); // ... footer |
//$_SERVER['DOCUMENT_ROOT'] = ....; use for cli register_shutdown_function(function() { print_r(error_get_last()); }); |
$reflection = new ReflectionClass(\Psr\Log\LoggerInterface::class); echo $reflection->getFileName(); |
{ "require": { ... }, "replace": { "psr/log": "*", "psr/http-message": "*" } } |
define('IP_LIMIT', '192.168.1.2'); define('INIT_TIMESTAMP', '123123123123123'); |
define('IP_LIMIT', '#IP_LIMIT_PLACEHOLDER#'); define('INIT_TIMESTAMP', '#INIT_TIMESTAMP#'); |
// init.php use Bitrix\Main\Loader; use Bitrix\Main; use Bitrix\Main\EventManager; use Bitrix\Main\Application; use Bitrix\Sale\Basket; use Bitrix\Sale\Order; use Bitrix\Sale\OrderBase; use Bitrix\Sale\Helpers; use Bitrix\Sale\PropertyValueCollection; $eventManager = EventManager::getInstance(); $request = Application::getInstance()->getContext()->getRequest(); $eventManager->addEventHandler('sale', /*\Bitrix\Sale\Notify::EVENT_ORDER_STATUS_SEND_EMAIL= */ 'OnOrderStatusSendEmail', static function ($orderId, &$eventName, &$fields, $statusId) use ($request) { $entity = Bitrix\Sale\Order::load($orderId); $separator = "<br/>"; $eventName = Bitrix\Sale\Notify::EVENT_DEFAULT_STATUS_CHANGED_ID . $statusId; $filter = array( "EVENT_NAME" => $eventName, 'ACTIVE' => 'Y', ); if ($entity instanceof OrderBase) { $filter['SITE_ID'] = $entity->getSiteId(); } elseif (defined('SITE_ID') && SITE_ID != '') { $filter['SITE_ID'] = SITE_ID; } $res = \CEventMessage::GetList('', '', $filter); if ($eventMessage = $res->Fetch()) { if ($eventMessage['BODY_TYPE'] == 'text') { $separator = "\n"; } } $basketList = ''; /** @var Basket $basket */ $basket = $entity->getBasket(); if ($basket) { $basketTextList = $basket->getListOfFormatText(); if (!empty($basketTextList)) { foreach ($basketTextList as $basketItemCode => $basketItemData) { $basketList .= $basketItemData . $separator; } } } $getUserEmail = static function (Order $order) { $userEmail = ""; if (empty($userEmail)) { /** @var PropertyValueCollection $propertyCollection */ if ($propertyCollection = $order->getPropertyCollection()) { if ($propUserEmail = $propertyCollection->getUserEmail()) { $userEmail = $propUserEmail->getValue(); } } } if (empty($userEmail)) { $userRes = Main\UserTable::getList(array( 'select' => array('ID', 'LOGIN', 'NAME', 'LAST_NAME', 'SECOND_NAME', 'EMAIL'), 'filter' => array('=ID' => $order->getUserId()), )); if ($userData = $userRes->fetch()) { $userEmail = $userData['EMAIL']; } } return $userEmail; }; $getUserName = static function (Order $order) { $userName = ""; if (empty($userName)) { /** @var PropertyValueCollection $propertyCollection */ if ($propertyCollection = $order->getPropertyCollection()) { if ($propPayerName = $propertyCollection->getPayerName()) { $userName = $propPayerName->getValue(); } } } if (empty($userName)) { $userRes = Main\UserTable::getList(array( 'select' => array('ID', 'LOGIN', 'NAME', 'LAST_NAME', 'SECOND_NAME', 'EMAIL'), 'filter' => array('=ID' => $order->getUserId()), )); if ($userData = $userRes->fetch()) { $userData['PAYER_NAME'] = \CUser::FormatName( \CSite::GetNameFormat(null, $order->getSiteId()), $userData, true ); $userName = $userData['PAYER_NAME']; } } return $userName; }; $fields = array_merge($fields, array( "ORDER_ID" => $entity->getField("ACCOUNT_NUMBER"), "ORDER_REAL_ID" => $entity->getField("ID"), "ORDER_ACCOUNT_NUMBER_ENCODE" => urlencode(urlencode($entity->getField("ACCOUNT_NUMBER"))), "ORDER_DATE" => $entity->getDateInsert()->toString(), "ORDER_USER" => $getUserName($entity), "PRICE" => SaleFormatCurrency($entity->getPrice(), $entity->getCurrency()), "BCC" => Main\Config\Option::get("sale", "order_email", "order@" . $request->getServer()->getServerName()), "EMAIL" => $getUserEmail($entity), "ORDER_LIST" => $basketList, "SALE_EMAIL" => Main\Config\Option::get("sale", "order_email", "order@" . $request->getServer()->getServerName()), "DELIVERY_PRICE" => $entity->getDeliveryPrice(), "ORDER_PUBLIC_URL" => Helpers\Order::isAllowGuestView($entity) ? Helpers\Order::getPublicLink($entity) : "" )); return true; } ); |