source: branches/1.1dev/lib/RecordVersion.inc.php

Last change on this file was 81, checked in by scdev, 18 years ago

Changed all instances of addslashes to mysql_real_escape_string

File size: 11.1 KB
Line 
1<?php
2/**
3 * The RecordVersion class provides a system for saving, reviewing, and
4 * restoring versions of a record of any DB table. All the data in the record is
5 * serialized, compressed, and saved in a blob in the version_tbl. Restoring a
6 * version simply does a REPLACE INTO of the data. It is very simple, and works
7 * with multiple database tables, but the drawback is that relationships for
8 * a record cannot be retained. For example, an article from an article_tbl can
9 * be saved, but not categories associated to the record in a category_article_tbl.
10 * The restored article will simple retain the relationships that the previous
11 * current article had.
12 *
13 * @author  Quinn Comendant <quinn@strangecode.com>
14 * @requires App.inc.php
15 * @version 1.0
16 */
17
18require_once dirname(__FILE__) . '/App.inc.php';
19
20class RecordVersion {
21
22    var $record_version_max_qty = 100; // Never have more than this many versions of each record.
23    var $record_version_min_qty = 25; // Keep at least this many versions of each record.
24    var $record_version_min_days = 7; // Keep ALL versions within this many days, even if MORE than record_version_min_qty.
25
26    /**
27     * Saves a version of the current record into the version table.
28     *
29     * @param string $record_table  The table containing the record.
30     * @param string $record_key    The key column for the record.
31     * @param string $record_val    The value of the key column for the record.
32     * @param string $title         The title of this record. Only used for human presentation.
33     *
34     * @return int                  The id for the version (mysql last insert id).
35     */
36    function create($record_table, $record_key, $record_val, $title='')
37    {
38        global $_admin;
39       
40        // Get current record.
41        if (!$record = $this->getCurrent($record_table, $record_key, $record_val)) {
42            logMsg(sprintf('Could not create %s version, record not found: %s, %s, %s.', $title, $record_table, $record_key, $record_val), LOG_ERR, __FILE__, __LINE__);
43            return false;
44        }
45               
46        // Clean-up old versions.
47        $this->deleteOld($record_table, $record_key, $record_val);
48       
49        // Save as new version.
50        dbQuery("
51            INSERT INTO version_tbl (
52                record_table,
53                record_key,
54                record_val,
55                version_data,
56                version_title,
57                saved_by_admin_id,
58                version_datetime
59            ) VALUES (
60                '" . mysql_real_escape_string($record_table) . "',
61                '" . mysql_real_escape_string($record_key) . "',
62                '" . mysql_real_escape_string($record_val) . "',
63                '" . mysql_real_escape_string(gzcompress(serialize($record), 9)) . "',
64                '" . mysql_real_escape_string($title) . "',
65                '" . mysql_real_escape_string($_admin->getVal('user_id')) . "',
66                NOW()
67            )
68        ");
69
70        return mysql_insert_id($GLOBALS['dbh']);
71    }
72
73    /**
74     * Copy a version back into it's original table.
75     *
76     * @param string $version_id    The id of the version to restore.
77     *
78     * @return int                  The id for the version (mysql last insert id).
79     */
80    function restore($version_id)
81    {
82        // Get version data.
83        $qid = dbQuery("
84            SELECT * FROM version_tbl
85            WHERE version_id = '" . mysql_real_escape_string($version_id) . "'
86        ");
87        $record = mysql_fetch_assoc($qid);
88        $data = unserialize(gzuncompress($record['version_data']));
89       
90        $qid = dbQuery("SHOW COLUMNS FROM " . mysql_real_escape_string($record['record_table']));
91        while ($row = mysql_fetch_assoc($qid)) {
92            $fields[] = $row['Field'];
93        }
94        $schema_diff = array_diff($fields, array_keys($data));
95        if (sizeof($schema_diff) > 0 || sizeof($fields) != sizeof($data)) {
96            raiseMsg(sprintf(_("Version ID %s%s is not compatable with the current database table."), $version_id, (empty($record['version_title']) ? '' : ' (' . $record['version_title'] . ')')), MSG_ERR, __FILE__, __LINE__);
97            logMsg('Version restoration failed, DB schema change: (' . join(', ', $schema_diff) . ')', LOG_ERR, __FILE__, __LINE__);
98            return false;
99        }
100
101        // Replace current record with specified version.
102        dbQuery("
103            REPLACE INTO " . $record['record_table'] . " (
104                " . join(",\n", array_map('mysql_real_escape_string', array_keys($data))) . "
105            ) VALUES (
106                '" . join("',\n'", array_map('mysql_real_escape_string', $data)) . "'
107            )
108        ");
109       
110        return $record;
111    }
112
113    /**
114     * Version garbage collection. Deletes versions older than record_version_min_days
115     * when quantity of versions exceeds record_version_min_qty. If quantity
116     * exceeds 100 within record_version_min_days, the oldest are deleted to bring the
117     * quantity back down to record_version_min_qty.
118     *
119     * @param string $record_table  The table containing the record.
120     * @param string $record_key    The key column for the record.
121     * @param string $record_val    The value of the key column for the record.
122     *
123     * @return mixed                Array of versions, or false if none.
124     */
125    function deleteOld($record_table, $record_key, $record_val)
126    {
127        // Get total number of versions for this record.
128        $qid = dbQuery("
129            SELECT COUNT(*) FROM version_tbl
130            WHERE record_table = '" . mysql_real_escape_string($record_table) . "'
131            AND record_key = '" . mysql_real_escape_string($record_key) . "'
132            AND record_val = '" . mysql_real_escape_string($record_val) . "'
133        ");
134        list($v_count) = mysql_fetch_row($qid);
135       
136        if ($v_count > $this->record_version_min_qty) {
137            if ($v_count > $this->record_version_max_qty) {
138                // To prevent a record bomb, limit max number of versions to record_version_max_qty.
139                $qid = dbQuery("
140                    SELECT version_id FROM version_tbl
141                    WHERE record_table = '" . mysql_real_escape_string($record_table) . "'
142                    AND record_key = '" . mysql_real_escape_string($record_key) . "'
143                    AND record_val = '" . mysql_real_escape_string($record_val) . "'
144                    ORDER BY version_datetime ASC
145                    LIMIT " . ($v_count - $this->record_version_min_qty) . "
146                ");
147                while (list($old_id) = mysql_fetch_row($qid)) {
148                    $old_versions[] = $old_id;
149                }
150                dbQuery("
151                    DELETE FROM version_tbl
152                    WHERE version_id IN ('" . join("','", $old_versions) . "')
153                ");
154            } else {
155                // Delete versions older than record_version_min_days, while still keeping record_version_min_qty.
156                $qid = dbQuery("
157                    SELECT version_id FROM version_tbl
158                    WHERE record_table = '" . mysql_real_escape_string($record_table) . "'
159                    AND record_key = '" . mysql_real_escape_string($record_key) . "'
160                    AND record_val = '" . mysql_real_escape_string($record_val) . "'
161                    AND DATE_ADD(version_datetime, INTERVAL '" . $this->record_version_min_days . "' DAY) < NOW()
162                    ORDER BY version_datetime ASC
163                    LIMIT " . ($v_count - $this->record_version_min_qty) . "
164                ");
165                while (list($old_id) = mysql_fetch_row($qid)) {
166                    $old_versions[] = $old_id;
167                }
168                if (sizeof($old_versions) > 0) {
169                    dbQuery("
170                        DELETE FROM version_tbl
171                        WHERE version_id IN ('" . join("','", $old_versions) . "')
172                    ");
173                }
174            }
175        }
176    }
177
178    /**
179     * Get a list of versions of specified record.
180     *
181     * @param string $record_table  The table containing the record.
182     * @param string $record_key    The key column for the record.
183     * @param string $record_val    The value of the key column for the record.
184     *
185     * @return mixed                Array of versions, or false if none.
186     */
187    function getList($record_table, $record_key, $record_val)
188    {
189        // Get versions of this record.
190        $qid = dbQuery("
191            SELECT version_id, saved_by_admin_id, version_datetime, version_title
192            FROM version_tbl
193            WHERE record_table = '" . mysql_real_escape_string($record_table) . "'
194            AND record_key = '" . mysql_real_escape_string($record_key) . "'
195            AND record_val = '" . mysql_real_escape_string($record_val) . "'
196            ORDER BY version_datetime DESC
197        ");
198        while ($row = mysql_fetch_assoc($qid)) {
199            // Get admin usernames.
200            $qid2 = dbQuery("SELECT username FROM admin_tbl WHERE admin_id = '" . mysql_real_escape_string($row['saved_by_admin_id']) . "'");
201            list($row['editor']) = mysql_fetch_row($qid2);
202            $versions[] = $row;
203        }
204        if (is_array($versions) && !empty($versions)) {
205            return $versions;
206        } else {
207            return false;
208        }
209    }
210
211    /**
212     * Get the version record for a specified version id.
213     *
214     * @param string $version_id    The id of the version to restore.
215     *
216     * @return mixed                Array of data saved in version, or false if none.
217     */
218    function getVerson($version_id)
219    {
220        // Get version data.
221        $qid = dbQuery("
222            SELECT * FROM version_tbl
223            WHERE version_id = '" . mysql_real_escape_string($version_id) . "'
224        ");
225        return mysql_fetch_assoc($qid);
226    }
227
228    /**
229     * Get the data stored for a specified version id.
230     *
231     * @param string $version_id    The id of the version to restore.
232     *
233     * @return mixed                Array of data saved in version, or false if none.
234     */
235    function getData($version_id)
236    {
237        // Get version data.
238        $qid = dbQuery("
239            SELECT * FROM version_tbl
240            WHERE version_id = '" . mysql_real_escape_string($version_id) . "'
241        ");
242        $record = mysql_fetch_assoc($qid);
243        if (isset($record['version_data'])) {
244            return unserialize(gzuncompress($record['version_data']));
245        } else {
246            return false;
247        }
248    }
249
250    /**
251     * Get the current record data from the original table.
252     *
253     * @param string $version_id    The id of the version to restore.
254     *
255     * @return mixed                Array of data saved in version, or false if none.
256     */
257    function getCurrent($record_table, $record_key, $record_val)
258    {
259        $qid = dbQuery("
260            SELECT * FROM " . mysql_real_escape_string($record_table) . "
261            WHERE " . mysql_real_escape_string($record_key) . " = '" . mysql_real_escape_string($record_val) . "'
262        ");
263        if ($record = mysql_fetch_assoc($qid)) {
264            return $record;
265        } else {
266            return false;
267        }
268    }
269
270
271} // End of class.
272?>
Note: See TracBrowser for help on using the repository browser.