PHPでのMySQLのデータ変更の追跡

また、MySQLに、レコードの挿入、変更、削除時に古いデータ値と新しいデータ値を記録できるトリガーを作成し、PHPスクリプトにある情報を追加するような素晴らしい機会があればどうでしょうか?



MySQLトリガーは以下を知っています:

*変更が発生する瞬間

*古い意味と新しい意味



PHPは知っています:

*現在ログインしているユーザー

*どのページが開いており、どのページからアクセスしたか

*ブレイザー

* IPアドレス

* POST、GET

*クッキー



どうすれば必要な情報をすべて記録できますか?



PHPとMySQLの機能を活用してください!



MySQLは、データベースへの接続が閉じられるまでのみ存続する一時テーブルを作成でき、PHPは各ページを開くとすぐに新しい接続を作成します(WebサーバーとPHP構成の大部分で)。



したがって、トリガーが一時テーブルにも書き込む場合、特定の変更の責任者または原因を見つけることができます。



もう少し詳しく-ページの先頭に一時テーブルを作成します。トリガーが起動すると、データを追跡するためのテーブルに情報を書き込み、last_insert_id()によって返された識別子を一時テーブルに書き込みます。 作業の最後に、一時テーブルに目を向け、空でない場合は、ロードされたPHPページが知っているものから必要なものをすべて変更テーブルに記録します。



次は実装オプションです。



1)一時テーブルから始めましょう-初めてページでトリガーが実行されたときに作成できます! これを行うには、CREATE TEMPORARY TABLE temp_watch_changes IF NOT EXISTSを記述します。 わずかな問題しかありません-現在のバージョンのMySQLでは、クエリによって一時テーブルが存在するかどうかを調べることはできません。 したがって、phpを使用して値を選択するときにエラーが発生しないように作成する必要があります。



仕掛けることはできますが、すべてを簡単に行うことができます。



小さなトリックとして-MySQLでは、同じ名前の通常のテーブルと一時テーブルが同時に存在できます。 一時的なものがある場合は、それが使用されます。 また、temp_watch_changesテーブル内にレコードがあるかどうかをphpがチェックするたびに、空、またはトリガーによって記録されたエラーなしの識別子があります。



より簡単な方法は、ページがロードされるたびに一時テーブルを作成することです。 私たちのサーバーでは、0.0008秒かかりますが、これは原則として許容範囲です:)



CREATE TEMPORARY TABLE temp_watch_changes ( id_change INTEGER NOT NULL )
      
      







2)変更自体を含むテーブルを作成する



 CREATE TABLE `watch_changes` ( `id` int(11) NOT NULL AUTO_INCREMENT, `table_name` varchar(255) DEFAULT NULL, `column_name` varchar(255) DEFAULT '', `key_name` varchar(255) DEFAULT NULL, `key_value` varchar(1000) DEFAULT NULL, `old_value` text, `new_value` text, `type` enum('insert','update','delete') DEFAULT 'update', `date` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `ip` varchar(255) DEFAULT NULL, `id_user` int(11) DEFAULT '0', `user_email` varchar(255) DEFAULT '', `post` text, `get` text, `session` text, `server` text, `user_agent` varchar(1000) DEFAULT '', `url` text, `referer` text, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
      
      







3)トリガーを作成します。 トリガーで列名を動的に使用できるかどうかを確認することはできませんでした。 おそらく、それは単に不可能ですが、私たちは本当にそれを必要としません。 結局のところ、PHPがあります。



 function createWatchTrigger($table,$columns,$primaryKey){ if(!is_array($primaryKey)){ $primaryKey=array($primaryKey); } $types=array('update','insert','delete'); foreach($types as $type){ db::$used->internalQuery("drop trigger IF EXISTS {$table}_t_$type"); $triggerContent="CREATE TRIGGER {$table}_t_$type AFTER $type ON {$table} FOR EACH ROW BEGIN CREATE TEMPORARY TABLE IF NOT EXISTS temp_watch_changes ( id_change INTEGER NOT NULL ); "; foreach($columns as $columnTitle){ if($type=='update'){ $triggerContent.=" IF NEW.{$columnTitle} != OLD.$columnTitle THEN "; } $triggerContent.="INSERT INTO watch_changes (table_name,column_name,old_value,new_value,type,key_name,key_value) "; if($type=='insert'){ $triggerContent.="VALUES('{$table}','$columnTitle','', NEW.$columnTitle,'$type','".implode(',',$primaryKey)."',CONCAT('',NEW.".implode(",',',NEW.",$primaryKey)."));"; }else if($type=='update'){ $triggerContent.="VALUES('{$table}','$columnTitle',OLD.$columnTitle, NEW.$columnTitle,'$type','".implode(',',$primaryKey)."',CONCAT('',NEW.".implode(",',',NEW.",$primaryKey)."));"; }else if($type=='delete'){ $triggerContent.="VALUES('{$table}','$columnTitle',OLD.$columnTitle,'','$type','".implode(',',$primaryKey)."',CONCAT('',OLD.".implode(",',',OLD.",$primaryKey)."));"; } $triggerContent.=" set @last_id=last_insert_id(); INSERT INTO temp_watch_changes (id_change) values (@last_id);"; if($type=='update'){ $triggerContent.="END IF;"; } } $triggerContent.="\nEND;"; db::$used->internalQuery($triggerContent); } }
      
      





作成機能自体は、読みやすさの点で優れている可能性があります。 彼女は、更新、挿入、削除の3つのトリガーを作成します。 テーブルの名前、監視する列、およびこのレコードを見つけることができるキー(複数のキー)を取ります。

次のように呼び出すことができます。

 createWatchTrigger('employees',array('salary','job_title'),'id');
      
      







4)ここで、PHPページの処理が完了した後、一時テーブルのデータが処理されるようにします。



register_shutdown_functionを使用します 。これにより、スクリプトの完了時に任意の関数を実行できます。 どのプロジェクトにも、常に含まれるファイルがあります-そこに配置します。



 function shutdown(){ $affectedRows=db::$used->fetchRows("select * from temp_watch_changes"); if($affectedRows){ if(User::isLogged()){ $userId=User::getCurrent()->getId(); $email=User::getCurrent()->getEmail(); }else{ $userId=0; $email=''; } $updateData=array( 'ip'=>$_SERVER['REMOTE_ADDR'], 'id_user'=>$userId, 'user_email'=>$email, 'post'=>serialize($_POST), 'get'=>serialize($_GET), 'session'=>serialize($_SESSION), 'server'=>serialize($_SERVER), 'user_agent'=>$_SERVER['HTTP_USER_AGENT'], 'url'=>serialize($_SERVER['REQUEST_URI']), 'referer'=>$_SERVER['HTTP_REFERER'] ); foreach($affectedRows as $row){ db::$used->update('watch_changes',$updateData,array('id'=>$row['id_change'])); } } } register_shutdown_function('shutdown');
      
      







以上です。



All Articles