PHP
downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

PDO::query> <PDO::lastInsertId
Last updated: Fri, 10 Oct 2008

view this page in

PDO::prepare

(PHP 5 >= 5.1.0, PECL pdo:0.1-1.0.3)

PDO::prepare 文を実行する準備を行い、文オブジェクトを返す

説明

PDOStatement PDO::prepare ( string $statement [, array $driver_options ] )

PDOStatement::execute() メソッドによって実行される SQL ステートメントを準備します。 SQL ステートメントは、文が実行されるときに実際の値に置き換えられる 0 個もしくはそれ以上の名前 (:name) もしくは疑問符 (?) パラメータマークを含むことができます。 名前と疑問符パラメータを同一 SQL ステートメント中で使用することはできません。 どちらか一方か、他のパラメータ形式を使用してください。

PDOStatement::execute() をコールする際には、 文に渡すパラメータにはそれぞれ固有のパラメータマークを設定する必要があります。 ひとつのプリペアドステートメントの中で、同じ名前のパラメータマークを 複数使用することはできません。SQL 文の IN() 句などで、 ひとつのパラメータに複数の値を 割り当てることはできません。

異なるパラメータを用いて複数回実行されるような文に対し PDO::prepare()PDOStatement::execute() をコールすることで、 ドライバがクライアントまたはサーバ側にクエリプランやメタ情報を キャッシュさせるよう調整するため、 アプリケーションのパフォーマンスを最適化します。また、 パラメータに手動でクオートする必要がなくなるので SQL インジェクション攻撃から保護する助けになります。

PDO は元々この機能をサポートしていないドライバに対して プリペアドステートメントとバインドパラメータをエミュレートします。 このため、ある形式をサポートしているがその他の形式をサポートしていない ドライバの場合、名前もしくは疑問符形式のパラメータを他の適当な値に 書き換えることも可能です。

パラメータ

statement

これは対象のデータベースサーバに対して有効な SQL 文でなければなりません。

driver_options

この配列は、このメソッドによって返される PDOStatement オブジェクトに対して 1 もしくはそれ以上の key=>value の組を含みます。 通常、スクロール可能なカーソルを要求するために PDO::ATTR_CURSORPDO::CURSOR_SCROLL を設定する場合に使用することになるでしょう。 いくつかのドライバには、準備する際に利用可能なドライバ固有の オプションがあります。

返り値

もしデータベースサーバが正常に文を準備する場合、 PDO::prepare() は PDOStatement オブジェクトを返します。 もしデータベースサーバが文を準備できなかった場合、 PDO::prepare()FALSE を返します。

例1 名前付きパラメータを用いて SQL ステートメントを準備する

<?php
/* 値の配列を渡してプリペアドステートメントを実行する */
$sql 'SELECT name, colour, calories
    FROM fruit
    WHERE calories < :calories AND colour = :colour'
;
$sth $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
$sth->execute(array(':calories' => 150':colour' => 'red'));
$red $sth->fetchAll();
$sth->execute(array('calories' => 175'colour' => 'yellow'));
$yellow $sth->fetchAll();
?>

例2 疑問符パラメータを用いて SQL ステートメントを準備する

<?php
/* 値の配列を渡してプリペアドステートメントを実行する */
$sth $dbh->prepare('SELECT name, colour, calories
    FROM fruit
    WHERE calories < ? AND colour = ?'
);
$sth->execute(array(150'red'));
$red $sth->fetchAll();
$sth->execute(array(175'yellow'));
$yellow $sth->fetchAll();
?>



PDO::query> <PDO::lastInsertId
Last updated: Fri, 10 Oct 2008
 
add a note add a note User Contributed Notes
PDO::prepare
Anonymous
26-Sep-2008 07:25
@ jacques at chester dot id dot au

If your table names are configurable (and came from a safe source, like your own config), you can easily use string concatenation to put them in a query.

If the source is unknown / unsafe, it's usually a sign of terrible design flaws. in example if you have N tables with the same set of fields, it would be much safer to make just two tables - mark (containing list of names of what "used to be" old tables) and real data (with one more column referencing key). Then, all operations on data can be performed using the db user unable to delete all your data, and (the point this all started) you know names of both tables when preparing statement, so no problem with PDO not converting/escaping it properly.

Only exception is when you're writing DB management system. Then, however, user is supported to have access to everything db user has, so SQL Injection is a cese of no gain == no problem.

As far as I understand, those were main reason nobody even thought that serious developer will need functioning table names sql injection prevention so near to db drivers.
ak_9jsz
19-May-2008 02:16
Using cursors doesn't work with SQLite 3.5.9. I get an error message when it gets to the execute() method.

Some of you might be saying "duh!" but i was surprised to see TRIGGER support in SQLite, so i had to try. :)

I wanted to use Absolute referencing on a Scrollable cursor and i only wanted one column of data. So i used this instead of a cursor.

<?php

$dbo
= new PDO('sqlite:tdb');
$sql = 'SELECT F1, F2 FROM tblA WHERE F1 <> "A";';
$res = $dbo->prepare($sql);
$res->execute();
$resColumn = $res->fetchAll(PDO::FETCH_COLUMN, 0);

for(
$r=0;$r<=3;$r++)
    echo
'Row '. $r . ' returned: ' . $resColumn[$r] . "\n";

$dbo = null;
$res = null;
?>
Stan
15-Nov-2007 12:35
Using prepared SELECT statements on a MySQL database prior to MySQL 5.1.17 can lead to SERIOUS performance degradation.

Quote from http://dev.mysql.com/doc/refman/5.1/en/query-cache.html :

>> The query cache is not used for server-side prepared statements before MySQL 5.1.17 <<

The MySQL query cache buffers complete query results and is used to satisfy repeated identical queries if the underlying tables do not change in the meantime - just what happens all the time in a typical web application. It speeds up queries by a several hundred to a several thousand percent.

Obviously, it doesn't make much sense to give up query caching for the relatively small performance benefit of prepared statements (i.e. the DBMS not having to parse and optimize the same query multiple times) - so using PDO->query() for SELECT statements is probably the better choice i you're connecting to MySQL < 5.1.17.
www.onphp5.com
07-Apr-2007 10:41
Please note that the statement regarding driver_options is misleading:

"This array holds one or more key=>value pairs to set attribute values for the PDOStatement object that this method returns. You would most commonly use this to set the PDO::ATTR_CURSOR value to PDO::CURSOR_SCROLL to request a scrollable cursor. Some drivers have driver specific options that may be set at prepare-time"

From this you might think that scrollable cursors work for all databases, but they don't! Check out this bug report:
http://bugs.php.net/bug.php?id=34625
Greg MacLellan
24-Feb-2007 03:51
A more versatile version of the below, but supporting an associative array and arbitrary number of fields:

<?php

  
public function matchCriteria($fields=null) {
      
$db=DB::conn();
      
$sql=array();
      
$paramArray=array();
       if(
is_array($fields)) {
           foreach (
$fields as $field=>$value)) {
              
$sql[] = $field.'=?';
              
$paramArray[]=$value;
           }
       }
      
$rs=$db->prepare('SELECT * FROM mytable'.(count($paramArray) ? ' WHERE '.join(' AND ',$sql) : ''));
      
$result=$rs->execute($paramArray);
       if(
$result) {
           return
$rs;
       }
       return
false;
   }

?>
johniskew
23-Feb-2007 01:03
If you need to create variable sql statements in a prepare statement...for example you may need to construct a sql query with zero, one, two, etc numbers of arguments...here is a way to do it without a lot of if/else statements needed to glue the sql together:

<?php

   
public function matchCriteria($field1=null,$field2=null,$field3=null) {
       
$db=DB::conn();
       
$sql=array();
       
$paramArray=array();
        if(!empty(
$field1)) {
           
$sql[]='field1=?';
           
$paramArray[]=$field1;
        }
        if(!empty(
$field2)) {
           
$sql[]='field2=?';
           
$paramArray[]=$field2;
        }
        if(!empty(
$field3)) {
           
$sql[]='field3=?';
           
$paramArray[]=$field3;
        }
       
$rs=$db->prepare('SELECT * FROM mytable'.(count($paramArray)>0 ? ' WHERE '.join(' AND ',$sql) : ''));
       
$result=$rs->execute($paramArray);
        if(
$result) {
            return
$rs;
        }
        return
false;
    }

?>
jacques at chester dot id dot au
13-Nov-2006 11:07
Watch out: prepared statements on MySQL barf if you try to pass in substitution tables for sql keywords, table names, view names and field names.

For example, this will not work:

$stmt = $dbh->prepare("SELECT :sqlAggregate( :fieldName) from :viewName";

You will get a MySQL error 1064 and a very unhelpful error message.

In short, you need to do string substitutions into your queries if you want configurable table names, aggregate keywords etc etc.

Which doesn't help at all in the "protection from injection attacks" thing. A very annoying discovery.
william dot clarke at gmail dot com
01-Sep-2006 07:58
Surely if you want to use prepared statements that way you should use the syntax in the second example:

eg.

instead of:
select id,name from demo_de where name LIKE :name OR name=:name

use:
select id,name from demo_de where name LIKE ? OR name=?

I believe you are supposed to either use distinct named parameters (name, name1) OR anonymous parameters (?s)
roth at egotec dot com
30-Aug-2006 05:58
Attention using MySQL and prepared statements.
Using a placeholder multiple times inside a statement doesn't work. PDO just translates the first occurance und leaves the second one as is.

select id,name from demo_de where name LIKE :name OR name=:name

You have to use

select id,name from demo_de where name LIKE :name OR name=:name2

and bind name two times. I don't know if other databases (for example Oracle or MSSQL) support multiple occurances. If that's the fact, then the PDO behaviour for MySQL should be changed.

PDO::query> <PDO::lastInsertId
Last updated: Fri, 10 Oct 2008
 
 
show source | credits | stats | sitemap | contact | advertising | mirror sites