SQLの窓

2014年05月27日


PHP : PDO のエラー処理

概要

PDO エラー処理には3通りあります。

(1) DO::ERRMODE_SILENT
最初はその名の通り、エラーが起きてもなにも起こりません。そのまま実行されますが、エラー情報は設定されていますし、戻り値も正しく返ります。一番簡単でバグさえなければ問題は発生しにくいですが、複雑な問題を確認する為には戻り値とメッセージを常に確認して正しいエラー処理を行う必要があります

(2) PDO::ERRMODE_WARNING
二つ目は、さらにPHPの通常のエラーメッセージを出力させるようにしたバージョンです。初期段階のデバッグに有効です

(3) PDO::ERRMODE_EXCEPTION
三つ目は、try 〜 catch を使うようにしたものですが、慣れていないと扱いは少し難しくなります。しかし、例外によりスクリプトが終了した際には、トランザクションは自動的に ロールバックされるそうです。

前者でどうなるかは未確認ですが、業務アプリケーションならばこちらを選択したほうが良いでしょう。個人の一般の WEB アプリならばそこまで神経質になる必要は無いと思いますので、デフォルトの ERRMODE_SILENT で良いと思います
<?php
$strDriver = "{SQL Native Client}";
$strTarget = "NIGHT_TCP";	// 別名
$strDB = "lightbox";
$strUser = "sa";
$strPass = "passwordpassword";

// **********************************************************
// 接続
// **********************************************************
$Cn = new PDO(
	"odbc:Driver=$strDriver;Server=$strTarget;" .
	"Database=$strDB;Uid=$strUser;Pwd=$strPass;");

	// デフォルトエラーモード
	$Cn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );

	// 存在しない列を更新
	$Query = "update [社員マスタ] set [生年月] = '2005/01/01'";
	$Query .= " where [社員コード] = '0001'";
	$ret = $Cn->exec( $Query );
	if ($ret===false) {
		print_r( $Cn->errorInfo() );
	}


	// エラー表示( デバッグに有効 )
	// 抑制する場合は、@$Cn->exec( $Query );
	$Cn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );

	// 存在しない列を更新
	$Query = "update [社員マスタ] set [生年月] = '2005/01/01'";
	$Query .= " where [社員コード] = '0001'";
	$ret = $Cn->exec( $Query );
	if ($ret===false) {
		print_r( $Cn->errorInfo() );
	}

	// try catch 用
	$Cn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

	// 存在しない列を更新
	$Query = "update [社員マスタ] set [生年月] = '2005/01/01'";
	$Query .= " where [社員コード] = '0001'";
	try {
		$ret = $Cn->exec( $Query );
	}
	catch( PDOException $e ) {
		print $e->getMessage();
	}

$Cn = null;

?>



タグ:PHP PDO
posted by lightbox at 2014-05-27 17:25 | PHP + データベース | このブログの読者になる | 更新情報をチェックする

2010年01月21日


PHPのマニュアルにある、SQLインジェクション攻撃の例

オリジナルページ
PHP: mysql_real_escape_string - Manual

この例では、パスワードを正しく入力しなくても、ユーザの存在チェックがなされた事になってしまいます。( ※ mysql_fetch_row が行を取得してしまう )

また、この場合はユーザーが一致する必要があるのですが、以下のようにすると、ユーザー名が解らなくでもクエリが
行を返す事になります( 但し全てのユーザを返す複数行になります )

$_POST['username'] = "' OR '' != ''";
$_POST['password'] = "'";

よって、入力値に mysql_real_escape_string を使用する事が必要になります
<?
header( "Content-Type: text/html; Charset=utf-8" );
header( "pragma: no-cache" );
header( "Expires: Wed, 31 May 2000 14:59:58 GMT" );
header( "Cache-control: no-cache" );


$server = 'localhost';
$dbname = 'lightbox';
$user = 'root';
$password = 'password';

// 接続解除
$connect = @mysql_connect( $server, $user, $password );
if ( !$connect ) {
	print "接続エラーです";
	exit();
}

// DB選択
mysql_select_db( $dbname, $connect );


// データベース上のユーザに一致するかどうかを調べる
$_POST['username'] = 'lightbox';
$_POST['password'] = "' OR ''='";

$query = <<<QUERY
SELECT * FROM users
	WHERE user = '{$_POST['username']}'
	 AND password = '{$_POST['password']}'
QUERY;

$result = mysql_query($query,$connect);
print_r($result);
print "<pre>";
print_r(mysql_fetch_row($result));
print "</pre>";

?>

但し、入力のキャラクタセットが shift_jis の場合、この関数では、日本語に \ が含まれる文字をエスケープしてしまうので個別に注意が必要です。


また、SQL インジェクションに対する基本的な対処として、

1) DBにスーパーユーザーまたはデータベースの所有者として接続しない

2) 指定された入力が期待するデータ型であることを確認

3) データベースに渡される数値以外のユーザ入力が想定しているキャラクタセットか確認

4) 3) でOKならば mysql_real_escape_string でエスケープ

が上げられます。


関連する記事

PHP+MySQLで、SQLインジェクション対策の為に、一括で mysql_real_escape_string を行う一つの手段


タグ:SQL
posted by lightbox at 2010-01-21 12:11 | PHP + データベース | このブログの読者になる | 更新情報をチェックする

2009年11月15日


PHP : SQLite3 を PDO の ODBC 経由で読み込み

SQLITE_MASTER は、実際には存在しないテーブルで、ドライバがファイルから直接情報を取得しているようですが、PHP から動作しています。( SQLite3 クラス / PDO の sqlite 接続 / PDO の ODBC )
<?
header( "Content-Type: text/html; Charset=UTF-8" );
header( "pragma: no-cache" );
header( "Expires: Wed, 31 May 2000 14:59:58 GMT" );
header( "Cache-control: no-cache" );
// **********************************************************
// PHP php_pdo_odbc.dll 経由 sqlite3(日本語テーブル) 読み込み
// **********************************************************

print "<pre>\n";

$strDB = realpath("./db1.sqlite3" );
$strDriver = "{SQLite3 ODBC Driver}";

print PHP_SAPI . "\n";
print PHP_OS. "\n";
print PHP_VERSION. "\n";

print "\n";

// **********************************************************
// 処理
// www.php.net/manual/ja/sqlite3.construct.php
// www.php.net/manual/ja/ref.pdo-sqlite.connection.php( PDO )
// **********************************************************
$Cn = new PDO( "odbc:Driver=$strDriver;Database=$strDB;" );
$Rs = $Cn->Query( 'select * from SQLITE_MASTER' );

$nFields = $Rs->columnCount();
$hbuffer = "";
$update_cnt = 0;
while( $result = $Rs->fetch(PDO::FETCH_ASSOC) ) {
	print_r($result);
	if ( $hbuffer == "" ) {
		$field_names = array_keys($result);
		for( $i = 0; $i < $nFields; $i++ ) {
			if ( $hbuffer != "" ) {
				$hbuffer .= ",";
			}
			$hbuffer .= $field_names[$i];
		}
		print $hbuffer . "\n";
	}

	$buffer = "";
	for( $i = 0; $i < $nFields; $i++ ) {
		if ( $buffer != "" ) {
			$buffer .= ",";
		}
		$buffer .= $result[$field_names[$i]];
	}
	print $buffer . "\n";

}
$Cn = null;	// close
print "</pre>\n";
?>

関連するリンク

SQLite3 ODBC ドライバ


タグ:PHP PDO sqlite3
posted by lightbox at 2009-11-15 14:34 | PHP + データベース | このブログの読者になる | 更新情報をチェックする

PHP : 5.3 / 5.2.11 用共用 sqlite3(日本語テーブル) 読み込み

PHP 5.3 では、通常 cli 以外で dl が使えないのでモジュールは使用可能であるという前提にしています。使用したファイルは、日本語テーブルで日本語列に日本語データの SQLite3 です。( キャラクタセットは utf-8 です )

※ PHP 5.3 でも もちろん PDO を使用できます。

さくらのサンプル実行ページ
<?
header( "Content-Type: text/html; Charset=UTF-8" );
header( "pragma: no-cache" );
header( "Expires: Wed, 31 May 2000 14:59:58 GMT" );
header( "Cache-control: no-cache" );
// **********************************************************
// PHP 5.3 / 5.2.11 用共用 sqlite3(日本語テーブル) 読み込み
// **********************************************************

print "<pre>\n";

$strDB = realpath("./db1.sqlite3" );

print PHP_SAPI . "\n";
print PHP_OS. "\n";
print PHP_VERSION. "\n";

print "\n";

// **********************************************************
// 処理
// www.php.net/manual/ja/sqlite3.construct.php
// www.php.net/manual/ja/ref.pdo-sqlite.connection.php( PDO )
// **********************************************************
if( (PHP_VERSION+0) >= 5.3 ) {
	$Cn = new SQLite3( $strDB, SQLITE3_OPEN_READWRITE | SQLITE3_OPEN_CREATE );
	$Rs = $Cn->query( 'select * from 社員マスタ' );
	$nFields = $Rs->numColumns();
	$hbuffer = "";
	$update_cnt = 0;
	while( $result = $Rs->fetchArray(SQLITE3_ASSOC) ) {
		print_r($result);
		if ( $hbuffer == "" ) {
			$field_names = array_keys($result);
			for( $i = 0; $i < $nFields; $i++ ) {
				if ( $hbuffer != "" ) {
					$hbuffer .= ",";
				}
				$hbuffer .= $field_names[$i];
			}
			print $hbuffer . "\n";
		}

		$buffer = "";
		for( $i = 0; $i < $nFields; $i++ ) {
			if ( $buffer != "" ) {
				$buffer .= ",";
			}
			$buffer .= $result[$field_names[$i]];
		}
		print $buffer . "\n";

	}
	$Cn->close();

}
else {
	$Cn = new PDO( "sqlite:$strDB" );
	$Rs = $Cn->Query( 'select * from 社員マスタ' );

	$nFields = $Rs->columnCount();
	$hbuffer = "";
	$update_cnt = 0;
	while( $result = $Rs->fetch(PDO::FETCH_ASSOC) ) {
		print_r($result);
		if ( $hbuffer == "" ) {
			$field_names = array_keys($result);
			for( $i = 0; $i < $nFields; $i++ ) {
				if ( $hbuffer != "" ) {
					$hbuffer .= ",";
				}
				$hbuffer .= $field_names[$i];
			}
			print $hbuffer . "\n";
		}

		$buffer = "";
		for( $i = 0; $i < $nFields; $i++ ) {
			if ( $buffer != "" ) {
				$buffer .= ",";
			}
			$buffer .= $result[$field_names[$i]];
		}
		print $buffer . "\n";

	}
	$Cn = null;	// close
}
print "</pre>\n";
?>







タグ:PHP sqlite3
posted by lightbox at 2009-11-15 13:59 | PHP + データベース | このブログの読者になる | 更新情報をチェックする

2009年09月14日


PHP : Oracle を処理する COM を使ったクラス

Windows 用 Oracle/ADO ODBC 基本クラス

長年使用して来たクラスの Oracle 部分を切り出しました。ADO の ODBC 接続です。DSN を作成する必要があります
※ IIS 等のサービスでは、システムDSN に作成する必要があります
※ OO4O とは違います。

<?
header( "Content-Type: text/html; Charset=shift_jis" );
header( "pragma: no-cache" );
header( "Expires: Wed, 31 May 2000 14:59:58 GMT" );
header( "Cache-control: no-cache" );

require_once( "oracle.php" );

$SQL = new Oracle("OracleServer", "lightbox", "lightbox" );

$Query = 'select * from 社員マスタ';

$Column = $SQL->QueryEx( $Query . $Cond );

while ( $Column ) {

	print_r($Column);
	print $Column['作成日'] . "<br>";
	print "<br>";

	$Column = $SQL->QueryEx( );

}

$SQL->Close();

?>

▼ 詳細はこちらを参照して下さい

クラスのソースコード


タグ:Oracle クラス PHP
posted by lightbox at 2009-09-14 21:01 | PHP + データベース | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します
container 終わり



フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

CSS ドロップシャドウの参考デモ
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり