Блог

Починить все базы данных и таблицы MySQL

В терминале (не в консоли mysql) выполните следующую команду:

$ mysqlcheck -u root -p -A --auto-repair

Пример ответа:

...
website.b_adv_banner_2_country                     OK
website.b_adv_banner_2_day                         OK
website.b_adv_banner_2_group                       OK
website.b_adv_banner_2_page                        OK
website.b_adv_banner_2_site                        OK
website.b_adv_banner_2_stat_adv                    OK
website.b_adv_banner_2_weekday                     OK
...

Для поиска: repair database, repair table.

bash bitrix mysql sql

Базовая авторизация (basic auth) на nginx

Для начала надо установить apache2-utils

$ sudo apt install -y apache2-utils

После этого можно создать файл с учетными данными для входа, например

$ htpasswd -c /etc/nginx/.htpasswd user

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

Если файл уже создан, то для последующих пользователей уберите флаг -c:

$ htpasswd /etc/nginx/.htpasswd user2

Теперь внесите в конфигурацию nginx (например, /etc/nginx/sites-enabled/default) изменения, чтобы он спрашивал доступ.

Вот эти строки:

        auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;

Чтобы получилось, например:

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    root /usr/share/nginx/html;
    index index.html index.htm;

    server_name localhost;

    location / {
        try_files $uri $uri/ =404;
        auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }
}
bash devops nginx

Как узнать кодировку файла в Ubuntu?

Можно с помощью программы enca.

Устанавливаем:

$ sudo apt install -y enca

Запускаем:

$ enca myfile.txt

Видим результат, например, такой:

Universal transformation format 8 bits; UTF-8
  Doubly-encoded to UTF-8 from ISO-8859-5
bash

ERROR: could not access file “$libdir/postgis-2.4”: No such file or directory

Встретил такую ошибку. Использовал образ https://hub.docker.com/r/mdillon/postgis

Выяснилось, что образ обновил postgis до версии 2.5 (2.4 был полностью убран).

Чтобы все починить, просто выполните команду внутри контейнера /usr/local/bin/update-postgis.sh - это обновит postgis с версии 2.4 до версии 2.5 внутри вашего контейнера. Возможно, придется перезагрузить его, но у меня все заработало.

devops docker postgresql

Защита от ботов Distil Networks

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

Называется она - Distil Networks

Если использовать вместе с рекапчей от гугла, то на сайт вообще практически невозможно пробиться автоматизированными путями. Да, селениум тоже заблокирует. Да, может не с первого раза, но на 2-3 заблокирует.

Кому очень надо, вот здесь ребята с реддит уверяют, что могут обойти защиту https://www.reddit.com/r/webdev/comments/5q1ypx/what_is_your_approach_on_scraping_distil_networks/

сайты

Простейший работающий пример docker + chromedriver + selenium + python на сервере

Скачать пример файлом - example_chromedriver.zip

Структура папок и файлов:

wrapper/Dockerfile
wrapper/requirements.txt
wrapper/main.py
docker-compose-yml

Содержимое docker-compose.yml:

version: "2"

services:

  web:
    build: wrapper
    restart: always
    command: python main.py

Содержимое wrapper/Dockerfile:

FROM python:3.6

ENV PYTHONUNBUFFERED 1

# install google chrome
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'
RUN apt-get -y update
RUN apt-get install -y google-chrome-stable

# install chromedriver
RUN apt-get install -yqq unzip
RUN wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE`/chromedriver_linux64.zip
RUN unzip /tmp/chromedriver.zip chromedriver -d /usr/local/bin/

# set display port to avoid crash
ENV DISPLAY=:99

RUN mkdir /code
WORKDIR /code

COPY . /code/

RUN pip install -r requirements.txt

Содержимое wrapper/requirements.txt:

selenium==3.8.0

Содержимое wrapper/main.py:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time


chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.implicitly_wait(10)

while True:
    print('start')
    driver.get("http://www.python.org")
    assert "Python" in driver.title
    elem = driver.find_element_by_name("q")
    print('elem', elem)
    elem.clear()
    elem.send_keys("pycon")
    elem.send_keys(Keys.RETURN)
    assert "No results found." not in driver.page_source
    print('all ok')
    time.sleep(3)

driver.close()

Источник: https://github.com/joyzoursky/docker-python-chromedriver

python selenium

Табличный вид заказа в письме в битриксе версии 18

Вот таким образом можно сделать табличный вид заказа с торговыми предложениями и самими товарами в письме. Для вывода таблицы в шаблоне нового заказа необходимо использовать переменную #ORDER_TABLE_ITEMS#. Картинки тоже прилагаются.

Файл init.php:

<?
AddEventHandler("sale", "OnOrderNewSendEmail", "ModifyOrderSaleMails");

function ModifyOrderSaleMails($orderID, &$eventName, &$arFields) {
    if(CModule::IncludeModule("sale") && CModule::IncludeModule("iblock")) {
        $strOrderList = "";
        $dbBasketItems = CSaleBasket::GetList(
            array("NAME" => "ASC"),
            array("ORDER_ID" => $orderID),
            false,
            false,
            array("PRODUCT_ID", "ID", "NAME", "QUANTITY", "PRICE", "CURRENCY")
        );
        $strOrderList = "
                <style>
                    table.example {
                        border-collapse: collapse;
                        width: 585px;
                    }
                    table.example td {
                        border:1px solid black;
                    }
                    table.example td.num {
                        width: 30px;
                        text-align: center;
                    }
                </style>
                <table class=\"example\">
                    <tr>
                        <td class=\"num\" align=\"center\">№</td>
                        <td align=\"center\">Фото товара</td>
                        <td align=\"center\">Наименование</td>
                        <td align=\"center\">Количество</td>
                        <td align=\"center\">Цена, руб.</td>
                        <td align=\"center\">Cумма, руб.</td>
                    </tr>";
        $i = 0;
        while ($arProps = $dbBasketItems->Fetch()) {
            $i += 1;
            // image
            $offer = CIBlockElement::GetById(IntVal($arProps["PRODUCT_ID"]))->GetNext();
            $pictureId = $offer["PREVIEW_PICTURE"];
            if (is_null($pictureId)) {
                $realProductInfo = CCatalogSku::GetProductInfo(IntVal($arProps["PRODUCT_ID"]));
                $realProduct = CIBlockElement::GetById(IntVal($realProductInfo["ID"]))->GetNext();
                $pictureId = $realProduct["PREVIEW_PICTURE"];
            }
            $thumb = CFile::ResizeImageGet(
                $pictureId,
                array("width" => 200, "height" => 200),
                BX_RESIZE_IMAGE_PROPORTIONAL,
                false
            );
            $thumb = $thumb["src"];
            // sum
            $summ = $arProps['QUANTITY'] * $arProps['PRICE'];
            $strOrderList .= "<tr><td class=\"num\">".$i."</td><td><img src=\"http://".$_SERVER['SERVER_NAME'] . $thumb."\"></td><td>".$arProps['NAME']."</td><td>".$arProps['QUANTITY']."</td><td>".number_format((float)$arProps['PRICE'], 2, '.', '')."</td><td>".number_format((float)$summ, 2, '.', '')."</td><tr>";
        }
        echo "</table>";
        // пишем в переменную для письма
        $arFields["ORDER_TABLE_ITEMS"] = $strOrderList; 
    }
}
?>

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

bitrix php

Ansible Playbook для создания нового сервера на vscale.io

Написал плейбук для создания нового сервера для небольших сайтов на хостинге https://vscale.io.

Работает следующим образом:

  1. Запускаете, спрашивает название скейлета на хостинге.
  2. Спрашивает путь к репозиторию, клонирует его локально.
  3. Создает новый сервак на хостинге, заходит на него, устанавливает докер и его зависимости.
  4. Копирует туда указанную в vars.yml директорию.
  5. Выполняет команду docker-compose up -d на сервере.

Найти последнюю версию можно здесь https://github.com/crusat/ansible_vscale_new_server, также прикрепил здесь версию на момент создания статьи.

devops docker

Как установить модули python без интернета с помощью pip

Для начала надо скачать все модули, которые перечислены в requirements.txt. Проще всего через докер.

$ docker run -it --rm --name my -v "$PWD":/tmp/pip_cache python:3.6 pip download -r /tmp/pip_cache/requirements.txt -d /tmp/pip_cache/

Обратите внимание на версию. Тут используется 3.6 - она должна совпадать с той версией питона, который установлен на сервере. Иначе Pillow, psycopg2 и т.п. скомпилированные модули не поставятся.

Затем можно залить их и установить с помощью такой команды:

$ pip install -r requirements.txt -f /path/to/pip/cache/ --no-index

Все, после этого можно использовать.

copypaste python

Редирект nginx

HTTP

server {
    listen 80;
    server_name www.example.com;

    location /.well-known/acme-challenge/ {
        root /home/garpix/www/example.com/;
    }

    location / {
       return 301 https://$host$request_uri;
    }
}

HTTPS (letsencrypt)

server {
    listen 443 ssl;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}
devops nginx