Quoting and Placeholder Support

print conn-num_rows . rows were updated\n; issue queries that fetch rows, using each row-fetching method query = SELECT id, name, cats FROM profile; conn-issue_query query; while row = conn-fetch_row print id: row[0], name: row[1], cats: row[2]\n; conn-issue_query query; while row = conn-fetch_array { print id: row[0], name: row[1], cats: row[2]\n; print id: row[id], name: row[name], cats: row[cats]\n; } conn-issue_query query; while row = conn-fetch_object print id: row-id, name: row-name, cats: row-cats\n;

2.10.8 Quoting and Placeholder Support

I n Recipe 2.9 , we developed a PHP sql_quote funct ion for PHP t o handle quot ing, escaping, and NULL unset values, so t hat any value can be insert ed easily int o a query: function sql_quote str { if isset str return NULL; func = function_exists mysql_escape_string ? mysql_escape_string : addslashes; return . func str . ; } I f w e add sql_quote t o t he MySQL_Access class, it becom es available aut om at ically t o any class inst ance as an obj ect m et hod and you can const ruct query st rings t hat include properly quot ed values like so: stmt = sprintf INSERT INTO profile name,birth,color,foods,cats VALUESs,s,s,s,s, conn-sql_quote DeMont, conn-sql_quote 1973-01-12, conn-sql_quote NULL, conn-sql_quote eggroll, conn-sql_quote 4; conn-issue_query stmt; I n fact , we can em ploy t he sql_quote m et hod as t he basis for a placeholder em ulat ion m echanism , t o be used as follows: 1. Begin by passing a quer y st r ing t o t he prepare_query m et hod. 2. I ndicat e placeholder s in t he quer y st r ing by using ? char act er s. 3. Execut e t he query and supply an array of values t o be bound t o t he query, one value per placeholder. To bind NULL t o a placeholder , pass t he PHP NULL v alue. One way t o perform param et er binding is t o do a lot of pat t ern m at ching and subst it ut ion in t he query st ring wherever ? occurs as a placeholder charact er. An easier approach is sim ply t o break t he query st ring at t he ? charact ers, t hen glue t he pieces back t oget her at query execut ion t im e wit h t he properly quot ed dat a values insert ed bet ween t he pieces. Split t ing t he query also is an easy way t o find out how m any placeholders t here are it s t he num ber of pieces, m inus one . That s useful for det erm ining whet her or not t he proper num ber of dat a values is present when it com es t im e t o bind t hose values t o t he placeholders. The prepare_query m et hod is quit e sim ple. All it does is split up t he query st ring at ? charact ers, placing t he result int o t he query_pieces array for lat er use at param et er- binding t im e: function prepare_query query { this-query_pieces = explode ?, query; return TRUE; } We could invent new calls for binding dat a values t o t he query and for execut ing it , but it s also possible t o m odify issue_query a lit t le, t o have it det erm ine what t o do by exam ining t he t ype of it s argum ent . I f t he argum ent is a st ring, it s int erpret ed as a query t hat should be execut ed direct ly which is how issue_query behaved before . I f t he argum ent is an array, it is assum ed t o cont ain dat a values t o be bound t o a previously prepared st at em ent . Wit h t his change, issue_query looks like t his: function issue_query arg = { if arg == if no argument, assume prepared statement arg = array ; with no values to be bound if this-connect establish connection to server if return FALSE; necessary if is_string arg arg is a simple query query_str = arg; else if is_array arg arg contains data values for placeholders { if count arg = count this-query_pieces - 1 { this-errno = -1; this-errstr = data valueplaceholder count mismatch; this-error Cannot execute query; return FALSE; } insert data values into query at placeholder positions, quoting values as we go query_str = this-query_pieces[0]; for i = 0; i count arg; i++ { query_str .= this-sql_quote arg[i] . this-query_pieces[i+1]; } } else arg is garbage { this-errno = -1; this-errstr = unknown argument type to issue_query; this-error Cannot execute query; return FALSE; } this-num_rows = 0; this-result_id = mysql_query query_str, this-conn_id; this-errno = mysql_errno ; this-errstr = mysql_error ; if this-errno { this-error Cannot execute query: query_str; return FALSE; } get number of affected rows for non-SELECT; this also returns number of rows for a SELECT this-num_rows = mysql_affected_rows this-conn_id; return this-result_id; } Now t hat quot ing and placeholder support is in place, t he class provides t hree ways of issuing queries. First , you can writ e out t he ent ire query st ring lit erally and perform quot ing, escaping, and NULL handling yourself: conn-issue_query INSERT INTO profile name,birth,color,foods,cats VALUESDe\Mont,1973-01-12,NULL,eggroll,4; Second, you can use t he sql_quote m et hod t o insert dat a values int o t he query st ring: stmt = sprintf INSERT INTO profile name,birth,color,foods,cats VALUESs,s,s,s,s, conn-sql_quote DeMont, conn-sql_quote 1973-01-12, conn-sql_quote NULL, conn-sql_quote eggroll, conn-sql_quote 4; conn-issue_query stmt; Third, you can use placeholders and let t he class int erface handle all t he work of binding values t o t he query: conn-prepare_query INSERT INTO profile name,birth,color,foods,cats VALUES?,?,?,?,?; conn-issue_query array DeMont, 1973-01-12, NULL, eggroll, 4; The MySQL_Access and Cookbook_DB_Access classes now provide a reasonably convenient m eans of writ ing PHP script s t hat is easier t o use t han t he nat ive MySQL PHP calls. The class int erface also includes placeholder support , som et hing t hat PHP does not provide at all. The developm ent of t hese classes illust rat es how you can writ e your own int erface t hat hides MySQL-specific det ails. The int erface is not wit hout it s short com ings, nat urally. For exam ple, it allow s you t o prepare only one st at em ent at a t im e, unlike DBI and JDBC, which support m ult iple sim ult aneous prepared st at em ent s. Should you require such funct ionalit y, you m ight consider how t o reim plem ent MySQL_Access t o provide it .

2.11 Ways of Obtaining Connection Parameters