barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

среда, 23 ноября 2011 г.

Javascript URL encode / decode

Следующий объект предоставляет методы encode() и decode() для, соответственно, кодирования и декодирования строк с использованием URL-метода кодирования.
/**
*
* URL encode / decode
* http://www.webtoolkit.info/
*
**/

var Url = {

// public method for url encoding
encode : function (string) {
return escape(this._utf8_encode(string));
},

// public method for url decoding
decode : function (string) {
return this._utf8_decode(unescape(string));
},

// private method for UTF-8 encoding
_utf8_encode : function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";

for (var n = 0; n < string.length; n++) {

var c = string.charCodeAt(n);

if (c < 128) {
utftext += String.fromCharCode(c);
}
else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}

}

return utftext;
},

// private method for UTF-8 decoding
_utf8_decode : function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;

while ( i < utftext.length ) {

c = utftext.charCodeAt(i);

if (c < 128) {
string += String.fromCharCode(c);
i++;
}
else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
}
else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}

}

return string;
}

}
 Важно то, что используется стандарт RFC 3986, кодирующий пробел как "%20", а не как "+" (так делается при кодировании в соответствии с типом контента application/x-www-form-urlencoded). При необходимости получить строку, закодированную именно как application/x-www-form-urlencoded, необходимо в полученной с помощью метода encode() строке выполнить замену "+" на "%2B", а "%20" - на "+".  

Windows: управление сертификатами пользователя не через Internet Explorer

Управлять сертификатами пользователя можно через IE (Свойства обозревателя -> Содержание -> Сертификаты). Но можно это делать и без него: Выполнить -> mmc -> Файл -> Добавить или удалить оснастку -> Найти в списку "Сертификаты" и нажать "Добавить", а потом - "Ок". В дереве консоли появится пункт "Сертификаты", позволяющий управлять сертификатами. Параметры консоли необходимо сохранить в msc-файл, запуская который Вы будете попадать в только что созданную консоль управления сертификатами.

вторник, 22 ноября 2011 г.

PHP Startup: Unable to load dynamic library '.../php_pgsql.dll' - Не найден указанный модуль

Проблема:
При попытке запуска apache + php под Windows с подключенным в php.ini расширением php_pgsql.dll в логи апача вываливает ошибка:
PHP Startup: Unable to load dynamic library '.../php_pgsql.dll' - Не найден указанный модуль
Ну и модуль, естественно, не загружается.
Причина:
Php не может найти динамические библиотеки Postgres, необходимые расширению для работы.
Решение:
Добавить директории bin и lib установки Postgres в системный PATH (например, E:\Programs\Postgres8.3\lib;E:\Programs\Postgres8.3\bin).

воскресенье, 20 ноября 2011 г.

Как мне НЕ удалось подружить WSO2 WSF/PHP 2.1.0 и 1С-Битрикс Веб-Окружение 2.1.

Собственно возникла необходимость использования внутри компонента 1С-Битрикс функционала SOAP-клиента, и для этого был выбран WSO2 WSF/PHP (http://wso2.org/library/wsf/php).
Для начала был скачан бинарник WSF/PHP версии 2.1.0, распакован (в директорию "F:\Install\wso2-wsf-php-bin-2.1.0-win32\"), wsf.dll был положен в папку "apache2\zendserver\lib\phpext\" относительно директории установки окружения 1С-Битрикс. В php.ini Битрикса (apache2\zendserver\etc\php.ini) были внесены следующие изменения:
...
[Zend]
include_path=".;F:\Install\wso2-wsf-php-bin-2.1.0-win32\scripts"
...
extension=php_xsl.dll
extension=wsf.dll
...
wsf.home="F:\Install\wso2-wsf-php-bin-2.1.0-win32\wsf_c"
wsf.log_path="F:\Install\wso2-wsf-php-bin-2.1.0-win32\wsf_c\logs"
wsf.log_level=3
wsf.rm_db_dir="F:\Install\wso2-wsf-php-bin-2.1.0-win32\wsf_c"
...
Однако при попытке запустить битрикс стала появляться ошибка о том, что не найден файл "php5ts.dll". Действительно, в директории apache2\zendserver\bin можно найти только php5.dll, т.к. php в Битриксе видимо не-threadsafe. Ладно, попробуем подложить туда ещё и php5ts.dll (взят он был из php 5.3.5). Теперь сообщение об отсутствующем php5ts.dll ушло, однако расширение wsf все равно не подключается, а в логах видим:
[20-Nov-2011 17:23:36] PHP Warning:  PHP Startup: wsf: Unable to initialize module
Module compiled with build ID=API20090626,TS,VC9
PHP    compiled with build ID=API20090626,NTS,VC9
These options need to match
 in Unknown on line 0
Теперь build ID модуля конфликтует с версией битриксовского php - у битрикса php non-threadsafe, о чем говорит аббревиатура NTS, а модуль собран для threadsafe (TS). 
Придется видимо собирать WSF из сорцов, благо они есть на wso2.org.
Помимо самих сорцов, пришлось скачать и установить Win32 OpenSSL (http://www.slproweb.com/products/Win32OpenSSL.html), ну и конечно же, понадобилась Visual Studio. Лучше девятка (2008). У меня была только 2010, что в дальнейшем и послужило граблями. Также понадобились исходники и бинарники php, которые были скачаны с php.net (бинарники, правда, были взяты threadsafe, что в дальнейшем послужило проблемой). В принципе, в качестве бинарников можно было взять php из самого Битрикса, однако их там в явном виде не присутствует, т.к. в основе окружения битрикса лежит Zend Server, так что пришлось брать со стороны.
Для того, чтобы собрать не-threadsafe версию WSF/PHP, нужно в configure.in распакованных исходников закомментировать строку:
# ZTS =1
Далее в этом же файле нужно прописать путь к директории установки Open SSL, к исходниками и бинарникам php. В моём случае это выглядело так:
OPENSSL_BIN_DIR = E:\Programs\OpenSSL-Win32
PHP_SRC_DIR = F:\Install\php-5.3.8-src
PHP_BIN_DIR = C:\php\php5.3.8
Перед сборкой необходимо проверить, что директория VC\bin относительно директории установки Visual Studio включена в PATH.
Пробуем собрать, запуская build.bat в директории исходников WSF/PHP, однако получаем ошибку:
f:\install\php-5.3.8-src\zend\zend_config.w32.h(25) : fatal error C1083: Cannot open
include file: '../main/config.w32.h': No such file or directory
Оказывается, прежде чем выполнять build.bat исходников WSF/PHP, нужно запустить в директории исходников php:
buildconf.bat
cscript configure.js
После этого при запуске cscript вылезла ошибка "Отсутствует исполняющее ядро для расширения имени файла ".js"" - см. http://barbitoff.blogspot.com/2011/11/cscript-js.html, потом -  "The application has failed to start bacause mspdb100.dll was not found ..." при попытке вызова cl.exe, пришлось предварительно запустить vcvars32.bat из Visual Studio (см. http://barbitoff.blogspot.com/2011/11/ms-visual-studio-clexe-mspdb100dll-not.html).
Но и тут ждет неудача:
ERROR: bison is required
Идем на http://gnuwin32.sourceforge.net/packages/bison.htm, качаем и устанавливаем Бизон, добавляем путь к его исполняемым файлам (расположены в bin директории) в PATH.
После этого configure.js отработал удачно, создав недостающий ранее файл "main/config.w32.h".
Возвращаемся в исходники WSF/PHP, жмем build.bat, но снова ошибка:
LINK : fatal error LNK1181: cannot open input file 'php5.lib'
Библиотеку линкер ищет в бинарниках php, и, естественно, там её не находит, т.к. бинарники threadsafe, и там есть только php5ts.lib. Берем php5.lib из "apache2\zendserver\bin" Битрикса, кладем в папку dev бинарников php. Снова делаем build.bat... и ура, WSF собрался.
Кладем wsf.dll куда надо, меняем пути в php.ini к новым, только что собранным директориям. Пытаемся запустить Битрикс, и видим в логах:
[20-Nov-2011 21:21:12] PHP Warning:  PHP Startup: wsf: Unable to initialize module
Module compiled with build ID=API20090626,NTS,VC10
PHP    compiled with build ID=API20090626,NTS,VC9
These options need to match
 in Unknown on line 0
Да, теперь не совпадает версия студии. И на этом моменте надо было бы поискать 2008 студию, но я решил обмануть php. В Zend\zend_build.h исходников php поправил 
#define ZEND_BUILD_SYSTEM "," PHP_COMPILER_ID
на 
#define ZEND_BUILD_SYSTEM ",VC9"
Пересобрал WSF/PHP. Модуль наконец-таки загрузился, вот только примеры из дистрибутива не работают, php падает молча, а в логах винды видно:
Имя сбойного приложения: php-cgi.exe, версия: 5.3.2.0, отметка времени: 0x4c0b8710
Имя сбойного модуля: MSVCR90.dll, версия: 9.0.30729.4974, отметка времени 0x4b7a226f
Код исключения: 0xc0000005
Смещение ошибки: 0x0003ae7a
Идентификатор сбойного процесса: 0x20fc
Время запуска сбойного приложения: 0x01cca817c8b93692
Путь сбойного приложения: E:\Programs\Bitrix Environment\Apache2\ZendServer\bin\php-cgi.exe
Путь сбойного модуля: C:\Windows\WinSxS\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4974_none_50940634bcb759cb\MSVCR90.dll
Код отчета: 0845dff7-140b-11e1-8fee-fcf4765882af
Мда, придется все-таки пересобрать 9ой студией, вдруг поможет.
2008 студия поставлена, теперь нужно перезапустить config.js исходников php (на всякий случай), для этого потребуется, чтобы в PATH были директории "Common7\Tools" и "VC\bin" 2008 студии, причем в таком порядке и перед путями к 2010 студии (удобнее менять в данном случае не глобальный PATH системы, а устанавливать PATH командой set).

И да, слеши в путях в php.ini пришлось поставить в другую сторону, как в Unix ("/"), т.к. глупый WSF использует "/" независимо от платформы, конкатенируя свои пути с путями из php.ini.

Однако и после всех этих манипуляций собранная 2008-ой студией библиотека WSF работать отказалась, с теми же сообщениями в логах, что и собранная 2010-ой.

Плюнув на самостоятельную сборку non-threadsafe библиотеки WSF, я развернул битрикс не в его родном веб-окружении, а на wamp 2.2a, благо там php threadsafe и собран 2008-ой студией, т.е. бинарник WSF должен подойти. Собственно, ожидания оправдались, WSF подключился, тестовые примеры заработали.

Дальше правда всё снова стало грустно: при попытке создать клиент по моей wsdl WSF стал молча виснуть, ничего не говоря в логи, после чего я забил на него и воспользовался стандартной php-шной библиотекой php_soap, которая, по крайней мере по функционалу soap-клиента, ничем не хуже WSF.

cscript: ошибка "Отсутствует исполняющее ядро для расширения имени файла ".js""

Проблема: при попытке запуска js-файла из командной строки с помощью команды cscript (например, "cscript configure.js" при компиляции php) появляется ошибка:
Отсутствует исполняющее ядро для расширения имени файла ".js"
Причина: нарушена файловая ассоциация файлов с расширением js.
Решение: запустить cmd из-под администратора, выполнить
ASSOC .JS=JSFile

MS Visual Studio 2010: cl.exe и "mspdb100.dll not found".

Проблема: при вызове компилятора MS Visual Studio 2010 cl.exe из командной строки получаем ошибку: "The application has failed to start bacause mspdb100.dll was not found ...".
Решение:  перед вызовом непосредственно компилятора cl.exe необходимо запустить в той же командной строке vcvars32.bat.

пятница, 18 ноября 2011 г.

"1С-Битрикс Веб-окружение": добавление поддержки Postgres в php

В "Веб-окружении" "1С-Битрикс" php-модуль для работы с Postgres уже есть, нужно только включить его в php.ini, расположенном в apache2\zendserver\etc относительно директории установки окружения:
extension=php_pgsql.dll

суббота, 12 ноября 2011 г.

пятница, 11 ноября 2011 г.

MySQL: как убрать NUL в конце строк

Проблема: 
при переносе БД из другой СУБД в конце всех перенесенных varchar-строк оказался символ NUL (или "00" в шестнадцатеричном представлении, что является символом конца строки, например, в С, но в БД этот лишний байт вовсе не нужен).
Решение:
Решается проблема простым UPDATE`ом, который удалит лишний байт в конце всех строк, если он там есть (строки расположены в столбце brand таблицы manufacturers):

UPDATE `manufacturers`
SET brand=SUBSTRING(brand,1,CHAR_LENGTH(brand)-1)
WHERE HEX(SUBSTRING(brand FROM CHAR_LENGTH(brand)))='00'