2 import(
'Dataface/AuthenticationTool.php');
70 'history__id'=>array(
'Type'=>
'int(11)',
'Extra'=>
'auto_increment'),
71 'history__language'=> array(
'Type'=>
'varchar(2)'),
72 'history__comments'=> array(
'Type'=>
'text'),
73 'history__user'=>array(
'Type'=>
'varchar(32)'),
74 'history__state'=>array(
'Type'=>
'int(5)'),
75 'history__modified'=>array(
'Type'=>
'datetime')
94 function logRecord(&$record, $comments=
'', $lang=null, $state=null){
98 $lang =
$app->_conf[
'lang'];
101 if ( !isset($state) ){
106 $fieldnames = array_keys($record->_table->fields());
107 $sql =
'select `'.implode(
'`,`', $fieldnames).
'` from `'.$record->_table->tablename.
'` where';
108 $keynames = array_keys($record->_table->keys());
109 $where_clauses = array();
110 foreach ( $keynames as $keyname){
111 $where_clauses[] =
'`'.$keyname.
'`=\''.addslashes($record->strval($keyname)).
'\'';
113 $sql .=
' '.implode(
' and ', $where_clauses);
115 if ( @
$app->_conf[
'multilingual_content'] ){
117 $sql = $db->translate_query($sql, $lang);
122 $userRecord =& $auth->getLoggedInUser();
123 if ( !isset($userRecord) ){
126 $user = $auth->getLoggedInUsername();
130 $insertsql =
"insert into `".$this->logTableName($record->_table->tablename).
"`
131 (`".implode(
'`,`', $fieldnames).
"`, `history__language`,`history__comments`,`history__user`,`history__state`,`history__modified`)
132 select *, '".addslashes($lang).
"','".addslashes($comments).
"','".addslashes($user).
"','".addslashes($state).
"', NOW()
133 from (".$sql.
") as t";
135 $res = mysql_query($insertsql,
$app->db());
138 $res = mysql_query($insertsql,
$app->db());
142 trigger_error(mysql_error(
$app->db()), E_USER_ERROR);
146 $hid = mysql_insert_id(
$app->db());
148 $this->
logField($record, $fieldname, $hid);
168 $s = DIRECTORY_SEPARATOR;
169 switch(strtolower(
$field[
'Type'])){
171 $savepath =
$field[
'savepath'];
172 if ( $savepath{strlen($savepath)-1} != $s ) $savepath.=$s;
174 if ( !is_readable($savepath.$record->val(
$fieldname)) )
break;
175 if ( !file_exists($savepath) || !is_dir($savepath) )
178 'scripts.Dataface.HistoryTool.logField.ERROR_CONTAINER_FIELD_SAVEPATH_MISSING',
179 "Field {$fieldname} is a Container field but its corresponding savepath {$savepath} does not exist. Please create the directory {$savepath} and ensure that it is writable by the web server",
180 array(
'fieldname'=>
$fieldname,
'savepath'=>$savepath)
182 $histpath = $savepath.
'.dataface_history'.$s;
183 if ( !file_exists($histpath) ){
184 $res = mkdir($histpath, 0777);
185 if ( !$res ) trigger_error(
187 'scripts.Dataface.HistoryTool.logField.ERROR_FAILED_TO_MAKE_HISTORY_FOLDER',
188 "Failed to make history folder {$histpath} to store the history for container field {$fieldname} in table {$record->_table->tablename}. It could be a permissions problem. Please ensure that the {$savepath} directory is writable by the web server.",
189 array(
'histpath'=>$histpath,
'fieldname'=>
$fieldname,
'tablename'=>$record->_table->tablename,
'savepath'=>$savepath)
193 if ( !is_dir($histpath) ){
196 'scripts.Dataface.HistoryTool.logField.ERROR_NOT_A_DIRECTORY',
197 "The history path for the field {$fieldname} in table {$record->_table->tablename} is not a directory. Perhaps a file has been uploaded with the reserved name '.history'. Please delete this file to allow Dataface's history feature to work properly.",
198 array(
'fieldname'=>
$fieldname,
'tablename'=>$record->_table->tablename)
201 if ( !is_writable($histpath) ){
202 trigger_error(
"The history folder for field {$fieldname} of table {$record->_table->tablename} is not writable by the web server. Please make it writable by the web server for Dataface's history feature to work properly.", E_USER_ERROR);
206 $destpath = $histpath.$history_id;
207 if ( file_exists($destpath) ) {
return;}
209 $srcpath = $savepath.$record->val(
$fieldname);
210 $res = copy($srcpath,$destpath);
239 if ( mysql_num_rows(mysql_query(
"show tables like '".$name.
"'",
$app->db())) == 0 ){
244 if ( !$res ) trigger_error(mysql_error(
$app->db()), E_USER_ERROR);
245 $history_fields = array();
246 while ( $row = mysql_fetch_assoc($res) ){
247 $history_fields[$row[
'Field']] = $row;
249 @mysql_free_result($res);
252 $fieldnames = array_keys(
$table->fields());
255 if ( !isset($history_fields[$fieldname]) ){
257 $type = (( strcasecmp(
$field[
'Type'],
'container') === 0 ) ?
'varchar(64)' :
$field[
'Type'] );
258 $sql =
"alter table `".$name.
"` add column `".$fieldname.
"` {$type} DEFAULT NULL";
259 $res = mysql_query($sql,
$app->db());
261 trigger_error(mysql_error(
$app->db()), E_USER_ERROR);
270 if ( !isset($history_fields[$fieldname]) ){
271 $sql =
"alter table `".$name.
"` add column `".$fieldname.
"` ".$history_fields[
$fieldname][
'Type'].
' '.@$history_fields[
$fieldname][
'Extra'];
272 $res = mysql_query($sql,
$app->db());
274 trigger_error(mysql_error(
$app->db()), E_USER_ERROR);
290 $sql =
"create table `".$this->logTableName(
$tablename).
"` (
291 `history__id` int(11) auto_increment NOT NULL,
292 `history__language` varchar(2) DEFAULT NULL,
293 `history__comments` text default null,
294 `history__user` varchar(32) default null,
295 `history__state` int(5) default 0,
296 `history__modified` datetime,";
299 $res = df_q(
"SHOW TABLE STATUS LIKE '".addslashes(
$tablename).
"'");
300 $status = mysql_fetch_assoc($res);
301 $charset = substr($status[
'Collation'],0, strpos($status[
'Collation'],
'_'));
302 $collation = $status[
'Collation'];
303 $fieldnames = array_keys(
$table->fields());
304 $fielddefs = array();
307 $type = (( strcasecmp(
$field[
'Type'],
'container') === 0 ) ?
'varchar(64)' :
$field[
'Type'] );
308 $fielddefs[] =
"`".$fieldname.
"` ".$type;
312 $sql .= implode(
",\n",$fielddefs);
314 PRIMARY KEY (`history__id`),
315 KEY prikeys using hash (`".implode(
'`,`', array_keys(
$table->keys())).
"`),
316 KEY datekeys using btree (`history__modified`)) ".(@$status[
'Engine'] ?
"ENGINE=".$status[
'Engine']:
'').
" ".($charset ?
"DEFAULT CHARSET=".$charset.($collation ?
" COLLATE $collation":
''):
'');
318 $res = mysql_query($sql,
$app->db());
320 trigger_error(mysql_error(
$app->db()), E_USER_ERROR);
337 import(
'Text/Diff.php');
338 import(
'Text/Diff/Renderer/inline.php');
342 df_translate(
'scripts.Dataface.HistoryTool.getDiffs.ERROR_HISTORY_TABLE_DOES_NOT_EXIST',
343 "History table for '{$tablename}' does not exist, so we cannot obtain changes for records of that table.",
347 $rec1 = df_get_record($htablename, array(
'history__id'=>$id1));
353 $query = $rec1->strvals(array_keys(
$table->keys()));
355 $io->lang = $rec1->val(
'history__language');
357 $io->read($query, $rec2);
359 $rec2 = df_get_record($htablename, array(
'history__id'=>$id2));
362 $vals1 = $rec1->strvals();
363 $vals2 = $rec2->strvals();
365 $vals_diff = array();
366 $renderer =
new Text_Diff_Renderer_inline();
367 foreach ($vals2 as $key=>$val ){
368 $diff =
new Text_Diff(explode(
"\n", @$vals1[$key]), explode(
"\n", $val));
370 $vals_diff[$key] = $renderer->render($diff);
394 if ( !isset($date2) ) $date2 = date(
'Y-m-d H:i:s');
395 $time1 = strtotime($date1);
396 $time2 = strtotime($date2);
397 if ( $time1 > $time2 ){
403 if ( !isset($lang) ) $lang =
$app->_conf[
'lang'];
404 $htablename = $record->_table->tablename.
'__history';
407 df_translate(
'scripts.Dataface.HistoryTool.getDiffs.ERROR_HISTORY_TABLE_DOES_NOT_EXIST',
408 "History table for '{$tablename}' does not exist, so we cannot obtain changes for records of that table.",
412 $keyvals = $record->strvals(array_keys($record->_table->keys()));
413 foreach ($keyvals as $key=>$val){
414 $clauses[] =
"`{$key}`='".addslashes($val).
"'";
416 $clauses[] =
"`history__language`='".addslashes($lang).
"'";
418 $sql =
"select `history__id` from `{$htablename}` where ".implode(
' and ',$clauses);
419 $sql1 = $sql .
" and `history__modified` <= '".addslashes($date1).
"' order by `history__modified` desc limit 1";
420 $sql2 = $sql .
" and `history__modified` <= '".addslashes($date2).
"' order by `history__modified` desc limit 1";
422 $res2 = mysql_query($sql2,
$app->db());
425 trigger_error(mysql_error(
$app->db()), E_USER_ERROR);
427 if ( mysql_num_rows($res2) == 0 ){
431 list($id2) = mysql_fetch_row($res2);
432 @mysql_free_result($res2);
434 $res1 = mysql_query($sql1,
$app->db());
437 trigger_error(mysql_error(
$app->db()), E_USER_ERROR);
439 if ( mysql_num_rows($res1) == 0 ){
440 $rec = df_get_record($htablename, array(
'history__id'=>$id2));
444 'scripts.Dataface.HistoryTool.getDiffsByDate.ERROR_FAILED_TO_LOAD_HISTORY_RECORD',
445 "Failed to load history record with id {$id2}",
451 list($id1) = mysql_fetch_row($res1);
452 @mysql_free_result($res1);
465 else $fieldnames = array_keys($record->_table->fields());
468 foreach ($fieldnames as $k=>
$f){
469 $fld = $record->table()->getField(
$f);
470 if ( @$fld[
'encryption'] )
continue;
471 if ( $record->checkPermission(
'edit', array(
'field'=>
$f)) ){
477 $htablename = $record->_table->tablename.
'__history';
478 $res = mysql_query(
"select `".implode(
'`,`', $fieldnames).
"`,`history__language` from `{$htablename}` where `history__id`='".addslashes($id).
"'",
$app->db());
479 if ( !$res ) trigger_error(mysql_error(
$app->db()), E_USER_ERROR);
480 if ( mysql_num_rows($res) == 0 )
483 'scripts.Dataface.HistoryTool.restore.ERROR_NO_SUCH_RECORD',
484 "Could not restore record with id {$id} in table {$htablename} because no such record exists. Perhaps the history was cleaned out.",
485 array(
'id'=>$id,
'tablename'=>$htablename)
487 $vals = mysql_fetch_assoc($res);
488 @mysql_free_result($res);
489 $old_record =
new Dataface_Record($record->_table->tablename, $record->getValues());
490 $lang = $vals[
'history__language'];
491 unset($vals[
'history__language']);
495 $record->setValues($vals);
497 $record->save($lang, $secure);
498 foreach ($fieldnames as $fld){
517 $htablename = $record->_table->tablename.
'__history';
519 switch (strtolower(
$field[
'Type'])){
521 $savepath =
$field[
'savepath'];
522 if ( $savepath{strlen($savepath)-1} !=
'/' ) $savepath .=
'/';
526 $filepath = $savepath.basename($old_record->val(
$fieldname));
527 if ( file_exists($filepath) ) unlink($filepath);
530 $hsavepath = $savepath.
'.dataface_history/'.$id;
531 if ( !file_exists($hsavepath) || !is_readable($hsavepath) )
return false;
532 $filename = basename($record->val(
$fieldname));
533 $filepath = $savepath.
'/'.$filename;
534 while ( file_exists($filepath) ){
535 $filepath = $savepath.
'/'.strval(rand(0,10000)).
'_'.$filename;
537 return copy($hsavepath, $filepath);
589 if ( !isset($lang) ) $lang =
$app->_conf[
'lang'];
590 $htablename = $record->_table->tablename.
'__history';
594 'scripts.Dataface.HistoryTool.getDiffs.ERROR_HISTORY_TABLE_DOES_NOT_EXIST',
595 "History table for '{$record->_table->tablename}' does not exist, so we cannot obtain changes for records of that table.",
596 array(
'tablename'=>$record->_table->tablename)
599 $keyvals = $record->strvals(array_keys($record->_table->keys()));
600 foreach ($keyvals as $key=>$val){
601 $clauses[] =
"`{$key}`='".addslashes($val).
"'";
603 $clauses[] =
"`history__language`='".addslashes($lang).
"'";
605 $sql =
"select `history__id` from `{$htablename}` where ".implode(
' and ',$clauses).
"
606 and `history__modified` <= '".addslashes($date).
"' order by `history__modified` desc limit 1";
608 $res = mysql_query($sql,
$app->db());
609 if ( !$res ) trigger_error(mysql_error(
$app->db()), E_USER_ERROR);
610 if ( mysql_num_rows($res) == 0 ){
613 list($id) = mysql_fetch_row($res);
614 @mysql_free_result($res);
615 if ( $idonly )
return $id;
636 'scripts.Dataface.HistoryTool.getDiffs.ERROR_HISTORY_TABLE_DOES_NOT_EXIST',
637 "History table for '{$tablename}' does not exist, so we cannot obtain changes for records of that table.",
641 $rec = df_get_record($htablename, array(
'history__id'=>$id));
656 $history_tablename = $record->_table->tablename.
'__history';
658 $keys = $record->strvals(array_keys($record->_table->keys()));
660 foreach (
$keys as $key=>$val){
661 $clauses[] =
"`{$key}`='".addslashes($val).
"'";
663 if ( isset($lang) ) $clauses[] =
"`history__language` = '".addslashes($lang).
"'";
664 $where = implode(
' and ', $clauses);
665 if ( isset($limit) ) $limit =
"LIMIT $limit";
668 $sql =
"select `".implode(
'`,`', array_keys($this->meta_fields)).
"` from `{$history_tablename}` where {$where} order by `history__modified` desc {$limit}";
670 $res = mysql_query($sql,
$app->db());
671 if ( !$res ) trigger_error(mysql_error(
$app->db()), E_USER_ERROR);
673 while ( $row = mysql_fetch_assoc($res) )
$out[] = $row;
674 @mysql_free_result($res);
689 $htablename = $record->_table->tablename.
'__history';
691 $keys = $record->strvals(array_keys($record->_table->keys()));
692 foreach (
$keys as $key=>$val){
693 $query[$key] =
'='.$val;
697 $sql = $qbuilder->select(array(
'history__id'), $query);
698 $res = mysql_query($sql, df_db());
700 while ( $row = mysql_fetch_row($res) ) $ids[] = $row[0];
701 @mysql_free_result($res);
704 return df_get_records_array($htablename, $query);