• Переезд на WordPress

    Переезд на WordPress

    Привет.

    Я тут давеча зашёл на свой старый blogger, чтобы опубликовтаь заметку про Sphinx, и понял — хватит с меня. Проведя на этой площадке около 7 лет, я заметил как сильно она меняется. Изменения были колоссальными, но чисто внешними, косметическими.

    Используя те средства управления, которые там есть, нельзя оформить блог как хочешь. Т.е. технически это можно, но на самом деле намного проще купить VPS, поднять весь софт, wordpress, завести инструменты для веб-мастеров яндекса и гугла, чем попытаться заверстать блог на blogger.

    Да, есть плюшки в виде интеграции с adsense, analytics, webmaster и вот этого всего, но когда речь идёт об удостве публикации — нет, увольте. Это какое-то безумие.  (далее…)

  • Как исправить ошибки при работе с Sphinx 3.0.3 и выше (с самого начала)

    Привет.

    Я тут на днях оформлял вики для корпоративного репозитория на тему правильного поднятия сфинкса и что делать при ошибках. Я не буду вдаваться в детали настройки, этого полно в сети и документации. Привожу общий порядок действий для установки и небольшой список самых распространённых проблем с их решениями.

    Допустим, что у нас есть сервер, на который ранее не устанавливался sphinx, и мы хотим поставить версию 3.0.3 или выше.

    Все манипуляции могут производиться любым системным пользователем (если не указано иное). В нашем примере мы сидим под пользователем user. (далее…)

  • Модуль интеграции Dreamkas для OpenCart 3.0.2.0

    Модуль интеграции Dreamkas для OpenCart 3.0.2.0

    Доброго дня, читатель. Редко я захожу сюда, ещё реже что-то пишу. Сейчас один из тех случаев, когда я считаю, что это просто необходимо.

    Введение

    Те, кто сталкивался с сервисом Dreamkas (онлайн-кассы, фискализация чеков, сканеры, терминалы и вот это вот всё по 54-ФЗ), могут иметь интернет-магазин на базе OpenCart.

    Дримкас предоставляет модули для интеграции с кучей CMS. Такие надстройки необходимы для отслеживания статусов фискализации чеков по заказу на сайте. Есть такой модуль и для OpenCart.

    (далее…)
  • VK API: загрузка изображения на стену. Рабочий код на PHP7 + cURL

    Публикую просто чтобы не потерялось.

    Если хорошо попросите и если я не забуду, оформлю полноценный репепт публикации постов с твоего сайта на страницу пользователя, с прикреплением фотографии. Когда твоё приложение в ВК зарегистрировано как веб-сайт, а не Stand-alone приложение.

    Пока тут только серверная часть. Она большого труда не составляет.

    Забудь всё, что ты видел о загрузке фотографий через curl. Я двое суток ебал мозги с целью выяснить почему я делаю так, как говорили когда-то и говорят до сих пор (например, про @ перед именем загружаемого файла, например, что уже неактуально для PHP >= 5.5)…. и почему при успешном запросе к серверу фотографий, ВК мне отдаёт пустой photo = []

    Будем считать, что у тебя уже есть ID приложения и ты получил жизненно важный access_token. Конкретно в контексте данного поста не играет роли, является ли твоё приложение веб-сайтом или Stand-alone. Механизм на сервере один.

    Наверняка ты уже заебался также, как и я, уже изучил документации, ответы сервера и всякое такое. Поэтому не буду рассказывать что будет происходить после каждого чиха.
    (далее…)

  • DavFS2. Куда утекает свободное место? Got error 28 from storage engine

    DavFS2. Куда утекает свободное место? Got error 28 from storage engine

    На сервере стало уменьшаться свободное место. Какое-то время не придавал этому значения, т.к. чётко знал, что у меня дважды в день работает скрипт автоматического бекапа базы данных с выгрузкой в облако.

    Хранить бекапы в том же месте, что резервировалось — глупый риск. Поэтому я просто чистил устаревше архивы на сервере ручками раз в несколько дней, т.к. они уже есть в облаке.

    Однажды утром, после свежего бекапа, MySQL стал падать с ошибкой:

    Got error 28 from storage engine

    Эта ошибка возникает во время выборки записей из БД. Поскольку выборка хранится в кеше на диске и в этот момент возникает ошибка, значит что-то с ним не так. Самое банальное — закончилось место. По факту так и оказалось. СУБД просто негде было хранить файлы кеша.

    Но как? На сервере свежий бекап только один, и его размер несоизмеримо меньше, чем сейчас должно быть свободного места.

    Начал поиски обжоры.

    (далее…)
  • Резервное копирование базы данных на Cron с выгрузкой в облако на примере Яндекс.Диск. Версия 1.

    Резервное копирование базы данных на Cron с выгрузкой в облако на примере Яндекс.Диск. Версия 1.

    Привет.

    Тут я расскажу о самом простом способе создания бекапов БД на сервере, о выгрузке их в Яндекс.Диск. Я написал скрипт, который всё это выполняет.

    Он приведён поэтапно, можешь скопировать пункты 4.1-4.5, убрав оттуда заголовки, и получишь готовый скрипт. Или можешь скачать, ссылка будет в конце. А лучше прочитать пост и вникнуть в суть происходящего.

    ОС на сервере — CentOS 6.7
    Версия СУБД — MySQL 5.5 (да, знаю, старая)

    Скрипт будет вертеться на сron, конечно же. Это чтобы само всё. Но это в конце.

    Монтирование Я.Диска в систему.

    1.1 Ставим davfs2 систему:

    yum install davfs2

    1.2 Создаём папку, в которую у нас будет монтироваться удалённое хранилище:

    mkdir /mnt/yadisk

    1.3 В файл /etc/davfs2/secrets пишем:

    /mnt/yadisk полныйадресemail@yandex.ru пароль

    1.4 В файле /etc/fstab указываем настройки монтирования хранилища (в одну строку, конечно):

    https://webdav.yandex.ru/ /mnt/yadisk davfs user,rw,_netdev,file_mode=600,dir_mode=700 0 1

    В конце файла должна быть пустая строка.

    Разгадку этого заклинания можно разобрать вот тут.

    1.5 Тестируем:

    mount /mnt/yadisk # монтирование
    df -h /mnt/yadisk # проверка свободного места

    В результате должно отобразиться свободное место на Яндекс.Диске, типа того:

    [root@server ~]# mount /mnt/yadisk
    [root@server ~]# df -h /mnt/yadisk
    Filesystem            Size  Used Avail Use% Mounted on
    https://webdav.yandex.ru/
                           10G  1,8G  8,3G  18% /mnt/yadisk

    По факту мы имеем обычную с виду директорию, куда можно писать всякое.

    umount /mnt/yadisk # Размонтируем диск

    Три-четыре. Закончили упражнение.

    Делаем дампы базы данных

    Дамп базы данных создаётся штатной утилитой mysqldump, которая идёт в комплекте с MySQL. Подробнее о ней можно прочесть здесь: MySQL.ru. Я же покажу здесь только необходимое мне самому.

    Синтаксис всей команды, например, таков:

    mysqldump --host=localhost --user=root --password=1234 -q --default-character-set=utf8 mybigdatabase > /home/mybigdatabase.sql

    Разберёмся с этой командой:

    —user — Имя пользователя БД
    —password — Его пароль
    —host — Адрес базы данных (скорее всего это localhost)
    —default-character-set — Кодировка текста дампа (скорее всего, это будет utf8)
    -q — Вывод текста дампа непосредственно на стандартный вывод stdout без буферизации запроса. Вообще, этот ключик нам необязателен, ибо у нас будет прямая запись вывода в файл. Но без него оно нафиг не надо, а с ним пусть будет.
    mybigdatabase — Имя базы данных
    > — Перенаправление вывода с перезаписью
    /home/mybigdatabase.sql — …например, в этот файл

    Можешь поиграться, чего-нибудь подампить, если есть чего.

    Упаковка дампа

    Используем команду gzip таким простым образом:

    gzip /home/mybigdatabase.sql

    В этой же папке образуется файл mybigdatabase.sql.gz, который меньше исходного на порядки.

    Можно использовать tar, но придётся вносить правки в скрипт. Если хочешь заморочиться — пожалуйста, но особой разницы не будет.

    tar -czf mybigdatabase.tar.gz /home/mybigdatabase.sql

    Всё.

    Объединение вышеописанного

    Теперь определяемся что и зачем будет делать наш скрипт. Всё очень просто:

    1. Инициализация — готовим переменные, параметры, пути, адреса;
    2. Создание дампа — собственно, бекапа БД;
    3. Упаковка дампа — для экономии места;
    4. Отправка бэкапа в облака — на случай смерти локального файла:
      1. Монтирование хранилища;
      2. Копирование файла в хранилище;
      3. Размонтирование хранилища;
    5. Завершение — выводим сообщения с результатами и итогами работы скрипта.

    Дальше я буду описывать это уже самими командами.

    Создаём файл db_backup.sh там, где душе угодно. Мне угодно в домашней папке рута.
    Пишем в него нижеследующее.

    4.1 Инициализация:

    #!/bin/bash
    
    # Данные для работы с БД
    DBHOST=localhost # Адрес БД
    DBUSER=root # Имя пользователя базы данных
    DBPASSWD=1234 # Пароль от базы данных
    DBNAME=mybigdatabase # Имя базы данных для резервного копирования
    DBCHARSET=utf8 # Кодировка базы данных (utf8)
    
    # Даты
    DATE=`date +%F` # Префикс для структурирования бекапов (формат: 2017-05-22)
    DATETIME=`date +%F-%H-%M-%S` # Полная текущая дата и время (формат: 2017-05-22-12-23-34)
    
    # Локальное хранилище
    LOCALDIR=/root/db_backup # Полный путь к каталогу, где будут храниться резервные копии
    LOCALPATH=$LOCALDIR/$DATE # Полный путь к папке за сегодня
    LOCALFILE=$LOCALPATH/$DBNAME-$DATETIME.sql # Полный путь к файлу дампа
    LOCALFILEGZ=$LOCALFILE.gz # Полный путь к архиву дампа
    # Путь к бекапу будет выглядеть так:
    # /root/db_backup/2017-05-22/mybigdatabase-2017-01-01-12-23-34.sql.gz
    
    # Облачное хранилище
    CLOUDUSE=1 # Копировать ли в облако? Закомментировать строку, если не надо
    CLOUDMNT=/mnt/yadisk # Точка монтирования облака относительно корня
    CLOUDDIR=db_backup # Папка в облаке, куда будут лететь файлы (внутри папки CLOUDMNT, т.е. без / в начале)
    CLOUDPATH=$CLOUDMNT/$CLOUDDIR/$DATE # Полный путь к папке текущей даты в облаке относительно корня
    CLOUDFILE=$CLOUDPATH/$DBNAME-$DATETIME.sql # Полный путь к файлу дампа в облаке
    CLOUDFILEGZ=$CLOUDFILE.gz # Полный путь к архиву в облаке
    
    # Путь к бекапу на примонтированном хранилище будет выглядеть так:
    # /mnt/yadisk/db_backup/2017-05-22/mybigdatabase-2017-01-01-12-23-34.sql.gz
    
    # Начало процесса
    echo "[-----------------------------[`date +%F-%H-%M-%S`]-----------------------------]"
    echo "[`date +%F-%H-%M-%S`] Starting backup"

    4.2 Создание дампа:

    if ! [[ -d $LOCALPATH ]]; then # Если нет папки за сегодня
     mkdir $LOCALPATH 2> /dev/null # создаём её, ошибки игнорируем
    fi
    echo "[`date +%F-%H-%M-%S`] Generate a database dump: '$DBNAME'..."
    mysqldump --user=$DBUSER --host=$DBHOST --password=$DBPASSWD -q --default-character-set=$DBCHARSET $DBNAME > $LOCALFILE
    if [[ $? -gt 0 ]]; then
     # если дамп сделать не удалось (код завершения предыдущей команды больше нуля) - прерываем весь скрипт
     echo "[`date +%F-%H-%M-%S`] Dumping failed! Script aborted."
     exit 1

    4.3 Упаковка дампа:

    else # иначе - упаковываем его
     echo "[`date +%F-%H-%M-%S`] Dumping successfull! Packing in GZIP..."
     gzip $LOCALFILE # Упаковка
     if [[ $? -ne 0 ]]; then # Если не удалась
      echo "[`date +%F-%H-%M-%S`] GZipping failed! SQL-file will be uploaded."
      GZIP_FAILED=1 # Создаём флажок, что упаковка сорвалась
     else
      echo "[`date +%F-%H-%M-%S`] Result file: $LOCALFILEGZ"
     fi

    4.4 Отправка в облака:

    if [[ $CLOUDUSE -eq 1 ]]; then # Если задано копирование в облако - делаем всякое такое 
     mount | grep "$CLOUDMNT" > /dev/null # Проверяем примонтировано ли уже у нас облако (вывод не важен) 
     if [[ $? -ne 0 ]]; then # Если нет 
      mount $CLOUDMNT # значит монтируем 
     fi 
     if [[ $? -eq 0 ]]; then # если монтирование успешно - копируем туда файл 
      echo "[`date +%F-%H-%M-%S`] Cloud: successfully mounted at $CLOUDMNT" 
      echo "[`date +%F-%H-%M-%S`] Cloud: copying started => $CLOUDFILEGZ" 
      if ! [[ -d $CLOUDPATH ]]; then # Если в облаке нет папки за сегодня 
       mkdir $CLOUDPATH 2> /dev/null # создаём её, ошибки игнорируем 
      fi 
      if [[ -f $LOCALFILEGZ && GZIP_FAILED -ne 1 ]]; then # Если у нас архивирование выше не сорвалось 
       cp -R $LOCALFILEGZ $CLOUDFILEGZ # Копируем архив 
      else 
       cp -R $LOCALFILE $CLOUDFILE # Иначе - копируем большой тяжёлый дамп 
      fi 
      if [[ $? -gt 0 ]]; then # Если не скопировался - просто сообщаем 
       echo "[`date +%F-%H-%M-%S`] Cloud: copy failed." 
      else # Если скопировался - сообщаем и размонтируем 
       echo "[`date +%F-%H-%M-%S`] Cloud: file successfully uploaded!" 
       umount $CLOUDMNT # Размонтирование облака 
       if [[ $? -gt 0 ]]; then # Сообщаем результат размонтирования (если необходимо)
        echo "[`date +%F-%H-%M-%S`] Cloud: umount - failed!" 
       fi # Конец проверки успешного РАЗмонтирования 
      fi # Конец проверки успешного копирования 
     else # если монтирование НЕуспешно - сообщаем 
      echo "[`date +%F-%H-%M-%S`] Cloud: failed to mount cloud at $CLOUDMNT" 
     fi # Конец проверки успешного монтирования 
    fi # Конец проверки необходимости выгрузки в облако

    4.5 Завершение

    fi # Конец проверки успешного выполнения mysqldump
    echo "[`date +%F-%H-%M-%S`] Stat datadir space (USED): `du -h $LOCALPATH | tail -n1`" # вывод размера папки с бэкапами за текущий день
    echo "[`date +%F-%H-%M-%S`] Free HDD space: `df -h /home|tail -n1|awk '{print $4}'`" # вывод свободного места на локальном диске
    echo "[`date +%F-%H-%M-%S`] All operations completed!"
    exit 0 # Успешное завершение скрипта

    5. Устанавливаем задачу в cron

    Из под root запускаем crontab -e. Подробности по работе с crontab можно найти здесь: Codenet.ru | Ubuntu.ru

    В окне запустившегося редактора пишем нижеследующее:

    # в качестве командного интерпретатора использовать /bin/sh
    SHELL=/bin/sh
    # результаты работы отправлять по этому адресу
    MAILTO=example@site.com
    # Запуск скрипта дампа боевой БД и запись в лог
    0 8,20 * * * bash ~/db_backup.sh >> ~/db_backup/db_backup.log

    Важна последняя команда:

    • 0 — в ноль минут 8,20 — в 8 часов утра и 20 часов вечера (без пробела) * — каждый день — каждой недели * — каждого месяца;
    • запускается интерпретатор bash;
    • который получает путь к скрипту ~/db_backup.sh (а равно /root/db_backup.sh, если всё происходит под рутом);
    • выполняет его;
    • а вывод дописывается (>>) в файл лога ~/db_backup/db_backup.log

    Сразу разъясню простой момент с угловыми скобками:

    • > (равносильно 1> ) — перенаправление всего вывода в указанное место с перезаписью. Существующий файл перезаписывается полностью, отсутствующий — создаётся.
    • 2> — перенаправление вывода ошибок stderr в указанное место. Если отправить в /dev/null, то сообщений об ошибках в выводе на экране не окажется.
    • >> — перенаправление вывода без перезаписи. Если файла нет — он создаётся, если файл есть — результат дописывается в его конец. Подробнее о перенаправлениях выводов можно прочесть здесь: OpenNET.ru. Там очень богатый функционал и синтаксис.

    Пример конечного лога

    [-----------------------------[2017-01-01-17-40-50]-----------------------------]
    [2017-01-01-17-40-50] Run the backup script...
    [2017-01-01-17-40-50] Generate a database backup: 'mybigdatabase'...
    [2017-01-01-17-44-17] Dumping successfull! Packing in GZIP...
    [2017-01-01-17-47-36] Result file: /root/db_backup/2017-01-01/mybigdatabase-2017-01-01-17-40-50.sql.gz
    [2017-01-01-17-47-38] Cloud: successfully mounted at /mnt/yadisk.
    [2017-01-01-17-47-38] Cloud: copying started => /mnt/yadisk/db_backup/2017-01-01/mybigdatabase-2017-01-01-17-40-50.sql.gz
    [2017-01-01-17-48-58] Cloud: file successfully uploaded!
    [2017-01-01-17-48-58] Stat datadir space (USED): 666M   /root/db_backup/2017-01-01
    [2017-01-01-17-48-58] Free HDD space: 100500G
    [2017-01-01-17-48-58] All operations completed!

    Заключение

    На этом пока всё.

    В планах сделать лимиты на объём папок с бекапами. При превышении заданного лимита — удалять старые бекапы.

    Это будет во второй версии. Когда-нибудь.

    Принимаю инфу об ошибках, критику и предложения.

  • Русификация NetDrive 2.6

    Интерфейс NetDrive на момент публикации поста

    Я был искренне удивлён, что в рунете до момента написания поста не всплывало русификатора этой прекрасной утилиты. Она платная, варез обсуждать не будем. А вот перевод очень важен. Если его и реально найти, то для чрезвычайно устаревших версий и со всяким говном вдовесок.

    Поэтому я решил сделать свой перевод. Переведено 100% фраз, но просмотреть как отображаются некоторые из них мне не удалось. Поэтому сорри, если где-то всплывёт косяк в отрисовке интерфейса.

    Версия NetDrive, на которой тестировался перевод — 2.6.15.953, но в теории должно подойти к любой минорной.

    (далее…)
  • Ошибка Laravel 5.3 — Exception in random.php line 185: There is no suitable CSPRNG installed on your system

    Ошибка Laravel 5.3 — Exception in random.php line 185: There is no suitable CSPRNG installed on your system

    Столкнулся с ошибкой после установки Laravel 5.3 на VPS.

    Exception in random.php line 185:
    There is no suitable CSPRNG installed on your system

    Коротко, конфигурация сервера:

    $ cat /etc/redhat-release
    CentOS release 6.6 (Final)
    $ php -v
    PHP 5.6.27 (cli) (built: Oct 14 2016 13:58:34)
    Copyright (c) 1997-2016 The PHP Group
    Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with XCache v3.2.0, Copyright (c) 2005-2014, by mOo
    with XCache Optimizer v3.2.0, Copyright (c) 2005-2014, by mOo
    with XCache Cacher v3.2.0, Copyright (c) 2005-2014, by mOo
    with XCache Coverager v3.2.0, Copyright (c) 2005-2014, by mOo
    $ httpd -v
    Server version: Apache/2.2.15 (Unix)
    Server built:   Oct 16 2014 14:45:47

    Эта ошибка Laravel решается элементарно.
    (далее…)

  • Пупсик. Цепная передача (ч.3)

    Пупсик. Цепная передача (ч.3)

    Часть 1: Пупсик. Я его купил! (ч.1)

    Часть 2: Пупсик. Первые вложения, первые впечатления (ч.2)


    Итак, на данный момент у нас есть начальный инструмент, некоторые окрашенные части и новая резина.

    С чем я заморочился дальше?

    (далее…)
  • Пупсик. Первые вложения, первые впечатления (ч.2)

    Пупсик. Первые вложения, первые впечатления (ч.2)

    Часть 1: Я его купил!

    Часть 3: Пупсик. Цепная передача (ч.3)


    Итак, я приехал домой. Ехал долго и мучительно, с непривычки болела задница от седла. Приходилось останавливаться для передышки, т. к. дыхалка курильщика надо полагать нездорова, а ноги совершенно каменные: я с физкультурой перестал дружить ещё в школе, и велосипед призван как-то это немного исправить. А вкупе с переходом с табачного дыма на глицериновый пар это должно дать ещё лучший результат в выносливости.

    Можете считать, что я понемногу, ненавязчиво стал заниматься своим здоровьем. Но мне это не присуще и потому странно.

    (далее…)