PDO i parametry procedur zapamiętanych/składowanych

4 Kwiecień 2011

W PDO po ODBC dołączonym do php 5.3.2 (WINDOWS 2008 SERVER, SQL 2008, CGI/FastCGI ) NIE działają poprawnie wywołania procedur , gdzie parametry podajemy :
EXEC procedure_name @param2 = :param2, @param4 = :param4

dla procedury:

CREATE PROCEDURE procedure_name
@param1 INT
@param2 INT
@param3 INT
@param4 INT
@param5 INT
AS
...

Do serwera zostanie wysłane zapytanie:

EXEC procedure_name @param3 = @param1, @param4 = @param2

Wystarczy jednak zainstalować “Microsoft Drivers for PHP for SQL Server 2.0″ i problem znika.

Jeżeli nie mamy/nie chcemy instalować w/w sterownika, należy zachować kolejność parametrów w php z parametrami procedury, a nieużywane podawać jako: $param1 = DEFAULT

Invalid character value for cast specification

30 Marzec 2011

Ten błąd z uzupełnieniem np “Operand type clash: text is incompatible with int” podczas wykonania procedury zapamiętanej oznacza z dużym prawdopodobieństwem, że używany jest sterownik (native client) z bugiem. Więcej szczegółów w oficjalnym zgłoszeniu i stanowisku firmy Małomiękki.

Mały hint, dla mniej zorientowanych ;) Jeżeli zainstalowany zostanie Native client na maszynie, gdzie wcześniej istniał wyłącznie sterownik np dla SQL 200 lub 2005 trzeba pamiętać o zmianie nazwy sterownika:

$pdo = new PDO(‘odbc:DRIVER={SQL Server};SERVER=SERVER2008\SERVER2008′, ‘sql_login’, ‘sql_pass’, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

$pdo = new PDO(‘odbc:DRIVER={SQL Server Native Client 10.0};SERVER=SERVER2008\SERVER2008′, ‘sql_login’, ‘sql_pass’, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

Bez buga Native Client znajduje się w paczce fjuczerów do sql 2008 R2 (kluczowe jest R2)

Linki do “Microsoft® SQL Server® 2008 R2 Native Client” na dzień 2011-03-30:
- wersja 64 bit http://go.microsoft.com/fwlink/?LinkID=188401&clcid=0×409
- wersja 32 bit: http://go.microsoft.com/fwlink/?LinkID=188400&clcid=0×409

Błąd Apache: unable to load dynamic library php_exif.dll

30 Sierpień 2010

Ten błąd może się pojawić nawet, gdy plik php_exif.dll znajduje się w odpowiednich katalogach. W takim przypadku w 99,9% wypadków oznacza to, problem z załadowaniem… php_mbstring.dll.
php_exif.dll jest zależne od php_mbstring.dll, dlatego nie dość, że musi wystąpić wpis extension=php_mbstring.dll, to jeszcze musi być on PRZED extension=php_exif.dll


extension=php_mbstring.dll
extension=php_exif.dll

Błąd przy pdo->prepare() – [Microsoft][ODBC SQL Server Driver][SQL Server]The text, ntext, and image data types cannot be compared or sorted, except when using IS NULL or LIKE operator.

20 Luty 2010

Cała zabawa dotyczy błędu opisanego tu http://bugs.php.net/bug.php?id=36561. ([Microsoft][ODBC SQL Server
Driver][SQL Server]The text, ntext, and image data types cannot be
compared or sorted, except when using IS NULL or LIKE operator.).
Rozwiązaniem jest (jeżeli nie chcecie czkać na M$) użycie konwersji (rzutowania?) poprze CAST.
Ponieważ nie wolno rzutować TEXT na INT (a właśnie TEXT jest brane jako typ parametru “bindowanego”, trzeba rzutować na VARCHAR, a potem baza sama sobie zrobi resztę. Ponieważ integer jest od -9223372036854775808 through 9223372036854775807 (BIGINT) na opisanie go potrzeba 20 znaków (1 znak na ‘minus’ + 19 na cyfry).
Resume :)
Użyj TestID = CAST(:TestID AS VARCHAR(20)) zamiast TestID = :TestID. Niewiele roboty, a potrafi zaoszczędzić modyfikacji kodu php.

PDO/ODBC/MSSQL does not work with bound params.

Simple solution (if you dont want wait for M$) use CAST:
because integer is definded (sql2000) as -9223372036854775808 through 9223372036854775807 we need max 20 chars.

Use this:
SELECT TestID FROM zTest_TBL
WHERE TestID = CAST(:TestID AS VARCHAR(20)) AND TestID IN (SELECT TestID FROM zTest_TBL
)

instead this:
SELECT TestID FROM zTest_TBL
WHERE TestID = :TestID AND TestID IN (SELECT TestID FROM zTest_TBL
)

Dont convert to INT or BIGINT. Why? Try it ;)

I hope, this help to save many complicated solution in php code.

‘Workflow’ dla projektów WS

29 Styczeń 2010

// remove slashes in get post cookie data...
if ( get_magic_quotes_gpc() ) {
if(is_array($_REQUEST)) $_REQUEST=stripslashes_ws($_REQUEST);
if(is_array($_POST)) $_POST=stripslashes_ws($_POST);
if(is_array($_GET)) $_GET=stripslashes_ws($_GET);
if(is_array($_COOKIE)) $_COOKIE=stripslashes_ws($_COOKIE);
}
@set_magic_quotes_runtime(0);

Ajax i kodowanie polskich znaków

29 Styczeń 2010

Tzw wywołania ajaxowe, wysyłają dane do serwera z kodowaniem UTF-8. Taka natura i nic tu się nie zrobi.
Jeżeli strona ma inne kodowanie niż UTF-8, najprościej:
1. w pliku php, który jest wywoływany ajaxowo, umieszczamy informację dla przeglądarki, że ma interpretować przychodzące znaki jako np ‘windows-1250:
header('Content-Type: text/html; charset=windows-1250');
2. Przychodzące dane POST lub GET) trzeba skonwertować z UTF-8 na windows-1250. można trenować z iconv(‘utf-8′, ‘windows-1250′, …) lub użyć funkcji własnej:

function prepareAjaxGPC()
{
$utf_iso = array(
"\xc4\x85" => "\xb1",
"\xc4\x84" => "\xa1",
"\xc4\x87" => "\xe6",
"\xc4\x86" => "\xc6",
"\xc4\x99" => "\xea",
"\xc4\x98" => "\xca",
"\xc5\x82" => "\xb3",
"\xc5\x81" => "\xa3",
"\xc3\xb3" => "\xf3",
"\xc3\x93" => "\xd3",
"\xc5\x9b" => "\xb6",
"\xc5\x9a" => "\xa6",
"\xc5\xba" => "\xbc",
"\xc5\xb9" => "\xac",
"\xc5\xbc" => "\xbf",
"\xc5\xbb" => "\xaf",
"\xc5\x84" => "\xf1",
"\xc5\x83" => "\xd1",
"%u0104" => "\xA1",
"%u0106" => "\xC6",
"%u0118" => "\xCA",
"%u0141" => "\xA3",
"%u0143" => "\xD1",
"%u00D3" => "\xD3",
"%u015A" => "\xA6",
"%u0179" => "\xAC",
"%u017B" => "\xAF",
"%u0105" => "\xB1",
"%u0107" => "\xE6",
"%u0119" => "\xEA",
"%u0142" => "\xB3",
"%u0144" => "\xF1",
"%u00D4" => "\xF3",
"%u015B" => "\xB6",
"%u017A" => "\xBC",
"%u017C" => "\xBF"
);
foreach ($_REQUEST as $key => $val) {
$_REQUEST[$key] = str_replace(array_keys($utf_iso), array_values($utf_iso), $val);
}
}

Oczywiście, jeżeli przesyłana jest tablica, potrzebne będzie zmodyfikowanie funkcji na jej wywołanie rekurencyjne itp.

Moje boje z SQLSTATE[HY010]: Function sequence error: 0

30 Grudzień 2009

PDO używające sterowników ODBC raczy nas od czasu do czasu wszystkomówiącymi komunikatami “SQLSTATE[HY010]: Function sequence error: 0″.

Z doświadczenia wiem, że ma to miejsce przynajmniej w kilku (jak nie kilkunastu) przypadkach. Będę je tu wypisywał w miarę, jak będą mi dokuczać ;)

1. Niby prosta sprawa:
$stmt = $pdo->prepare('SELECT * FROM tabela WHERE kol = :kol');
$params = array('kol'=> $kol);
$stmt->execute($params);

Ostatni wiersz powoduje błąd. kol jest integer. Co ciekawe, na innym komputerze, wszystko działa. Profiler pokazuje 1, zamiast spodziewanej wartości.
Zastąpienie $kol, wartością z palca, np.: 1234, powoduje, że błąd znika.
Rozwiązanie: tu sprawa jest prosta, prawdopodobnie, $kol nie przekazuje integer (np.: 1234.0 zamiast 1234) aby to sprawdzić, trzeba rozwiązać problem typu $kol. Można to sprawdzić rzutując (int)$kol – błąd zniknie – wszystko jasne. Błąd nie znika? Jaki błąd?? ;)

Podłączenie do dwóch baz przy użyciu mechanizmu bootstrap i resource

13 Sierpień 2009

Używanie zasobów aplikacji (application resource) pozawala na dyskretne tworzenie obiektów z wykorzystaniem mechanizmów Zend framework. Jeżeli, podczas tworzenia obiektu, w każdym projekcie wymagane są dodatkowe akcje, można je wykonać w metodach _initNazwaZasobu() klasy dziedziczącej z Zend_Application_Bootstrap_Bootstrap. Jednak ten sposób, wymusza, abyśmy za każdym razem, w każdym projekcie, umieszczali w tej klasie takie metody.
Istnieje metoda, która zwolni nas od każdorazowego powielania kodu metod _init. Polega ona na opakowaniu klas zendowskich Zend_Application_Resource_* i umieszczeniu tam powielanego dotąd kodu.
Przykładem może być umieszczanie w Zend_Registy adaptera do bazy danych, lub konfigurowanie view helperów DocType czy inne akcje.
Daje to jeszcze jedną korzyść: łatwe ustanawianie połączeń do wielu baz.
Przy 1 połączeniu sprawa jest prosta jak budowa Zend_Cepa :) W pliku ini umieszcza się:
bootstrap.path = APPLICATION_PATH “klasa_z_Zend_Application_Bootstrap_Bootstrap.php”
bootstrap.class = “Nazwa_Klasy_Naszego_Bootstrap”

resources.db.adapter = "Zend_Db_Adapter_Pdo_Mysql"
resources.db.params.username = "login"
resources.db.params.password = "pass"
resources.db.params.dbname = "sjakas_baza_np_lokalna"
resources.db.params.host = "localhost"

I to wystarczy. Po odpaleniu, resztę czarnej roboty odwala framework.
Dostęp do naszego połączenia mamy poprzez getPluginResource(‘db’)->getDbAdapter().
Jeżeli mamy dwie bazy i chcemy aby je ‘obsługiwał’ automatycznie nasz bootstrap, trzeba będzie utworzyć własną klasę reusorce: dbWWW i dbLocal.
1. tworzymy klasę np:
require_once 'Zend/Application/Resource/Db.php';

class Resource_Dbwww extends Zend_Application_Resource_Db {

function init()
{
parent::init();//pozwólmy popracować Zendowi ;)
Zend_Registry::set('dbwww', $this->getDbAdapter());//zapisujemy adapter do rejestru
}
}

teraz w config.ini dopisujemy (założyłem, że plik z klasą leży w /library projektu):

pluginPaths.Resource = APPLICATION_PATH "/../library/Resource"

...

resources.dbwww.adapter = "Zend_Db_Adapter_Pdo_Mysql"
resources.dbwww.params.username = "www"
resources.dbwww.params.password = "www"
resources.dbwww.params.dbname = "baza_na_www"
resources.dbwww.params.host = "mysql.playboy.com"

That’s all folks ;) Teraz, jeżeli potrzeba w dowolnym miejscu użyć połączenia do bazy ‘mysql.playboy.com’ piszemy Zend_Registry::get(‘dbwww’), a jak potrzeba do bazy lokalnej Zend_Registry::get(‘www’).
Jeżeli trzymamy się standardów nazywania adapterów do baz, które sami sobie narzucamy w pracy, to takie podejście pozwala pisać biblioteki klas działające na bazach, bez potrzeby przekazywania adapterów jako parametrów konstruktora czy poszczególnych metod.

Ręczna konfiguracja php pod IIS

8 Czerwiec 2009

Garść parametrów, które zwyczajowo NALEŻY ustawić, aby nie obudzić się z ręką w nocniku.
Plik php.ini z definicji jest szukany przez IIS w katalogu :\\php.ini

0) ustawić include_path
1) wstawić extension_dir
2) odremować odpowiednie rozszerzenia:
- pdo, pdo_odbc
- gettext
3) włączyć short_open_tag
4) jeżeli używane, włączyć asp_tags
5) ustawić safe_mode
6) ustawić disable_functions
7) ustawić magic_quotes_gpc, magic_quotes_runtime
8) ustawić doc_root
9) upload_tmp_dir
10) dla świętego spokoju ustawić date.timezone
11 ustawić zend_extension_ts

Zend Studio 7.0 Early Access + Zend Framework 1.8.2 pod Windows

8 Czerwiec 2009

Dla potomnych :) jak utworzyć projekt W Zend Studio 7.0 tak, aby posiadał cały szkielet aplikacji ZF.
1) jeżeli nie mamy skonfigurowanej zmiennej środowiskowej do php.exe, najprościej przeedytować ostatnią linie w pliku :\Katalog_Zenda\bin\zf.bat, aby wyglądała:
:\katalog_z_php\php\php.exe -d safe_mode=Off -f :\Katalog_Zenda\bin\zf\bin\zf.php — %*
2) wykonać polecenie zf.bat create project nasz_nasza_projektu
3) skopiować powstałą strukturę pkików i katalogów w docelowe miejsce
4) w Zend Studio wybrać File -> New ->Zend Framework Project
5) wybrać “Create project from existing source”, wskazać miejsce docelowe wybrane w 3)
6) wybrać “Zend Framework default project structure” lub “Full..”

Chłopaki z zenda obiecali, że w finalnej wersji ma się to już samo robić z wykorzystaniem zend toolsów.

Do testów, polecam na początek, w celu uniknięcia straty czasu na poszukiwaniu dziury w całym, dodać w index.php, na samym początku:

error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'On');
ini_set('display_startup_errors', 'On');

oraz zmianić linię :

defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

na linię:

defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) .'/../').'\application');

Do pliku configs\application.ini w sekcji “production”:

resources.frontController.throwExceptions = 1
resources.frontController.disableOutputBuffering = 1


Follow

Otrzymuj każdy nowy wpis na swoją skrzynkę e-mail.