Показаны сообщения с ярлыком php. Показать все сообщения
Показаны сообщения с ярлыком php. Показать все сообщения

вторник, 3 января 2012 г.

Взаимодействие PHP и MSSQL - новые веяния

Поразительный факт: подкупающие своей привычностью функции mssql_connect, mssql_query и т.п. канули в небытие начиная с версии 5.3.0, по крайней мере в варианте для windows.

Однако, как выяснилось, Microsoft в беде не оставит! Есть вполне работоспособный драйвер версии аж 2.0.1. Для него, правда, требуется нативный клиент SQL Server 2008, но его тоже легко можно скачать по ссылке вот с этой страницы (если, конечно, удастся нужную ссылку на этой странице отыскать ^_^).

Единственная тонкость: драйвер представляет из себя набор dll-ек "на все случаи жизни", и требуется выбрать из них нужную. Перебором получилось прописать в php.ini, закинув предварительно в папку расширений соответствующий файл:
extension=php_pdo_sqlsrv_53_ts_vc9.dll
что, видимо намекает на то, что PHP 5.3.1 компилировался при помощи Visual C++ 9...

В общем, минимально рабочий код оказался таким (лёгкая вариация примера из хелповника, поставляемого вместе с драйвером):
/* Указываем параметры поключения: имя сервера, логин-пароль и базу. */
$serverName = "myserver.mydomain.ru";
$connectionInfo = array( "UID"=>"uid",
"PWD"=>"pwd",
"Database"=>"AdventureWorks");

/* Подключаемся к серверу используя аутентификацию SQL Server. */
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn === false )
{
echo "Unable to connect.";
die( print_r( sqlsrv_errors(), true));
}

/* Выполняем SQL-запрос. */
$tsql = "SELECT getdate()";
$stmt = sqlsrv_query( $conn, $tsql);
if( $stmt === false )
{
echo "Error in executing query.";
die( print_r( sqlsrv_errors(), true));
}

/* Получаем результаты запроса и выводим их на экран (казалось бы). */
// $row = sqlsrv_fetch_array($stmt);
// echo "Server date: ".$row[0];
// не проканало с ошибкой Object of class DateTime could not be converted to string

/* Получаем результаты запроса и выводим их на экран - а вот так проканало. */
if (sqlsrv_fetch($stmt);)
echo "Server date: ".sqlsrv_get_field( $stmt, 0, SQLSRV_PHPTYPE_STRING( SQLSRV_ENC_CHAR) );

/* Освобождаем ресурсы, выделенные для запроса и подключения. */
sqlsrv_free_stmt( $stmt);
sqlsrv_close( $conn);


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

воскресенье, 26 декабря 2010 г.

Обработка изображений в PHP

По дороге из мастерской Март нагнал Бэрка и пошел рядом с ним.
– Что там такое? – спросил он. – Уж не собираются ли они выдать нам по оловянной медали?
– Даже лучше, – сказал Бэрк. – Узнаешь сам.

Джоунс Рэймонд Ф. "Уровень шума"

А почему бы, собственно, не нарисовать оловянную медаль? В конце концов, вариант

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

Итак, есть некое изображение, нужно превратить его в медаль. Для этого требуется:
1) Получить из изображения чеканку
2) Нарисовать колодку
А так как нужно стараться решать не задачи, а классы задач, то будем считать, что изображение - достаточно произвольное, и вообще пусть всё делает компьютер, а именно PHP с подключенным модулем gd2.

1а. Пусть у нас уже готова веб-форма для загрузки изображения, например:

<HTML>
<BODY>
<FORM method="POST" enctype="multipart/form-data" action="step2.php">
<INPUT type="file" name="">
</FORM>
</BODY>
</HTML>

Соответственно, в скрипте step2.php можно использовать имя сохраненной копии переданного файла в переменной $_FILES['userfile']['tmp_name']. С ним дальше и будем работать.

1б. Сначала надо открыть файл в PHP. Для этого воспользуемся способом, используемым в WR-Gallery:

$size = getimagesize($SrcFileName);
if ($size !== false)
{
$format = strtolower(substr($size['mime'], strpos($size['mime'], '/')+1));
$icfunc = "imagecreatefrom" . $format;
if (function_exists($icfunc))
$isrc = $icfunc($SrcFileName);
}

В результате получим в переменной $isrc ссылку на загруженное изображение.

1в. Дальше надо привести полученное изображение к нужному нам размеру. Это легко сделать при помощи функции imagecopyresampled:

$idest = imagecreatetruecolor($new_width, $new_height);
imagecopyresampled($idest, $isrc,
0, 0,
0, 0,
$new_width, $new_height,
$size[0], $size[1]);

После этой операции об $isrc можно забыть: imagedestroy($isrc);

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

Итак, оттенки серого. Как выяснилось, любой цветной пиксел (r,g,b) преобразуется в серый при помощи следующей формулы: h = 0.30*r + 0.59*g + 0.11*b. Таким образом, получив для каждой точки изображения ее составляющие мы вполне можем перевести эту точку в оттенки серого:

$rgb = imagecolorat($idest, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$grey[$x][$y] = $r * 0.3 + $g * 0.59 + $b * 0.11;

Тут, казалось бы, и рисовать! Но, забегая вперед, скажем, что результат чеканки в целом с использованием палитры $color[$i] = imagecolorallocate($igrey,$i,$i,$i); оказался неудовлетворительным с точки зрения контрастности, поэтому при инициализации палитры эту самую контрастность лучше заранее повысить.

1д. С контрастностью всё оказалось просто. Во-первых, есть вот такая статья с готовыми алгоритмами, посвященными этой теме, и, во-вторых, отыскалась простая формула, пересчета палитры в заданную контрастность: H_new = (H_old - H_mid)*Contrast + H_mid, где H_new и H_old - новое и старое значения цвета соответственно, Contrast - коэффициент, задающий контрастность и H_mid - неподвижная точка преобразования.

Соответственно в нашем случае подготовить изображение и нужный массив цветов можно следующим образом:

$igrey = imagecreatetruecolor(240, 400);
for ($i = 0; $i < 256; $i++)
{
$v = ($i - 128) * 4 + 128;
if ($v < 0) $v = 0;
if ($v > 255) $v = 255;
$color[$i] = imagecolorallocate($igrey, $v,$v,$v);
}


1е. Теперь остается самое простое - имея двумерный массив интенсивностей $grey[$x][$y] реализовать то, что называется emboss. И тут возникло небольшое затруднение. Из далекого детства известно, что большинство преобразований - размытие, резкость и т.п. - это просто результат применения некого фильтра к исходному изображению. Что имеется в виду? Пусть задана некая матрица А=a(i,j), где i=-n..n, j=-m..m. Тогда применение фильтра к каждой точке изображения - это вычисление суммы слагаемых вида a(i,j)*$grey[$x+i][$y+j], деленной на сумму коэффициентов a(i,j).

Например, для размытия матрица А имеет вид:
1 1 1
1 1 1
1 1 1

для вычисления границ:
 1  1  1
0 0 0
-1 -1 -1

и т.п.

А вот для emboss почему-то разные источники предлагают разные матрицы. Во-первых встретилась такая матрица:
1  0  0
0 0 0
0 0 -1

или даже такая:
-1 -1  1
-1 -1 1
1 1 1

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

$grey[$x][$y] = ($grey[$x+1][$y+1] + (255 - $grey[$x][$y])) / 2;


Теперь уже можно со спокойной совестью превратить пересчитанный массив $grey в изображение при помощи функции:

imagesetpixel($igrey, $x, $y, $color[$grey[$x][$y]]);


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

Для этой цели заводим еще одно изображение, $itransp, на котором рисуем белым цветом кружок, делаем остальной фон прозрачным, и функцией imagecopymerge копируем полученный шаблон на $igrey:

$itransp = imagecreatetruecolor(240, 400);
$black_color = imagecolorallocate($itransp, 0,0,0);
$white_color = imagecolorallocate($itransp, 255,255,255);
imagefill($itransp, 0,0, $white_color);
imagefilledellipse($itransp, 120, 300, 200, 200, $black_color);
imagecolortransparent($itransp, $black_color);
imagecopymerge($igrey, $itransp, 0,0,0,0, 240, 400, 100);
imagedestroy($itransp);


Ура, каким-то чудом медаль получена.

2. Теперь осталось самое простое - нарисовать колодку. Собственно, она представляет собой закрашенный многоугольник, единственная тонкость - нанести на него какую-нибудь фактуру, чтобы было похоже на ткань. Для этой цели не придумалось ничего умнее, чем завести еще одно вспомогательное изображение $ibarpattern, в котором нарисовать фактуру ткани, и потом при помощи функции imagecopymerge наложить эту фактуру на колодку:

$ibarpattern = imagecreatetruecolor(240, 5);
$black_color = imagecolorallocate($ibarpattern, 0,0,0);
$white_color = imagecolorallocate($ibarpattern, 255,255,255);
imagefill($ibarpattern, 0,0, $white_color);
imagecolortransparent($ibarpattern, $white_color);
$dy = 0;
for ($i = 0; $i < 240; $i++)
{
$dy++;
if ($dy >=10) $dy = 0;
imagesetpixel($ibarpattern,
$i,
($dy < 5) ? 2 : 3,
$black_color);
imagesetpixel($ibarpattern,
$i,
($dy < 5) ? 1 : 4,
$black_color);
}
for ($i = 0; $i < 190; $i += 5)
imagecopymerge($ibar, $ibarpattern, 0, $i, 0, 0, 250, 5, 10);
imagedestroy($ibarpattern);


И вот - наконец-то! - после всех этих ухищрений получается то, что нужно:



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

вторник, 12 января 2010 г.

Проблема с php_curl.dll

Проблема: после попытки раскомментировать extension=php_curl.dll под апачем выдаётся пара ошибок вида "не найден указанный модуль".
Решение: утащил libeay32.dll и ssleay32.dll в %WINDIR%\system32

воскресенье, 28 июня 2009 г.

формулы LaTeX на веб-странице

Отличная статья, как настроить отображение формул в стиле LaTeX на веб-странице с использованием php:
http://www.linuxjournal.com/article/7870

среда, 24 июня 2009 г.

удалось подрубиться к MSSQL из PHP

DEBIAN:

ну-у, сначала пришлось доустановить некий компонент apt-get install php5-sybase-чего-то-там (странно, при чем здесь MSSQL?), потом воспользоваться советом из хелпа:

senyahnoj
08-Feb-2005 10:09
When moving the following script from PHP on Win32 to PHP on Linux, I encountered problems:

$c = mssql_connect("SERVER\INSTANCE","UID","PWD");

After much searching, I discovered that 'instances' are just named aliases for port numbers, so on Linux this should be written:

$c = mssql_connect("SERVER:PORT","UID","PWD");

Please also note that the colon (:) should be used on Linux as the delimiter between servername and port number, not the comma (,) which only works on Win32 servers.

Windows:

Есть небольшая тонкость в php 5.1.4, а именно - мешает жить какая-то нехорошая ntwdblib.dll. Работоспособную версию можно взять отсюда.