Вывод содержание загруженной FB2 книги в Drupal

Продолжаю цикл статей о создании электронной библиотеки на Drupal 7. В прошлой статье я рассказал о модуле, который позволяет загружать на сайт книги в формате FB2 и создает из них ноды. Сегодня же я покажу, как можно вывести содержание загруженной тем модулем книги.
Кому интересно, прошу под кат.

Создание ноды в Drupal по загруженной FB2 книге.

Потихоньку работаю над проектом электронной библиотеки книг в формате FB2, и решил использовать для нее Drupal. Собственно, вся логика библиотеки будет заключаться в пакете модулей «FB2». Модули пишу строго под нужды конкретного проекта, поэтому пока не планирую выкладывать их целиком, а лишь опишу принцип их работы и приведу наиболее интересные и важные участки кода.
А первым на очереди у нас модуль, который позволяет пользователям загружать на сайт файлы FB2, разбирает их и создает соответствующие ноды, где заголовок ноды — это название книги а тело ноды — аннотация. Плюс, дополнительно созданные поля «autor» и «file» для хранения авторов книги и ссылки на сам FB2.
Узнать подробнее можно по ссылке: Загрузка книг в формате FB2 и создание из них нод в Drupal

Валидация форм на HTML5 по pattern и AJAX.

Как известно, HTML5 предоставляет нам много новых плюшек для контроля вводимых пользователем данных в текстовые поля форм. Это позволило сильно облегчить JS-валидацию форм в нашей системе интернет-банкинга. Однако, столкнулся с досадным моментом: каждый браузер по своему изменяет внешний вид полей при неправильном вводе. Кроме того, основная валидация происходит при вызове метода Submit формы. У нас же так исторически сложилось, что данные передаются в виде JSON’а через AJAX по нажатию на обычный button. В результате чего родилась вот такая функция:

function ChkHTMLValidation(obj)
{
	var field = document.getElementById(obj);
	if(!field.checkValidity()){
		document.getElementByID(obj).classList.add('StateError');
		document.getElementByID('button_next').disabled=true;
	}else{
		document.getElementByID(obj).classList.remove('StateError');
		document.getElementByID('button_next').disabled=false;
	}
}

На вход функция получает ИД текстового input’а, у которого определен pattern, и проверяет корректность введенных в него данных. Если данные некорректны, на поле навешивается CSS-класс ошибки и отключается кнопка отправки формы. Если же данные корректны — CSS-класс ошибки удаляется и кнопка включается.

Отправка XML методом POST в C#

Ох, что-то давно я ничего не писал… Дедлайн ближе — посты реже 🙂

В процессе прикручивания к интернет-банку платежной системы QIWI возникла необходимость слать XML POST-запросом на определенные URL и смотреть, что приходит в ответ. Чтобы не ворочать ради этого всю систему интернет-банкинга и не собирать нужную информацию по текстовым логам сервера, склепал на .Net небольшую софтинку в пару строк кода, которая шлет на указанный URL переданный XML методом POST используя класс WebRequest и выводит все, что получает в ответ. Исходник проекта берем тут.

P.S.: тулза писалась для личного использования в буквальном смысле на коленке, и по хорошему в нее надо добавить проверку ошибок (неправильный URL, URL не найден, ошибка DNS и т.д.).

Вычисляем Internet Explorer 11 или почему Jquery распознает его как Mozilla Firefox 11

В пятницу вечером обновился до IE 11 и ушел с работы. Дома для веб-серфинга пользуюсь только Firefox’ом. Сегодня утром, придя на работу, продолжил изменять интерфейс нашего интернет-банкинга. В свежих версиях Firefox, Opera и Chrome все было отлично, а вот при попытке залогинится через IE 11 получил сообщение «Браузер Mozilla Firefox 11 не поддерживается.». Для проверки версии браузера на клиенте используется Jquery.browser, и почему-то $.browser.mozilla при IE 11 равен true.

Взглянем на USER-AGEN STRING нового IE11:

Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv 11.0) like Gecko

Заметили, что больше нет слова «MSIE»? Зато появилось «like Gecko». В общем, похоже, jQuery  не находит слова «MSIE», зато находит «Mozilla», и думает, что браузер — Mozilla Firefox. А версия — 11.

Мой способ решения не особо оригинальный, да и вообще, пора уже переходить на jQuery 2. Но пока этого еще не произошло, я решил искать в USER-AGENT явное упоминание движка IE:

1
2
3
var UserAgentString = navigator.userAgent;
 
if(UserAgentString.indexOf('Trident/7.0') + 1){alert("Hello, IE11 !");}

Получаем локальный IP и Mac посетителя на сайте

Возникла задача: необходимо записать в лог, с какого локального (внутреннего) IP и MAC (на случай включенного DHCP внутри подсетки)  адресов клиент зашел на сайт. Если разбирать заголовки запроса на сервере, то мы получим лишь его внешний IP. Если пользователь сидит за NAT’ом, то это нам практически ничего не даст.  Что же делать? Запускать что-то на клиенте, что обратится к его сетевой карте и получит все необходимые сведения, а затем передаст на сервер. Первым в голову приходит JavaScript, но вот беда — из-за ограничений безопасности браузера JS не может получить доступа к железу. Значит, будем пробовать реализовать это на JAVA, добавив в страничку невидимый апплет.

Continue reading ‘Получаем локальный IP и Mac посетителя на сайте’ »

wp-cron.php грузит процессор

В выходные зашел на один из своих сайтов кое-чего подправить, и заметил жуткие тормоза в его работе, (даже несмотря на то, что он практически полностью кэшируется в memchached). Озадаченный этим, полез в админку хостера и обнаружил, что мой аккаунт полностью грузит процессор, при этом нагрузка на БД минимальна. В логах использования ЦП часто встречались строчки типа «charmlab.ru/wp-cron.php?doing_wp_cron=1369560421.321949005126953125000».

cpu_usage_log

Оказалось, что это известная проблема WordPress’а, и не раз уже поднималась в интернете. Однако, практически везде предлагают одно и то же решение: добавить в wp-config.php строчку «define(‘DISABLE_WP_CRON’, true);«. Я сделал тоже самое, но видимого результата почему-то не получил 🙁 (Как оказалось, не один я).

К сожалению, на выходных я так и не смог разобраться в первопричине такого поведения, поэтому просто переименовал wp-cron.php. Нагрузка сразу же спала, но, конечно, WordPress потерял возможность выполнять задания по расписанию.

Валидация даты на JavaScript

Для ввода дат на сайтах я обычно использую замечательный плагин Jquery Datepicker, выставляя текстовому полю, к которому он привязан, режим readonly. Таким образом, я точно знаю, в каком формате введенная дата придет на сервер, и как ее там обработать (но не забываю о проверке введенных данных на стороне сервера!). Однако, недавно возникла задача разрешить ручной ввод даты в текстовом поле в формате дд.мм.гггг. Конечно, можно разрешить писать в текстовое поле все, что угодно и проверять валидность введенных данных на сервере. Однако, на мой взгляд, было бы удобней проверить данные сразу на стороне клиента, и если данные введены неверно — принять нужные меры.
Итак, вот как будет работать наша система: при клике на поле для ввода даты будет отображаться стандартный Jquery Datepicker. Если же пользователь хочет ввести дату вручную, он может написать ее прямо в этом текстовом поле. Для облегчения этого добавим к полю маску ввода Jquery Masked Input. Если введенная дата валидна, включаем кнопку сабмита и подсвечиваем поле зеленым. Если дата не валидна — подсвечиваем поле красным и отключаем кнопку сабмита.
Проверить валидность даты можно при помощи Jquery Validate, но я решил написать для этого свой велосипед на нативном JS, так что представленная ниже функция валидации может быть использована без каких-либо JS фреймворков (или в связке с любым из них :)).
Собственно, вот исходник моей функции:

function ValidateDate(date_fl){
str=date_fl.value;
function TstDate(){
str2=str.split(".");
if(str2.length!=3){return false;}
//Границы разрешенного периода. Нельзя ввести дату до 1990-го года и позднее 2020-го.
if((parseInt(str2[2], 10)< =1990)||(parseInt(str2[2], 10)>=2020)) {return false;}
str2=str2[2] +'-'+ str2[1]+'-'+ str2[0];
if(new Date(str2)=='Invalid Date'){return false;}
return str;
}
var S=TstDate()
if(S)
{
//Дата валидна
date_fl.className='date_ok';
document.getElementById("submit").disabled = false;
}
else
{
//Дата не валидна
date_fl.className='date_err';
document.getElementById("submit").disabled = true;
}
}

Немного поясню принцип ее работы: функция принимает на вход объект, в который производится ввод даты. Затем введенное значение разбивается на массив по точке в качестве разделителя и приводится в формат гггг-мм-дд, после чего происходит попытка создания на его основе объекта типа Date. Таким образом проверяется не просто соответствие записи форме xx.xx.xxxx, а именно возможность существования такой даты (31-е февраля не прокатит). Если все отлично — присваиваем полю ввода CSS-класс ‘date_ok’ и включаем кнопку сабмита. Если произошла ошибка — присваиваем класс ‘date_err’ и отключаем кнопку. Конечно, ничто не мешает вам произвести какие-то свои действия.
Ну и в конце архив с примером использования.

Сказ о том, как крутой программист не мог Windows с флэшки поставить

Некоторое время назад стал "счастливым" обладателем ноутбука фирмы DNS. Практически сразу на него была поставлена Ubuntu и поднят LAMP. Однако все течет, все меняется, и в итоге мне понадобилось разработать довольно крупное приложение на ASP.NET, а для этого нужна ОС Windows.

Привычным движением записал на стационарном компе программой UltraISO образ новенькой 8-ки на флэшку, пихнул в USB ноута и… и ничего. Ноут с нее не грузился. Флэшка прекрасно виделась в BIOS, но при попытке с нее загрузится ноут просто не реагировал. Мигал курсором на девственно-чистом черном экране, и все 🙁 

Долго я думал, много мануалов перечитал, и в итоге надумал: форматнул флэшку в FAT32 (до этого она в NTFS была), и записал по новой на нее образ из UltraISO. В итоге система встала без каких-либо проблем. 

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

Drupal: запрет кэширования страницы модуля

Столкнулся недавно с такой проблемой: на сайте www.carhelpinfo.ru, работающим под Drupal, есть форма для поиска автомобильных запчастей, реализованная мной в виде отдельного модуля. Доступ к этой форме должен быть у всех пользователей, даже анонимных.

Для ускорения работы сайта используется Memcached. С включением опции кэширования страниц для анонимов сайт открывается практически мгновенно. Но вот беда — при этом не работает форма поиска: после запроса анонимному пользователю выдается не страница с результатами, а старая закэшированная страница.

Выходом из этой ситуации может быть использование в модуле своего собственного сегмента кэша и использование cahe_clear_all(). Эта функция может принимать в качестве параметра идентификатор сегмента кэша, который надо очистить. Если его не указывать — будет произведена очистка всего кэша. Но в таком случае при генерации страницы придется каждый раз тратить время на то, чтобы очистить сегмент кэша и записать туда новую версию страницы, которая при следующем вызове вновь будет перезаписанна.

Чтобы избежать этого, я просто стал передавать данные формы методом GET. Таким образом, при каждом запросе URL страницы меняется, и она генерируется снова. А если пользователь запросит то, что кто-то уже искал, то ему будет отдана страница из кэша.

Минусом такого метода является "загрязнение" URL, но в данном конкретном случае для сайта www.carhelpinfo.ru это не имеет значения.