ठीक है। मेरा समाधान PHP और MySQL का एक संयोजन है जो इसे यथासंभव "पारदर्शी रूप से" कार्य करने के लिए प्राप्त करता है।
ये विधियां Data
. में मौजूद हैं रैपर वर्ग जो पीडीओ और तैयार बयानों का उपयोग करता है।
इस्तेमाल की गई अन्य विधियों की कुछ व्याख्या:
Data::prepareAndExecute ($query, $tokens);
एक शॉर्टकट विधि है जो एक क्वेरी तैयार करती है, उसे निष्पादित करती है और, यदि परिणाम हैं, तो उन परिणामों की एक सहयोगी सरणी देता है।Data::isSafeDatabaseEntity ($table)
बस जाँचता है कि तालिका का नामpreg_match ("/^([a-zA-Z0-9_]+)$/", $check);
SQL इंजेक्शन को रोकने के लिए आदेश। ऐसा इसलिए है क्योंकि मैं फ़ील्ड और टेबल नामों के लिए तैयार स्टेटमेंट का उपयोग नहीं कर सकता।Data::tableInfo ($table);
PDOStatement::getColumnMeta ();
से प्राप्त जानकारी के आधार पर तालिका में स्तंभों की एक सहयोगी सरणी देता है ।Data::getTablePrimaryKey ($table);
SHOW INDEX FROM...
. के परिणामों का उपयोग करता है सवाल। यह कहा जाना चाहिए कि यह केवल एकल-फ़ील्ड PK के साथ कार्य करने के लिए डिज़ाइन किया गया है।
मेरे Data
. से उद्धरण कक्षा:
public static function addTableLogging ($table, $ignorecolumns = array ())
{
if (Data::isSafeDatabaseEntity ($table))
{
$update_trigger = "CREATE TRIGGER `{$table}_after_update` AFTER UPDATE ON `{$table}` FOR EACH ROW BEGIN\n";
$insert_trigger = "CREATE TRIGGER `{$table}_after_insert` AFTER INSERT ON `{$table}` FOR EACH ROW BEGIN\n";
$columns = Data::tableInfo ($table);
$pk = Data::getTablePrimaryKey ($table);
foreach ($columns as $column)
{
if (!in_array ($column ['name'], $ignorecolumns))
{
$update_trigger .= " IF (NEW.{$column ['name']} != OLD.{$column ['name']}) THEN
CALL changelog_store ('{$table}', OLD.{$pk}, '{$column ['name']}', OLD.{$column ['name']}, NEW.{$column ['name']});
END IF;\n";
$insert_trigger .= " CALL changelog_store ('{$table}', NEW.{$pk}, '{$column ['name']}', '', NEW.{$column ['name']});\n";
}
}
$update_trigger .= "END";
$insert_trigger .= "END";
self::removeTableLogging ($table);
self::prepareAndExecute ($update_trigger);
self::prepareAndExecute ($insert_trigger);
}
}
public static function removeTableLogging ($table)
{
if (self::isSafeDatabaseEntity ($table))
{
Data::prepareAndExecute ("DROP TRIGGER IF EXISTS `{$table}_after_update`;");
Data::prepareAndExecute ("DROP TRIGGER IF EXISTS `{$table}_after_insert`;");
}
}
public static function refreshLoggingProcedure ()
{
/* -- for logging into MySQL Table:
CREATE TABLE `changelog` (
`change_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`change_table` VARCHAR(50) NULL DEFAULT NULL,
`change_table_id` VARCHAR(25) NULL DEFAULT NULL,
`change_field` VARCHAR(50) NULL DEFAULT NULL,
`change_old` VARCHAR(255) NULL DEFAULT NULL,
`change_new` VARCHAR(255) NULL DEFAULT NULL,
`change_user` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`change_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`change_id`),
INDEX `change_table_id` (`change_table_id`),
INDEX `change_table` (`change_table`, `change_field`)
);
*/
$logquery = "CREATE PROCEDURE `changelog_store`(IN `tab` VARCHAR(50), IN `pkval` INT, IN `fieldn` VARCHAR(50), IN `oldv` TEXT, IN `newv` TEXT)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
IF ISNULL(@STAFFID) THEN
SET @STAFFID = 0;
END IF;
INSERT INTO `changelog` (change_table, change_table_id, change_field, change_old, change_new, change_date, change_user)
VALUES (tab, pkval, fieldn, oldv, newv, NOW(), @STAFFID);
END";
Data::prepareAndExecute ("DROP PROCEDURE IF EXISTS `changelog_store`;");
Data::prepareAndExecute ($logquery);
}