Category Archives: сервисы

Лечим раскладку клавиатуры

В одном из последних (весенних ещё) обширных обновлений винда как обычно испортило мне5 раскладку.

У меня такая раскладка:
ENG English (United States)/ US keyboard – основная
РУС Russian Russian keyboard.

Английская основная, т.к. я в основном занимаюсь программированием, а все языки программирования, кроме Рапиры, требуют латинской раскладки.

Переклчюаюсь я по Ctrl+Shift.

Итак, как я уже сказал, испортили мне опять раскладку, поставили en-GB вместе с en-US, удалили раскладку РУС.

Так вот, раньше в Language Preferences я мог быстро удалить ненужные раскладки, добавить нужные и выбрать раскладку по умолчанию.
Теперь же, после последнего обнолвения – нет. Не могу удалить EN-GB, хотя она не назначена как дефолтная.
Кнопка “Remove” у неё почему-то не активна во всех случаях.

Искал я инфо в интернете, пробовал разные варианты, в том числеи с редактированием реестра инастройкой различных прав доступа,
перезапускал раз десять систему, что делаю довольно редко, т.к. во время отдыха кладуего в сон – ничего не помогло.

Помог только один вариант, которые я нашёл в конце постов на каком-то форуме, и этот вариант предлагал использование Windows Power Shell.
Выглядит дико, признаю, но это факт. Как обычным пользователям, не знакомым с оболочками и программированием исправить себе раскладку клавиатуры, я не знаю!

Итак, сценарий исправления таков:

1. Открываем Power Shell с администраторскими правами.
2. Смотрим текущие раскладки:
PS C:\WINDOWS\system32> Get-WinUserLanguageList

LanguageTag : en-US
Autonym : English (United States)
EnglishName : English
LocalizedName : English (United States)
ScriptName : Latin script
InputMethodTips : {0409:00000409}
Spellchecking : True
Handwriting : False

LanguageTag : en-AU
Autonym : English (Australia)
EnglishName : English
LocalizedName : English (Australia)
ScriptName : Latin script
InputMethodTips : {0C09:00001809}
Spellchecking : True
Handwriting : False

LanguageTag : ru
Autonym : русский
EnglishName : Russian
LocalizedName : Russian
ScriptName : Cyrillic
InputMethodTips : {0419:00000419}
Spellchecking : True
Handwriting : False

LanguageTag : en-GB
Autonym : English (United Kingdom)
EnglishName : English
LocalizedName : English (United Kingdom)
ScriptName : Latin script
InputMethodTips : {0809:00000809}
Spellchecking : True
Handwriting : False

Тут видны 4 раскладки, это я экспериментировал, пытаясь добавлять/удалять и переназначать дефолтные раскладки.

Итак, чтобы устновить одну только раскладку, удалив все осталдьные, выполняем такую команду:
PS C:\WINDOWS\system32> Set-WinUserLanguageList -LanguageList en-US -Force
и смотрим, что получилось:
PS C:\WINDOWS\system32> Get-WinUserLanguageList

LanguageTag : en-US
Autonym : English (United States)
EnglishName : English
LocalizedName : English (United States)
ScriptName : Latin script
InputMethodTips : {0409:00000409}
Spellchecking : True
Handwriting : False

ОК, но как нам теперь доавить русскую раскладку? Не существует метода типа Add-WinUserLanguage, естьт только команды Set-/Get-WinUserLanguageList.

Для формирования нужной раскладки нам надо создать оъект с нужными раскладками и передать его в качестве парметра Set-WinUserLanguageList.

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

Вот мои действия, которые в итоге привели к успеху, я сейчас имю 2 нужные мне раскладки, описанные в начале поста, и они нормально функционируют, большего мне не нужно!
Итак, удаляем все раскладки, что можно, помня, что EN-GB не удаляется совсем, неважно, дефолтная она или нет, т.к. кнопка “Remove” по загадочным причинам не активна совсем.
Доабвляем EN-US, делаем её дефолтной и переставляем на первое место, потом добавляем раскладку РУС.

Теперь запускам Power Shell с административными привилегиями и делаем так:

PS C:\Users\Andrey> $list = Get-WinUserLanguageList
PS C:\Users\Andrey> $list
 
 
LanguageTag     : en-US
Autonym         : English (United States)
EnglishName     : English
LocalizedName   : English (United States)
ScriptName      : Latin script
InputMethodTips : {0409:00000409}
Spellchecking   : True
Handwriting     : False
 
LanguageTag     : en-GB
Autonym         : English (United Kingdom)
EnglishName     : English
LocalizedName   : English (United Kingdom)
ScriptName      : Latin script
InputMethodTips : {0809:00000809}
Spellchecking   : True
Handwriting     : False
 
LanguageTag     : ru
Autonym         : русский
EnglishName     : Russian
LocalizedName   : Russian
ScriptName      : Cyrillic
InputMethodTips : {0419:00000419}
Spellchecking   : True
Handwriting     : False
 
 
PS C:\Users\Andrey> $x = ($list[0], $list[2])
PS C:\Users\Andrey> $x
 
 
LanguageTag     : en-US
Autonym         : English (United States)
EnglishName     : English
LocalizedName   : English (United States)
ScriptName      : Latin script
InputMethodTips : {0409:00000409}
Spellchecking   : True
Handwriting     : False
 
LanguageTag     : ru
Autonym         : русский
EnglishName     : Russian
LocalizedName   : Russian
ScriptName      : Cyrillic
InputMethodTips : {0419:00000419}
Spellchecking   : True
Handwriting     : False
 
 
PS C:\Users\Andrey> Set-WinUserLanguageList $x
 
Confirm
Continue with this operation?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): y

Всё, теперь у нас только 2 раскладки, EN-US и РУС:

PS C:\Users\Andrey> $list = Get-WinUserLanguageList
PS C:\Users\Andrey> $list
 
 
LanguageTag     : en-US
Autonym         : English (United States)
EnglishName     : English
LocalizedName   : English (United States)
ScriptName      : Latin script
InputMethodTips : {0409:00000409}
Spellchecking   : True
Handwriting     : False
 
LanguageTag     : ru
Autonym         : русский
EnglishName     : Russian
LocalizedName   : Russian
ScriptName      : Cyrillic
InputMethodTips : {0419:00000419}
Spellchecking   : True
Handwriting     : False

В этом можно также убедиться, щёлкнув на раскладку в трее справа.

Информация, которую я использовал для поиска нужного варианта:
************************************************************************************************

Удалять/добавлять нужные раскладки:
$list = Get-WinUserLanguageList

Возвращает массив с 2 объектами – пример для Английской и Литовской раскладок:

$list[0]:
LanguageTag : en-US
Autonym : English (United States)
EnglishName : English
LocalizedName : English (United States)
ScriptName : Latin script
InputMethodTips : {0409:00000409}
Spellchecking : True
Handwriting : False

$list[1]:
LanguageTag : lt
Autonym : lietuvių
EnglishName : Lithuanian
LocalizedName : Lithuanian
ScriptName : Latin script
InputMethodTips : {0427:00010427}
Spellchecking : True
Handwriting : False

Теперь мы можем установить одну расклдаку из массива так:
Set-WinUserLanguageList $($list[0])

Если же English и Lithuanian раскладки под индексом 0 и 1 в массиве, мы можем сделать так, чтобы добавить только две эти раскладки в системе:
$x = ($list[0], $list[1])
Set-WinUserLanguageList $x

********************************
Работаем с массивами в Power Shell

$x.RemoveAt(1) – не работает?
$x.remove(($x|where-object languagetag -eq ‘ru’)) – тоже не рбаотает?

Оба этих метода выдют одну ошибку:
************************************************************************************************
Exception calling “RemoveAt” with “1” argument(s): “Collection was of a fixed size.”
At line:1 char:1
+ $x.RemoveAt(0)
+ ~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : NotSupportedException
************************************************************************************************
Ага попробуем с такого примера: https://stackoverflow.com/questions/40274422/remove-a-row-from-a-powershell-array-collection-hashtable

Оказывается, массивы неизменянемы в PowerShell, и мы не можем удалять/добавлять к ним элементы. Но мы можем выбрать изтаких варинатов:

a) Создать новый массив, отфильтровав не нужные нам элементы (например применяя -ne)
$data = $data | ? {$_.Server -ne “Total”}

b) Выбрать всё до последнего элемента по индексу:
$data = $data[0..($data.Count-2)]

c) Преобразовать массив к [System.Collections.ArrayList], который изменяем, и удалить элементы из него:
$data = [System.Collections.ArrayList]$data
$data.RemoveAt($data.Count-1)

в нашем случае:
$x = [System.Collections.ArrayList]$x
$x.RemoveAt(1)
$x.GetType()
$x

LanguageTag : en-US
Autonym : English (United States)
EnglishName : English
LocalizedName : English (United States)
ScriptName : Latin script
InputMethodTips : {0409:00000409}
Spellchecking : True
Handwriting : False

************************************************************************************************
************************************************************************************************

You can easily change current input language via .NET class, like this:

Add-Type -AssemblyName ‘System.Windows.Forms’
[System.Windows.Forms.InputLanguage]::CurrentInputLanguage = [System.Windows.Forms.InputLanguage]::InstalledInputLanguages | ? { $_.Culture -eq ‘ru-RU’ }

************************************************************************************************

Собственная капча на PHP своими руками за 5 минут

Приветствую вас!

Итак, мы наконец-то решились защитить свои формы капчей, т.к. спамеры вконец достали тупым спамом.

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

Итак, в этом посте мы напишем собственный гибкий капча-механизм на PHP, который мы сможем поставить на свои формы за 5-10 минут.

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

Капчу мы будем рисовать на движке PHP GD, и для этого нам потребуются шрифт(ы) – да, можно использовать несколько шрифтов для некого затруднения работы по обходу капч.

Создадим папку fonts и закинем туда парочку бесплатных TTF-шрифтов, например, liber-mono.ttf и liber-sans.ttf. Сразу замечу, что полный комплект файлов – скрипты и шрифты вы можете скачать по ссылке: https://beotiger.com/download/jcaptcha.

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

Вот этот скрипт с подробными комментариями:

// зададим имя куки для сохранения в ней кода капчи
define('CAPTCHA_COOKIE', 'imgcaptcha_');
 
/*
 
	Инициализируем генератор случайных чисел.
	Хотя в руководстве по PHP написано, что это делается автоматически
	каждый раз при запуске сценария, но... я им не верю 0_0
 
*/
 
mt_srand(time());
 
/*
 
	Определим путь к папке со шрифтами
	и список имен файлов со шрифтами в ней -
	из этого списка каждый раз будем выбирать случайный шрифт
 
*/
 
define('PATH_TTF', 'fonts/');
$fonts = array('liber-mono.ttf', 'liber-sans.ttf');
 
/*
 
	Основные параметры капчи.
 
	Для поддержки разных параметров капчи здесь можно	создать
	многомерный массив и обращаться к нему по индексу.
 
*/
 
$par = array(
	// ширина капчи
	'WIDTH' => 120,
	// высота капчи
	'HEIGHT' => 32,
	// размер шрифта на капче
	'FONT_SIZE' => 14,
 
	// кол-во символов на капче
	'CHARS_COUNT' => 5,
	// разрешенные символы капчи
	'ALLOWED_CHARS' => 'ABCDEFGHJKLMNPQRSTUVWXYZ23458',
 
	// фоновый цвет капчи - белый в нашем случае
	'BG_COLOR' => '#FFFFFF',
	// кол-во линий на капче
	'LINES_COUNT' => 3,
	// толщина линий
	'LINES_THICKNESS' => 2
);
 
/*
	Общие парметры капчи
*/
 
// цвета символов
define('CODE_CHAR_COLORS', '#880000,#008800,#000088,#888800,#880088,#008888,#000000');
// цвета линий
define('CODE_LINE_COLORS', '#880000,#008800,#000088,#888800,#880088,#008888,#000000');
 
// получаем цвета линий и символов в массивы для случайной выборки позднее
$line_colors = preg_split('/,\s*?/', CODE_LINE_COLORS);
$char_colors = preg_split('/,\s*?/', CODE_CHAR_COLORS);
 
// создаем пустой рисунок и заполняем его белым фоном
$img = imagecreatetruecolor($par['WIDTH'], $par['HEIGHT']);
imagefilledrectangle($img, 0, 0, $par['WIDTH'] - 1, $par['HEIGHT'] - 1, gd_color($par['BG_COLOR']));
 
// устанавливаем толщину линий и выводим их на капчу
imagesetthickness($img, $par['LINES_THICKNESS']);
 
for ($i = 0; $i < $par['LINES_COUNT']; $i++)
    imageline($img,
        mt_rand(0, $par['WIDTH'] - 1),
        mt_rand(0, $par['HEIGHT'] - 1),
        mt_rand(0, $par['WIDTH'] - 1),
        mt_rand(0, $par['HEIGHT'] - 1),
        gd_color($line_colors[mt_rand(0, count($line_colors) - 1)])
    );
 
// Переменная для хранения кода капчи
$code = '';
 
// Зададим координату по центру оси Y 
$y = ($par['HEIGHT'] / 2) + ($par['FONT_SIZE'] / 2);
 
// Выводим символы на капче
for ($i = 0; $i < $par['CHARS_COUNT']; $i++) {
		// выбираем случайный цвет из доступного набора
    $color = gd_color($char_colors[mt_rand(0, count($char_colors) - 1)]);
    // определяем случайный угол наклона символа от -45 до 45 градусов
    $angle = mt_rand(-45, 45);
    // выбираем случайный символ из доступного набора
    $char = substr($par['ALLOWED_CHARS'], mt_rand(0, strlen($par['ALLOWED_CHARS']) - 1), 1);
    // выбираем случайный шрифт из доступного набора
    $font = PATH_TTF . $fonts[mt_rand(0, count($fonts) - 1)];
    // вычислим координату текущего символа по оси X
    $x = (intval(($par['WIDTH'] / $par['CHARS_COUNT']) * $i) + ($par['FONT_SIZE'] / 2));
 
    // выводим символ на капчу
    imagettftext($img, $par['FONT_SIZE'], $angle, $x, $y, $color, $font, $char);
 
    // сохраняем код капчи
    $code .= $char;
}
 
// сохраним капчу в куках для дальнейшей проверки
setcookie(CAPTCHA_COOKIE, md5($code));
 
/*
 
	Посылаем сформированный рисунок в браузер и избавляемся от него, 
	хотя сборщик мусора обычно это делает за нас
 
*/
 
header("Content-Type: image/png");
imagepng($img);
imagedestroy($img);
 
// Преобразуем HTML 6-символьный цвет в GD цвет 
function gd_color($html_color)
{
  return preg_match('/^#?([\dA-F]{6})$/i', $html_color, $rgb)
    ? hexdec($rgb[1]) : false;
}

Вот как выглядит сформированная данным скриптом капча (щёлкните на ней для смены кода):

Капча

Теперь для создании формы с капчей достаточно добавить в неё дополнительный инпут с произвольным именем и разместить капчу, например так:

<form action="go.php" method="post">
	Введите имя: <input name="name"><br>
	Введите email: <input name="email"><br>
	Введите код с картинки: <input name="captcha">
	<img title="Щёлкните для нового кода" alt="Капча" src="jcaptcha.php" style="border: 1px solid black" onclick="this.src='jcaptcha.php?id=' + (+new Date());"><br>
	<input type="submit" value="Отправить!">
</form>

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

 
	// зададим имя куки для получения из неё кода капчи,
	// оно конечно же должно совпадать с соотв. именем в jcaptcha.php
	define('CAPTCHA_COOKIE', 'imgcaptcha_');
	// заметим: поле `captcha` обязательно для заполнения
	if(empty($_POST['captcha']) || md5($_POST['captcha']) != @$_COOKIE[CAPTCHA_COOKIE])
		die('Неверный код с картинки. Вернитесь и повторите попытку.');

Приведенный здесь код дан лишь для примера, в реальных условиях проверять капчу и выводить соотв. сообщение лучше ч/з AJAX, не покидая форму и не заставляя клиента каждый раз вводить одни те же данные по нескольку раз, с возможным таймаутом при превышении числа неудачных попыток для предотвращения брутфорс-атаки.

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

Итак, вы можете скачать полный комплект файлов данного примера – скрипты и шрифты по ссылке: https://beotiger.com/download/jcaptcha

А теперь – пока, пока.
До свидания, до новых встреч, друзья!

Комментарии VKontakte/Facebook – перехватываем и отправляем нам на почту

Добавляем виджеты комментариев VK/FB на свою страничку

Создаём приложения

Добавить комменты VK/FB на свой сайт относительно просто – создаём соотв. приложения в VK/FB, получаем их id. Вот адреса страничек для создания приложений: https://vk.com/dev/widgets_for_sites для ВК и https://developers.facebook.com/apps/ для Фэйсбук.

Подробно на этой теме останавливаться нет смысла, так как у них меняется всё очень часто, я имею в виду всякую воду и интерфейс, и каждый раз вникать в одно и тоже под другим соусом не особенно хочется. Но принцип видимо остаётся одним и тем же, и созданное нами несколько лет назад приложения продолжают работать. Честно говоря, назвать приложением это от FB/VK у меня язык с трудом поворачивается, скорее это надстройка над виджетами, контроллер виджетов точнее. Главное – они обеспечивают связь нашего сайта с многотысячной армией пользователей этих популярных сетей.
Continue reading

Часовые пояса и расширение tar.lz в Windows

Здравствуйте!

Нам понадобилось вывести список мировых временных зон, чтобы можно было выбрать одну из них.
Для PHP в итоге я смог сделать такой вариант:

function getOptTimeZones($dk_timezone = 0)
{
	// построим select для dk_timezone
	$dk_tzs = array(
-15 => '(GMT -12:00) Эневеток, Кваджалейн',
-14 => '(GMT -11:00) Остров Мидуэй, Самоа',
-13 => '(GMT -10:00) Гавайи',
-12 => '(GMT -9:00) Аляска',
-11 => '(GMT -8:00) Тихоокеанское время (США и Канада), Тихуана',
-10 => '(GMT -7:00) Горное время (США и Канада), Аризона',
-9 => '(GMT -6:00) Центральное время (США и Канада), Мехико',
-8 => '(GMT -5:00) Восточное время (США и Канада), Богота, Лима',
-7 => '(GMT -4:00) Атлантическое время (Канада), Каракас, Ла Пас',
-6 => '(GMT -3:00) Бразилия, Буэнос-Айрес, Джорджтаун',
-5 => '(GMT -2:00) Среднеатлантическое время',
-4 => '(GMT -1:00) Азорские острова, острова Зелёного Мыса',
-3 => '(GMT  0:00) Дублин, Лондон, Лиссабон, Касабланка, Эдинбург',
-2 => '(GMT +1:00) Брюсель, Копенгаген, Мадрид, Париж, Берлин',
-1 => '(GMT +2:00) Афины, Киев, Минск, Бухарест, Рига, Таллин',
0 => '(GMT +3:00) Москва, Санкт-Петербург, Волгоград',
1 => '(GMT +4:00) Абу-Даби, Баку, Тбилиси, Ереван',
2 => '(GMT +5:00) Екатеринбург, Исламабад, Карачи, Ташкент',
3 => '(GMT +6:00) Омск, Новосибирск, Алма-Ата, Астана',
4 => '(GMT +7:00) Красноярск, Норильск, Бангкок, Ханой, Джакарта',
5 => '(GMT +8:00) Иркутск, Пекин, Перт, Сингапур, Гонконг',
6 => '(GMT +9:00) Якутск, Токио, Сеул, Осака, Саппоро',
7 => '(GMT +10:00) Владивосток, Восточная Австралия, Гуам',
8 => '(GMT +11:00) Магадан, Сахалин, Соломоновы Острова',
9 => '(GMT +12:00) Камчатка, Окленд, Уэллингтон, Фиджи');
 
	$s = '';
 
	for($i = -15; $i < 10; $i++) {
		$s .= '<option value="' . $i . '"';
		if($i == $dk_timezone)
			$s .= ' selected';
		$s .= '>' . $dk_tzs[$i] . '</option>';
	}
 
        return $s;
}

То есть мы построили список из option элементов для select‘а для сдвига от МСК. Т.о. (GMT +3:00) Москва, Санкт-Петербург, Волгоград у нас будет иметь значение 0, а всё остальное плюс-минус от этого значения. Переменная $dk_timezone содержит текущий сдвиг, что позвлояет выделить нужный option. Полученный результат надо облечь в select элемент.

Да, я знаю, что построил массив излишне (можно было только указать -15 вначале, но так нагляднее и интересней выглядит.

При поиске готового архивчика с таким зонами я часто натыкался на ссылку http://www.iana.org/time-zones, где якобы представлна вся инфо по теме.

На этом уважаемом сайте действитльено даётся свободная скачка трёх интресных файликов:
Latest version
2016j (Released 2016-11-23)
File Description
tzdb-2016j.tar.lz (380.4kb) Complete Distribution (Data, Code and Extras)
tzdata2016j.tar.gz (313.7kb) Data Only Distribution
tzcode2016j.tar.gz (203.8kb) Code Only Distribution

Заметьте, что два файлика имеют расширение tar.gz, и один, самый интересный, за каким-то лешим имеет расширение .tar.lz. я не знаю, что творится в голове администратора данного ресурса, но выглядит это забавно. Что стукнуло ему в голову самый нужный файлик облечь в расширение .tar.lz, вместо доброго старого .tar.gz или на худой конец такого же доброго и такого же старого и проверенного временем tar.bz2?

Я сейчас пока вишу в Виньде (Windows 10), для распаковки пользуюсь 7zip (http://www.7-zip.org/) – огромная благодарность Игорю Павлову со-товарищи за разработку столь замечательного продукта. tar.gz и tar.bz2 (как и многие другие архивы) он щёлкает как семечки, а вот об tar.lz (по крайней мере на текущий момент, что я сейчас пишу) обламывает свои острые мощные зубки:

7zip fails to open tar.lz archive

Я даже проапгрейдил свой 7zip до версии 16.04, топовой на сегодня – 2016-11-23, т.е. 23 ноября 2016 РХ.

Быстрый гугл вывел на зверя lzip, я где-то нарыл скомпиленную под винду версию – lzip.exe, быстро запустил его в терминале,и вот что он выдаёт, собака:


С:\>lzip -d tzdb.tar.lz
tzdb.tar.lz: file ends unexpectedly at pos 21
lzip: Deleting output file `tzdb.tar', if it exists.
lzip: WARNING: deletion of output file (apparently) failed.

Я перименовал яновский tzdb-2016j.tar.lz в tzdb.tar.lz

Итак, что же делать? Далее гуглим и находим такую страничку: http://mm.icann.org/pipermail/tz/2016-September/024112.html

Вкратце, там человек по имени Oscar van Vlijmen жалуется, что не может открыть файлик lz в windows, такой же бедолага как и я, и упоминает тот же lzip, который я только что описал чуть выше.

Зачем, зачем, зачем админы http://www.iana.org/time-zones запаковали lzip‘ом только один файлик, а не все три тогда уж? Что у них, повторяюсь в третий раз, в головах творится?

Итак, кто-то ему отвечает:

Q: Why did the tachyon cross the road?
A: Because it was on the other side.

К чему это? Сколько лет ответившему так? он считает себя самым умным или самым остроумным? нет слов.

Следующий чуть лучше отвечает Оскару:

> do we get a decent application program with a graphical user interface
You mean, like the other tools we’re using? Like ‘tar’, ‘make’, and ‘cc’? 🙂

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

Ладно, этот же человек подсказал, что в CygWin‘е есть lzip, сейас его попробую, он скачивает кучу зависимостей за собой, что обычно для Unix-way. Спасибо ему, всё же он не так плох, как я думал вначале. 🙂 шутка

О, урра, получилось!!

Итак, по шагам, как я распаковал tzdb-2016j.tar.lz с сайта http://www.iana.org/time-zones в Windows 10:

1. Инсталлируем CygWin (https://cygwin.com/install.html), я это сделал в папку E:\cygwin64 – скачиваем setup-x86_64.exe файлик, запускаем его, выбираем папки (e:\cygwin64 для самого Cygwin‘а и e:\cygwin64\_local\ для временных локальных фалов.

2. Далее ищем в фильтре lzip, выбираем пакеты (я выбрал оба пакета, хотя боюсь можно выбрать только сам lzip), нажимаем Next или Далее, он выдаст окошко с зависимостями, которые по умолчанию все выбраны, нажимаем ОК, далее или что там ещё, не помню, и минут через 5 инсталлятор закончит работу.

3. Кидаем в папку e:\cygwin64\home\ВашеИмя\ нужный архивчик (tzdb-2016j.tar.lz)

4. Запускаем e:\cygwin64\Cygwin.bat, делаем ls, чтобы убедиться, что он тут:

$ ls
tzdb-2016j.tar.lz

И даём команду на его распаковку в tar:


$ lzip -d tzdb-2016j.tar.lz

На экран ничего не вывелось, кроме нового приглашения, что для Линукса говорит о том, что всё прошло ОК (хотя это не всегда так есть), т.к. если бы была какая-то ошибка, нам бы об этом с радостью сообщили.

Смотрим ещё ls:

$ ls
tzdb-2016j.tar

7zip fails to open tar.lz archive

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

Всё, задача решена, можно пойти выпить чая или какао или на худой конец коньяка с кофе. Или кофе без коньяка, до НГ, точнее до 12:00 31 декабря 2016 года я спиртного не потребляю, печень берегу и голову.

На сим кланяюсь. Доброй ночи!

P.S. Да, в итоге, в этом архивчике много всего интересного, но то, что мне нужно – список часовых поясов со сдвигом GMT+- для простого пользователя не оказалось!

Потом я в архиве какого-то форума нашёл приведенный выше (в самом начале поста) список, быстро переделал его под PHP, убрал +-30 минут кое-где, т.к. они мне не были нужны. И так получилась функция getOptTimeZones.

Node.js: пишем простой сервер с middleware, используя Connect

Предисловие. Пара слов о том, почему Node.js

Да, Node.js – это Вещь (с большой буквы, как и написано).
Чем больше я читаю и узнаю о нём, и пробую его, тем больше он мне нравится. С Ruby и Python‘ом пока не складывается (все мои проекты были на PHP, поэтому поддержка новой платформы была не актуальна – это учить новые языки, новые библиотеки, соглашения, короче, всю платформу, тогда как на PHP я программирую более-менее активно уже более 10 лет).

Но вот пришёл Node.js, который может заменить собой полностью серверную платформу, и он использует язык, на котором я также программирую свыше 10 лет – великий и ужасный JavaScript.

Причём пользоваться им легко и приятно, как оказалось, с учётом npmnode package manager‘а, который предоставляет быстрый и удобный доступ к тысячам или десяткам тысяч пакетов для Node.js с учётом всех зависимостей и прочая и прочая.

Пишем собственный (custom) middleware

Итак, давайте сваяем простой сервер на Connect, используя добавочно свою middleware. У меня в папке git скопилось наверное сотня разных проектов, и для серфинга по ним я использую либо Total Commander для просмотра и редактирования файлов, либо браузер ч/з запущенный сервер Apache или nginx также для наглядного просмотра папок и файлов.

Но с приходом Node.js логичней будет использовать сервер на нём для тренировки и вообще.

Так как в проектах на git частенько используется файл README.md в Markdown-разметке, добавим к нашему серверу функцию просмотра таких файлов в виде HTML на лету, написав простенький middleware.

Как известно, middleware для Connect/Express – это функция с тремя параметрами – req, res и next – запрос, ответ и функция обратного вызова для продолжения цепочки обработки запроса клиента.

Если наш middleware оканчивает запрос, он должен послать команду res.end(…) (в случае использования Connect‘а, в Express выбор богаче, это отдельная тема) для отдачи ответа клиенту, иначе он должен вызвать функцию next без параметров для обычного продолжения обработки, либо next(err) – с объектом ошибки – для дальнейшей обработки и рендеринга возникшей ошибки.

Вкратце алгоритм нашего middleware (назовём его any_md) будет таков: если строка запрашиваемого ресурса оканчивается на `.md`, то мы читаем файл ресурса, прогоняем его через marked (модуль формирования HTML из MD) и отдаём клиенту как обычный HTML файл. Считается, что файлы расположены начиная от текущей папки (git).
Круто? Круто. Неслыханно? Да. Восхитительно? Ещё как!

Вот как это выглядит на JavaScript под платформу Node.js:

// MIDDLEWARE: отдаём запрошенный файл .md как .html
var any_md = function(req, res, next){
// это md-файл?
if(req.url.toLowerCase().slice(-3) == '.md') {
 fs.readFile('.' + req.url, function(err, data){
  if(err) return next(err); // ошибку отправляем дальше
 
  // преобразуем MD -> HTML и отсылаем клиенту
  var html = '<!doctype html>\n<html lang="en">\n' +
  '<head>\n\t<meta charset="utf-8">\n\t<title>' + 
  req.url.slice(1) + '</title>\n</head>\n' + 
  '<body>\n' + marked(data.toString()) + '\n</body>\n</html>';
 
  res.writeHead(200, {
   'Content-Length': Buffer.byteLength(html),
   'Content-Type': 'text/html; charset=utf-8',
  });
  res.end(html);
 });
}
else
 next();
};

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

Так же в нашем сервере мы не рассматриваем кастомную обработку ошибок, оставляя её на совесть Connect‘а, точнее модуля errorhandler.

Готовый node.js сервер на Connect

Для нашего сервера мы будем использовать следующие middleware (модули) для Connect/Express:

  • compression – gzip/deflate сжатие данных на лету
  • morgan – бывший logger, лог запросов на консоль либо в файл
  • serve-favicon – отдача браузеру favicon.ico
  • serve-index – отдача списка файлов (каталога) клиенту
  • serve-static – отдача статических файлов (т.е. в нашем случае всех) клиенту
  • errorhandler – обработка ошибок
  • marked – рендер md разметки в html

Итак, для создания сервера заходим в папку git, где у нас расположены папки десятков или сотен git-проектов, и выполняем команду:

npm install -g errorhandler connect compression morgan serve-favicon serve-index serve-static marked

Заметьте, что мы установили все модули глобально, чтобы не загрязнять нашу папку git папкой node_modules. В Windows может возникнуть проблема доступа к глобально установленным модулям, тогда следует прописать такой параметр среды:

NODE_PATH=C:\Users\Andrey\AppData\Roaming\npm\node_modules

Тут `Andrey` надо поменять на имя пользователя, которое используете вы.
Также модули compression, morgan, serve-favicon, и в принципе errorhandler, которые отвечают за сжатие запроса, логирование, обслуживание favicon и обработку ошибок, не обязательны и используются тут в качестве примера создания более функционального сервера.

Затем создаём такой файл Node-сервера с именем git-server.js:

/* **************************************** */
/* Статический сервер на текущий каталог    */
/* с возможностью просмотров папок и файлов */
/* **************************************** */
var connect = require('connect');
var errorhandler = require('errorhandler');
var compression = require('compression');	// gzip/deflate
var morgan = require('morgan'); // logger
var favicon = require('serve-favicon');	// favorite icon
var serveIndex = require('serve-index');	// directory
var serveStatic = require('serve-static');	// static
 
var fs = require('fs');
var marked = require('marked');
 
// MIDDLEWARE: отдаём запрошенный файл .md как .html
var any_md = function(req, res, next){
 // это md-файл?
 if(req.url.toLowerCase().slice(-3) == '.md') {
   fs.readFile('.' + req.url, function(err, data){
    if(err) return next(err);
    // преобразуем MD -> HTML и отсылаем клиенту
    var html = '<!doctype html>\n<html lang="en">\n' +
    '<head>\n\t<meta charset="utf-8">\n\t<title>' + 
    req.url.slice(1) + '</title>\n</head>\n' + 
    '<body>\n' + marked(data.toString()) + '\n</body>\n</html>';
 
    res.writeHead(200, {
       'Content-Length': Buffer.byteLength(html),
       'Content-Type': 'text/html; charset=utf-8',
    });
    res.end(html);
   });
 }
 else
  next();
};
 
var app = connect()
.use(morgan('combined'))
.use(favicon('./favicon.ico'))
.use(any_md)
.use(compression({level: 3, memLevel: 5}))
.use(serveStatic('.'))
.use(serveIndex('.', {'icons': true}));
 
//if (process.env.NODE_ENV === 'development') {
// такую обработку ошибок использовать
// только при разработке и тестинге 
app.use(errorhandler());
//}
 
app.listen(80, function(){
	console.log('Server started at localhost port 80');
});

Для использования модуля favicon‘а закиньте файл favicon.ico сюда же, в каталог git, если лень, закомментируйте строчку `.use(favicon(‘./favicon.ico’))`.

Итак, запускаем наш сервер:

node git-server.js

Сервер работает по адресу localhost, порт 80 (в Linux для использования этого порта могут понадобиться права root, поэтому лучше поменять порт на 3000, например).

Теперь заходим браузером по адресу localhost (если мы используем порт 80 его тут указывать не нужно) и видим список папок git-проектов. Зайдя в какую-нибудь, где есть файл README.md (или любой md-файл), щёлкнем на нём и увидим его как обычный HTML-файл в браузере.

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

Но главное – это любовь и хорошее настроения, блин.

bcrypt в NodeJS в Windows 10 Home и Linux Mint

Я работаю с nodejs в Windows 10 Home (параллельно иногда загружаюсь в Linux Mint, но редко).

Изучаю книгу `Node.JS в действии`, она, к сожалению, в некоторых местах устарела, но в целом даёт представление о теме.

Итак, в главе 9 нам нужен был brcypt, но простой npm install bcrypt –save завершился с ошибкой.
Пошарив инете пару минут, я понял, что просто так его не установить, и я уже думал проверять примеры в Linux Mint‘е своём любимом, но наткнулся здесь: http://stackoverflow.com/questions/14573488/error-compiling-bcrypt-node-js

Оказывается, bcrypt можно заменить bcrypt-nodejs, который у меня установился без проблем за пару секунд.
Далее по теме увидел такую надпись: The performance is a lot slower though, то есть, мол, производительность гораздо ниже, и даётся ссылка на https://github.com/adrianblynch/bcrypt-vs-bcrypt/blob/master/index.js.

Там тестятся следующие bcrypt пакеты для nodejs:

И даётся простенький скрипт-тестирование (его мы дополним и рассмотрим ниже).

Можно запустить, потестить какие результаты даст, сделаю это через какое-то время в Linux Mint’е (т.к. под свою Windows bcrypt я не установил и не буду заморачиваться, время терять).

Но в этом тесте нет bcrypt-nodejs, я его добавлю тогда, ОК, и результаты позже выведу **** обещанного три года ждут. 🙂

Но какова мораль сей басни? Nodejs настолько стремительно развивающийся проект со столькими вовлеченными и увлеченными пользователями, что для любой более-менее известной и популярной либы есть несколько решений под эту удивительную платформу. И если какая-то либа по тем или иным причинам не подойдёт (как например в нашем случае с bcrypt под Windows 10 (8, 8.1, 7 да любой наверное), мы с большой вероятностью можем найти полноценную замену.

Например, для mongodb есть mongoose, и есть monk, для sqlite куча пакетов, и т.д.

А почему стремительно развивающийся? Например, на оф.страничке Express (http://expressjs.com/en/guide/migrating-4.html) есть устаревший уже пример с multer (обработка запросов multipart/form-data) – там приводится пример для работы с “multer”: “^0.1.3”, а сейчас уже есть multer 1.1.0 (на 4 февраля 2016 года – 2016-02-04), который не совместим с указанным multer‘ом, то есть он не может напрямую выступать в качестве middleware теперь, а надо использовать по особому его методы single, array и т.п. (http://stackoverflow.com/questions/31495499/multer-configuration-with-app-use-returns-typeerror/31495796#31495796):

multer({dest:'./uploads/'}).single(...)
multer({dest:'./uploads/'}).array(...)
multer({dest:'./uploads/'}).fields(...)

На сим всё, откланиваюсь – за мной ещё тесты производительности, если не забуду. )))

Тесты производительности различных пакетов bcrypt для NodeJS

Итак, что мы делаем?
Перезагржаемся в LinuxMint, смотрим систему:

$ uname -a
Linux justy 3.13.0-51-generic-tuxonice #84~ppa1-Ubuntu SMP
Wed Apr 29 19:39:16 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

Создаём папку, в ней nodejs-проект

$ mkdir bcrypt-bench
$ cd bcrypt-bench/
$ npm init
...
... - все параметры можно оставить по умолчанию,
они в принципе не играют большой роли здесь

Инсталлируем нужные пакеты с добавлением в packaje.json (флаг –save)

$ npm install bcrypt bcryptjs twin-bcrypt bcrypt-nodejs commander --save
 
> bcrypt@0.8.5 install /home/justy/nodejs/bcrypt-bench/node_modules/bcrypt
> node-gyp rebuild
 
make: Вход в каталог `/home/justy/nodejs/bcrypt-bench/node_modules/bcrypt/build'
  CXX(target) Release/obj.target/bcrypt_lib/src/blowfish.o
  CXX(target) Release/obj.target/bcrypt_lib/src/bcrypt.o
  CXX(target) Release/obj.target/bcrypt_lib/src/bcrypt_node.o
  SOLINK_MODULE(target) Release/obj.target/bcrypt_lib.node
  COPY Release/bcrypt_lib.node
make: Выход из каталога `/home/justy/nodejs/bcrypt-bench/node_modules/bcrypt/build'
bcrypt-bench@1.0.0 /home/justy/nodejs/bcrypt-bench
├─┬ bcrypt@0.8.5
│ ├── bindings@1.2.1
│ └── nan@2.0.5
├── bcrypt-nodejs@0.0.3
├── bcryptjs@2.3.0
├─┬ commander@2.9.0
│ └── graceful-readlink@1.0.1
└── twin-bcrypt@2.1.1
 
npm WARN EPACKAGEJSON bcrypt-bench@1.0.0 No repository field.

В результате наш package.json будет выглядеть примерно так:

{
  "name": "bcrypt-bench",
  "version": "1.0.0",
  "description": "Simple benchmarking for varios nodejs bcrypt packages",
  "main": "test.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "brcypt",
    "bench",
    "test"
  ],
  "author": "adrianblynch",
  "license": "MIT",
  "dependencies": {
    "bcrypt": "^0.8.5",
    "bcrypt-nodejs": "0.0.3",
    "bcryptjs": "^2.3.0",
    "commander": "^2.9.0",
    "twin-bcrypt": "^2.1.1"
  }
}

Теперь создаём скрипт test.js, скопировав его отсюда: https://github.com/adrianblynch/bcrypt-vs-bcrypt/blob/master/index.js и добавив в него пакет bcrypt-nodejs:

var bcrypt = require('bcrypt');
var bcryptJS = require('bcryptjs');
var twinBcrypt = require('twin-bcrypt');
var bcryptNodeJs = require('bcrypt-nodejs');
 
var commander = require('commander');
 
commander
.option('-r, --rounds [num]', 'Number of rounds to use', parseInt)
.option('-i, --iterations [num]', 'Number of iterations to use', parseInt)
.parse(process.argv);
 
var password = "password";
var rounds = commander.rounds || 12;
var iterations = commander.iterations || 10;
var hash, start, end, i, total;
 
console.log("Bcrypts ready? Fight!");
 
// bcrypt
 
total = 0;
 
for (i = 0; i < iterations; i++) {
	start = new Date();
	hash = bcrypt.hashSync(password, bcrypt.genSaltSync(rounds));
	end = new Date();
	total += (end - start);
}
 
console.log("bcrypt - " + iterations + " iterations took " + total + "ms which is an average of " + parseInt(total / iterations) + "ms each");
 
// bcryptjs
 
total = 0;
 
for (i = 0; i < iterations; i++) {
	start = new Date();
	hash = bcryptJS.hashSync(password, bcryptJS.genSaltSync(rounds));
	end = new Date();
	total += (end - start);
}
 
console.log("bcryptjs - " + iterations + " iterations took " + total + "ms which is an average of " + parseInt(total / iterations) + "ms each");
 
// twin-bcrypt
 
total = 0;
 
for (i = 0; i < iterations; i++) {
	start = new Date();
	hash = twinBcrypt.hashSync(password, twinBcrypt.genSalt(rounds));
	end = new Date();
	total += (end - start);
}
 
console.log("twin-bcrypt - " + iterations + " iterations took " + total + "ms which is an average of " + parseInt(total / iterations) + "ms each");
 
// bcrypt-nodejs
 
total = 0;
 
for (i = 0; i < iterations; i++) {
	start = new Date();
	hash = bcryptNodeJs.hashSync(password, bcryptNodeJs.genSaltSync(rounds));
	end = new Date();
	total += (end - start);
}
 
console.log("bcrypt-nodejs - " + iterations + " iterations took " + total + "ms which is an average of " + parseInt(total / iterations) + "ms each");

Всё готово для запуска тестов:

$ node test.js
Bcrypts ready? Fight!
bcrypt - 10 iterations took 2813ms which is an average of 281ms each
bcryptjs - 10 iterations took 8523ms which is an average of 852ms each
twin-bcrypt - 10 iterations took 8650ms which is an average of 865ms each
bcrypt-nodejs - 10 iterations took 8144ms which is an average of 814ms each

Как видим, стандартный bcrypt практически в 3 раза быстрее своих собратьев,
что не удивительно, так как он использует пре-компилированную версию, в то время как остальные написаны на чистом JavaScript и прогоняются ч/з интерпретатор V8, как бы он быстр не был.

Вторая мораль сей басни такова – если в нашем проекте требуется много и часто хэшировать с помощью алгоритма bcrypt’а, следует предпочесть bcrypt.

Сладкого чая и вкусной слойки на столе! С цукерками в вазочке.

Используем Hurricane Electric Free DNS Management

Введение

Здравствуйте.

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

В этом случае у нас как правило два выхода – заказать услуги DNS на стороне за небольшую плату (обычно их предоставляют сами же компании, занимающиеся сдачей в аренду серверов), либо воспользоваться одним из множества бесплатных DNS-сервисов.

Одним из таких сервисов является Hurricane Electric Free DNS Management – https://dns.he.net/. Здесь мы попытаемся описать, какие основные настройки для своего домена требуется задать, и как это сделать. Сейчас (на июнь 2015) Hurricane Electric позволяет добавлять до 50 доменов бесплатно, включая обратно-проксированные: At this time, we are limiting the free service to 50 zones which includes your reverse zones (if any).

Начнём!

Итак, заходим на https://dns.he.net, регистрируемся и добавляем новый домен: mydomain.ru
Система может задуматься на какое-то время, а потом выдать надпись типа того, что домен не делегирован им. Правильно, для того, чтобы наш домен работал через их DNS, надо у соответствующего регистратора нашего домена прописать новые NS-зоны: ns1.he.net, ns2.he.net, ns3.he.net, ns4.he.net и ns5.he.net
Это можно сделать сразу или потом, когда мы добавим все нужные DNS-записи.

ОК, теперь заходим в редактор нового домена:
HE DNS_2
и видим, что у нас уже добавлены записи SOA и NS.
HE DNS_3

В первую очередь добавляем две A-записи: mydomain.ru и www.mydomain.ru, которые должны указывать на ip-адрес сервера, где хостится домен. Жмём New-A в меню вверху, в качестве Name пишем адрес домена mydomain.ru, а в качестве IPv4 Address – ip адрес сервера в формате IPv4. Остальное можно оставить по умолчанию. Если вы захотите добавить поддержку домена для IPv6, добавьте AAAA-записи для него.

Теперь добавляем MX-запись для почты: New MX в верхнем меню. Name: mydomain.ru, Priority: 10, Hostname: mail.mydomain.ru

Добавим CNAME-запись: Name: mail.mydomain.ru, Hostname: mydomain.ru
Это позволяет при доступе к mail.mydomain.ru обратиться к mydomain.ru

Внимание! Я обнаружил, что почта на некоторые домены (например, gmx.de или mail.com),с нашего сервера не проходит, и мы получаем bounceback-письмо примерно такого содержания:

<akstandilliya@mail.com>: host mx01.mail.com[74.208.5.22] said: 550-Requested
action not taken: mailbox unavailable 550 invalid DNS MX or A/AAAA resource
record (in reply to MAIL FROM command)

Оказывается, не позволяется делать CNAME-записи для своих MX адресов, как мы это сделали сперва (см. выше перечёкнутый текст), согласно RFC2181: https://tools.ietf.org/html/rfc2181#section-10.3

Решение проблемы – удаление CNAME-записи для своего MX адреса (mail.mydomain.ru) – при условии, что мы её раньше добавили, и добавление новой A записи с адресом mail.mydomain.ru, указывающей на IP-адрес нашего сервера.

Добавим CNAME запись для www.mydomain.ru – mydomain.ru

Теперь нам надо добавить TXT-запись для удовлетворения различных анти-спам проверок при отправке почты с нашего домена.

Жмём New TXT. Name: mydomain.ru Text data: v=spf1 ip4:127.0.0.1 +a +mx +ip4:127.0.0.1 ?all
Здесь 127.0.0.1 надо поменять на ip-адрес вашего сервера с доменом, который мы указывали при добавлении A-записи.

В итоге наши DNS-записи для домена в общем случае могут выглядеть так:
HE DNS_4

Вот и всё, общий случай добавления DNS-зоны для домена. Теперь, как и писалось выше, надо направить NS-записи регистратора домена на ns1.he.net, ns2.he.net, ns3.he.net, ns4.he.net и ns5.he.net. Теоретически можно прописать любые два адреса, но лучше больше!

Удачи Вам и крепкого чая на столе!

nginx+php-fpm под Windows

Здравствуйте!

nginx

Apache – король веб-серверов, если можно так сказать. Но на пятки ему наступает даже не IIS от Microsoft, не lighttpd, а nginx (произносится как Энджин-Икс, engine с английского мотор, двигатель) нашего соотечественника Сысоева.

Чем он хорош? Говорят, что статика отдаётся гораздо быстрее, чем у Апача, да и динамика я думаю тоже. Он жрёт меньше ресурсов, что может быть критически важно для нагруженных серверов. Раньше мнгоие применял связку nginx+Apache – nginx для отдачи статики (рисунков, js/css etc.), а Апач – для отдачи динамики (PHP/Perl/Python/Ruby etc.). Но теперь nginx можно применять без Апача, так как для него появилось куча плагинов и дополнений, поэтому вместо связки nginx+Apache+PHP (мы тут говорим о PHP-среде) легко настроить просто nginx+php-fpm. Ладно, об нём написано куча литературы, не буду повторяться, опишу лишь процесс установки nginx+php-fpm под Виндовс (Windows).

Хотя, конечно, nginx органичней всего чувствует себя в FreeBSD и Linux (любой Unix-среде, наверное), под Винду он тоже неплохо работает, по крайней мере я его у себя на домашнем компе установил, чтобы тестировать некоторые штуки.

Итак, процесс установки/первичной настройки. Этот процесс расписан здесь: http://nginx.org/ru/docs/windows.html
я приведу лишь выжимку.

Смотрим доступные версии nginx под windows здесь: http://nginx.org/en/download.html
Сейчас есть версия 1.8.0, несколько месяцев назад я устанавливал 1.6.2, которая и сейчас у меня работает.
Итак, скачиваем текущую версию под windows: http://nginx.org/download/nginx-1.8.0.zip

Для удобства примем то, что я пользую сейчас:
Создаём папку C:\usr. Заходим в неё и распаковываем nginx-1.8.0.zip здесь (это можно проделать через GUI-интерфэйс).
Затем запускам териминал и заходим:

> C:
> cd C:\usr\nginx-1.8.0
> start nginx

Тут Виньда может выкинуть окошко с предупреждением (см. скриншот), что nginx пытается получить доступ в сеть. Мы конечно же разрешаем.

allow nginx to network

Проверяем, запущен ли nginx и видим результат:

>tasklist /fi "imagename eq nginx.exe"
 
Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
nginx.exe                     1336 Console                    1      6,440 K
nginx.exe                     3136 Console                    1      6,268 K
nginx.exe                     4864 Console                    1      6,496 K
nginx.exe                     6544 Console                    1      5,872 K

Остановим nginx нормально: nginx -s quit. Есть ещё несколько полезных команд для nginx:
nginx -s stop – останов nginx в любом случае (применяется, если nginx -s quit не сработает).
nginx -s reload – перезагрузка .conf файлов (конфигурации)
nginx -s reopen – переоткрытие .log файлов (полезна, если мы удалили или переместили логи при работающем nginx).

Итак, мы остановили nginx сейчас, так как прежде чем его запускать, надо правильно настроить .conf файлы. Они расположены в папке conf. Стандартный файл настройки – nginx.conf, из него директивой include могут подсоединяться другие файлы из этой (впрочем, и из любой другой) папки.
Например, директива include mime.types; в секции http присоединит файл mime.types, в котором находится определения всех стандартных MIME-типов. Впрочем, сам конфиг я обсуждать здесь не буду, о нем много написано в инете, приведу лишь пример своего конфига с краткими пояснениями.

Предупреждение: это конфиг для моей домашней тестовой среды. Для рабочего сервера требуется более тонкая настройка.

worker_processes  1;

error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;
    
    #
    # Формат лога делаем как у Апача
    #
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  logs/access.log  main;

    # sendfile        on;
    #tcp_nopush     on;
  
    keepalive_timeout  65;

    # Сжатие gzip на лету
    gzip  on;

    server {
        # listen       801;
        server_name  localhost;
				autoindex on; # allow dir listing
				root E:/sites;
				
        #charset koi8-r;
        #access_log  logs/host.access.log  main;

	#
        # запретим доступ ко всем файлам, начинающимся с точки 
	#
        location ~ /\. {
            deny  all;
        }

        location / {
            root   E:/sites;
            index  index.html index.htm index.php;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

	#
        # передаем все PHP скрипты серверу FastCGI, слушающему на 127.0.0.1:9123
        #
        location ~ \.php$ {
            root           E:/sites;
            fastcgi_pass   127.0.0.1:9123;
            fastcgi_index  index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
    }
}

Итак, в этом конфиге большинство настроек оставлено по умолчанию, а корень сайтов у нас в E:\sites, что в первую очередь делает команда root E:/sites. Обратите внимание на прямые слэши в стиле Unix в пути к папкам и файлам – это требование nginx, даже для Windows-версии.

Теперь можно запускать nginx (start nginx), если мы его останавливали перед этим, либо применить команду nginx -s reload, чтобы сервер перечитал конфиги без остановки своей работы, что полезно при работающем внешнем сайте.

Итак, теперь надо настроить PHP-FPM для Windows. Учтите, что мы уже в нашем конфиге сделали его поддержку на порту 9123 (под-секция location ~ \.php$)

PHP-FPM для Windows

1. Скачиваем свежий (или версию по выбору) .zip-архивчик с http://windows.php.net/download/. Архивчик должен быть VC11/VC9, что содержит в себе FastCGI-файл (phpcgi.exe).
2. Создаем папку в C:\usr, например с именем php-5.6.9 и распаковываем в неё содержимое архива.
3. Редактируем файл php.ini в соотв. со своими предпочтениями, единственное, убедиться, что у нас есть такая строка:

# nginx security setting
cgi.fix_pathinfo=0

Она закрывает одну из старых уязвимостей nginx. Далее можно подключить PHP-модули по вкусу, расскоментировав их в соотв. секции и произвести другие настройки.

4. Теперь создадим .bat-файл, например php-fpm-start.bat с таким содержимым:

@echo off
echo Starting PHP FastCGI...
set path=c:\usr\php-5.6.9;%PATH%
C:\usr\php-5.6.9\php-cgi.exe -b 127.0.0.1:9123 -c C:\usr\php-5.6.9\php.ini

и запустим его. Если мы его запускаем из GUI, то появится окно консоли и останется открытым, придётся с этим смириться.

Всё, наш сервер мы уже давно настроили на соединение с этим PHP процессом.

Для проверки создаём файл index.php в папке E:\sites с таким содержимым:

<?php
phpinfo();

Теперь направляем наш любимый браузер на http://localhost и видим такую примерно картину:

phpinfo() начало

phpinfo

phpinfo() с версией nginx

phpinfo nginx

Здесь же можно посмортеь переменные среды и подключаемые модули. Для совместимости nginx создет переменные среды, совместимые с апачевскими, например _SERVER[“SERVER_NAME”], _SERVER[“DOCUMENT_ROOT”], _SERVER[“REQUEST_URI”], _SERVER[“SCRIPT_NAME”] и т.д., и мы можем использовать их в своих PHP-сценариях, как делали это в случае с Апачем.

До свидания!

Windows 8.1 LE лицензия и мультизагрузочная флэха

Давно мечтал приобрести Windows 8.1, сам не знаю почему.
Эту – http://www.softkey.ru/catalog/program.php?ID=142751&ndcn=L18vTi0xMTQyNzUxKzI0ODg0NjA0#buy

Купил-таки за 3800 что ли рублей со скидкой! ))) Меня смущала аббревиатура LE в названии, то что это означает скорее всего Light Edition особой ясности не вносило. 5-минутный поиск по инету ничего вразумительного не просветил, единственное – нашел пару вопросов без ответов, чтобы же всё таки это за зверь такой LE и чем он отличается от не LE?

Сейчас пользуюсь этой LE уже с пару месяцев, никаких ограничений не заметил, кроме возможно обедненного экрана О системе с ссылкой – поставить дополнительные компоненты. Вот за них я так понял надо доплатить, но что это за компоненты, выяснить не захотел я. У меня и так всё есть, а что надо, я найду или в OpenSource или приобрету за валюту.

Итак под это дело, скачав образ по ссылке в письме после покупки на Softkey (впрочем скачать винду может любой желающий, только ключ надо будет вводить лицензионнный позднее – а у меня он был, спасибо Softkey и моим 3800 рублям (плюс-минус 80), решил я забацать мультизагрузочную флэху, чтобы уж не только там виньда была восьмушка для установки/переустановки, но и несколько интересных ситсем – линухи и тому подобное.

Благо флэшка на 16 гигов болталась без дела, надо было её оприходовать.

Сейчас создать мультризагрузочную флэху даже без распаковки iso образов – дело ну не пары, но десятка-двух минут точно.

Заходим на сайт http://www.rmprepusb.com/ – ох, тут много всяких плюшек для бутовой флэхи.

Нас тут же встречает надпись –
Want to boot everything from a USB drive? Visit the new ‘sister’ site at www.easy2boot.com

Ну ладно, как раз то что нам нужно – уходим на www.easy2boot.com

Тут же чуть ниже смотрим видос, где вроде как всё подробно разжевывается.

Мне нужно было запихнуть на флэшку 16 гигов – образ Windows 8.1 для установки и пару линухов – Кнопикс, Ебунту и т.п. Ну может ещё пару образов для экспериментов.

Что в итоге мне удалось – см. скриншот ниже в посте. Easy2boot позволяет создать загрузочную флэшку, просто запихав туда iso образы и при минимальном редактоировании загрузочного grub-меню (большинство образов, особенно линух-подобных, оно находит автоматом.

Образ же Windows надо запихивать в отдельный каталог.

Сейчас попробую подробнее всё расписать, как мне удалсь всё сделать так что всё рабоатет (кроме Андроида, что-то он на моем компе не пошёл, графика искаженная получается – в эмуляторе врооде работал нормально).

1. Нам всё же надо скачать и установить RMPrepUSB с сайта: http://www.rmprepusb.com/

2. Скачиваем и распаковываем Easy2Boot с сайта: http://www.easy2boot.com/download/

3. Вставляем свою флэшку и под админом запускаем файл _ISO\docs\Make_E2B_USB_Drive\MAKE_E2B_USB_DRIVE.cmd из распакованного архива (для Линукса есть такой же установочный файл по пути: /_ISO/docs/linux_utils/fmt.sh). У нас должна стоять RMPrepUSB – иначе ничего не выйдет.

Во время работы скрипта нам придётс яответить на несколько сложных (шутка) вопросов, вот ответы:
– Выбор номера флэшки для работы – она будет отформатирована. Номера перечилсяются со словом Drive, например Drive 2
– Потом надо ответить Y (да, мы согласны отформатировать именно эту флэшку).
– Потом нажимаем n (N-латинское), чтобы отформирировать флэшку под NTFS. В появившемся окошке нажимаем ОК.

Теперь ждём и в конце экран консоли должен стать зеленым, и надпись – Finish OK. Скрипт в частности перепишет Easy2Boot на флэшку и создаст необходимый загрузчик. Дальше мы уже работаем непосредственно с нашей флэшкой!

4. Инсталляторные ISO Windows запихиваем в соотв. каталоги в папку \_ISO\WINDOWS\ на флэшке – для каждой версии Винды есть соотв. папка, туда и надо бросать, очевидно. Я использовал Windows 8.1 оф. ISO-образ.

5. А вот Линукс-based ISO мы можем бросать либо в папку \_ISO\MAINMENU\, либо в папку \_ISO\LINUX\
Я лично бросал их в папку MAINMENU, папка LINUX у меня пуста.
Теоретически любой Линукс дистро должен работать отсюда (у меня всё запускалось нормально), а список протестированных ISO и некоторые нюансы их правильного подключения можно найти по адресу http://www.easy2boot.com/add-payload-files/list-of-tested-payload-files/ . Так же здесь можно найти и подключение некоторых нестандартных дистрибутивов, в частности например android_x86.
Я лично пытался использовать Andriod_x86 в постоянном режиме (по инструкции с этой страницы), но он у меня что-то не заработал – при запуске шли полосы на экране вместо больших букв Android и всё зависало потом наверное.

6. И последний шаг, но важный – надо все образы на флэшке сделать неразрывными (contiguous), иначе они не запустятся. Для этого нам также пригодится скачанный и установленный на первом шаге RMPrepUSB.

Запускам его (он требует права админа), убеждаемся что в верхнем списке выбрана наша флэшка и нажимаем Ctrl+F2 – горячую клавиши для пункта меню Drive – Make All Files On Drive Contiguous.

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

Или о неуспешной… Да, у меня был такой случай – я попытался запихнуть ещё один ISO Windows 7 на 16 Gb флэшку, а потом проделывал эту операцию, но у меня ничего не получалось – программа WinContig (её использует RMPrepUSB) писала, что этот новыый образ не contiguous, как я ни пытался что-то делать. Оказывается, у меня на фэшку было мало места, а для того чтобы сделать файлы contiguous (неразрывными) надо иметь достаточно места для копирования одного образа, а так как образы бывают большими 4-5 Гигов, то отсюда и проблема. но она как я понимаю, может возникнуть только втом случае (как у меня), если удаляешь-копируешь образы на флэшку, забивая её почти полностью, а потом пытаешься делать их неразрынвнми (contiguous). Может помочб форматирование флэшки, проделвание всех операций с Easy2Boot и запихиванием образов снова на неё, тогда теоретически они должны встать нормально.

Итак, у нас есть флэшка с Easy2Boot, Windows 8.1 ISO и несколько разных Linux-дистро ISO. Заметьте, что распаковать эти ISO не нужно, они копируются на флэшку как есть! И Easy2Boot как заявляется позволит нам запускть прктический любой из них.

Вот какое меню получилось у меня сейчас (сделал скриншот ч/з эмулятор QEMU – эту возможность в частности предоставляет всё та же чудесная RMPrepUSB, удивительная программа!):

easy2boot

Да, благодаря Easy2Boot я без проблем и быстро ознакомился (и продолжаю также удобно знакомиться) с некоторыми Linux-live дистрибутивами, установил себе новенькую Windows 8.1 (хотя в этом году скоро уже наверное перейду на 10, тем более её Майкрософт вроде как бесплатно всем раздаёт), установил в январе себе Кубунту, недавно снес её – она глюкавая оказалась, установил недавно Linux Mint Cinnamon Edition, которым сейчас вполне доволен и счастлив сам по себе!

Допиливаем VKontakteApi (WP-плагин)

Всё отлично!

Используем неплохой плагин для WordPress’а от Забродского Евгения (kowack): VKontakte API.

Плагин позволяет наряду с обычными комментариями вставлять и видеть комментарии VKontakte и Facebook.

Бонусом идёт также возможность добавлять кнопки соц.сетей – PlusOne button, Tweet button, Mail.ru+Ok.ru button, Ya.ru button.

Для Вконтакте имеется также возможность добавлять кнопки Мне нравится и Поделиться.

Настроить плагин также относительно легко – достаточно зарегистрировать свои приложения в VK и FB, ввести их ключи и админский ключ для плагина. Все ссылки даются тут же на соотв. страницах настройки плагина.

В общем плагин неплохой, можно сказать отличный, но нам хотелось бы его немного переделать.

Что не так?

Плагин выводит комменты VK,FB и WP блоками, если один блок виден, то другие скрыты, появление блока происходит с медленным эффектом, что немного имхо раздражает.

Кроме того, почему-то кнопки и надпись Comments: на английском языке, хотя наш блог на русском (может это из-за того что админку мы юзаем на английском? не знаю, не проверял).

Мы хотели бы, чтобы блоки были все сразу видны, то есть идёт первым VKontakte блок с комментариями, под ним – Facebook’чный блок комментариев, и уже под ним – стандартный WP (Word Press’овский блок с комментариями).

И надписи желательно переделать на русский насколько это возможно.

За работу!

Итак, заходим в папку wp-content/plugins/vkontakte-api.

Это родная папка плагина. Откроем файл js/callback.js и сразу видим блок Comments switcher с функциями showVK(),showFB(),showWP().

По названиям функций можно судить, что именно эти функции отвечают за появление/скрытие комментариев.

Нам достаточно закомментировать внутренность этих функций (но не сами функции конечно), чтобы комментарии были все видны. Наша задача выполнена? Да, почти, но по нажатию кнопок Vkontakte, Facebook и Site ничего не происходит.

Да, можно их убрать, но лучше наверное по их нажатию делать переход на соотв. блоки комментов.

Для этого внутри фуннкции добавляем простой переход на хэш-таг с соотв. ид.

Для VKontakte #vkapi, для Facebook #fb-comments (этого ид изнчально нету, ниже написано, как его добавить), для Site #comments.

Таким образом весь модернизированный блок будет выглядеть так:

// Comments switcher
function showVK(Tshow, Thide) {
/*    if (!Tshow && Tshow != 0) Tshow = 1000;
    if (!Thide && Thide != 0) Thide = 1500;
    jQuery("#vkapi").show(Tshow);
    jQuery(".fb-comments").hide(Thide);
    jQuery("#comments").hide(Thide);
    jQuery("#respond").hide(Thide);
*/
    if(Tshow == 1) window.location.hash = 'vkapi';
 
}
function showFB(Tshow, Thide) {
/*    if (!Tshow && Tshow != 0) Tshow = 1000;
    if (!Thide && Thide != 0) Thide = 1500;
    jQuery(".fb-comments").show(Tshow);
    jQuery("#vkapi").hide(Thide);
    jQuery("#comments").hide(Thide);
    jQuery("#respond").hide(Thide);
*/
    window.location.hash = 'fb-comments';
}
function showWP(Tshow, Thide) {
/*    if (!Tshow && Tshow != 0) Tshow = 1000;
    if (!Thide && Thide != 0) Thide = 1500;
    jQuery("#comments").show(Tshow);
    jQuery("#respond").show(Tshow);
    jQuery("#vkapi").hide(Thide);
    jQuery(".fb-comments").hide(Thide);
*/
    window.location.hash = 'comments';
}

Для чего для контакта мы добавили условие if(Tshow == 1)?

Дело в том, что при заходе на страницу вызывается первый раз функция showVK() (если включен показ сначала комментов VK, а не FB). И тогда из-за исправленого скрипта происходил бы перескок сразу на комменты VK, что не есть хорошо, так как по умолчанию читатель ещё не читал статью/пост.

Если же у Вас включен первым показ комментов от Facebook, тогда это условие надо добавить в его блок. Для универсальности наверное его можно добавить сразу в оба блока.

Как говорилось выше, нет хэша #fb-comments. Чтобы его добавить, откроем файл vkapi.php в папке плагина, найдём там функцию add_fb_comments() и перед строкой class=’fb-comments’ (или после неё, не важно) добавим строку id=’fb-comments’.

Таким образом функция add_fb_comments() станет выглядеть так:

function add_fb_comments()
{
		$width = get_option('vkapi_comm_width');
		$limit = get_option('vkapi_comm_limit');
		$url = get_permalink();
		echo "
	<div style='background:white'
			 id='fb-comments'
			 class='fb-comments'
			 data-href='{$url}'
			 data-num-posts='{$limit}'
			 data-width='{$width}'
			 colorscheme='light'>
	</div>";
}

Сохранить, Upload, Refresh – вуаля, всё работает.

А руссификация этих кнопок и надписи Comments?

Языковость у этого плагина происходит так:

$text = __('Comments:', $this->plugin_domain);

Комментируем соотв. строку и добавляем под ней свою такую:

$text = 'Комментарии: &nbsp;&nbsp;';

А &nbsp;&nbsp; я уже отсебя добавил, это отсебятина какая-то.

Это мы находим в функции add_tabs_button_start().

Аналогичные действия проделаем для функций add_tabs_button_vk(), add_tabs_button_fb(), add_tabs_button_wp() и называем кнопки как хотим. Я назвал ВКонтакте, Facebook и Сайт соответственно.

Всё, конец. Всё работает? Да!

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

До свидания, друзья!