@@ -69,6 +69,11 @@ class Config extends Singleton
6969 */
7070 private $ statusIsValid = false ;
7171
72+ /**
73+ * @var array list of revision relevant data
74+ */
75+ private $ revisionContext = [];
76+
7277 /**
7378 * @var float current modification time of our known config
7479 */
@@ -465,76 +470,101 @@ public function __toString()
465470 return $ dom ->saveXML ();
466471 }
467472
473+ /**
474+ * @return array revision key/values
475+ */
476+ public function getRevisionContext ()
477+ {
478+ $ revision = $ this ->revisionContext ;
479+ $ user_host = !empty ($ _SERVER ['REMOTE_ADDR ' ]) ? "@ " . $ _SERVER ['REMOTE_ADDR ' ] : '' ;
480+ if (!empty ($ _SESSION ["Username " ])) {
481+ $ revision ['username ' ] = $ _SESSION ["Username " ] . $ user_host ;
482+ } elseif (!isset ($ revision ['username ' ])) {
483+ $ revision ['username ' ] = "(system) " . $ user_host ;
484+ }
485+ $ revision ['description ' ] = sprintf (
486+ gettext ('%s made changes ' ),
487+ !empty ($ _SERVER ['REQUEST_URI ' ]) ? $ _SERVER ['REQUEST_URI ' ] : $ _SERVER ['SCRIPT_NAME ' ]
488+ );
489+ // append session revision tags when supplied (keys start with xrevision_)
490+ if (!empty ($ _SESSION ) && is_array ($ _SESSION )) {
491+ foreach ($ _SESSION as $ key => $ value ) {
492+ if (stripos ($ key , 'xrevision_ ' ) === 0 && !isset ($ revision [substr ($ key ,10 )])) {
493+ $ revision [substr ($ key ,10 )] = $ value ;
494+ }
495+ }
496+
497+ }
498+ $ revision ['time ' ] = empty ($ timestamp ) ? microtime (true ) : $ timestamp ;
499+
500+ return $ revision ;
501+ }
502+
503+ /**
504+ * set revision payload
505+ * @param array revision payload
506+ */
507+ public function setRevisionContext ($ ctx )
508+ {
509+ if (is_array ($ ctx )) {
510+ $ this ->revisionContext = $ ctx ;
511+ return true ;
512+ }
513+ return false ;
514+ }
515+
468516 /**
469517 * update config revision information (ROOT.revision tag)
470518 * @param array|null $revision revision tag (associative array)
471519 * @param \SimpleXMLElement|null pass trough xml node
520+ * @return array revision data
472521 */
473522 private function updateRevision ($ revision , $ node = null , $ timestamp = null )
474523 {
475- // if revision info is not provided, create a default.
524+ /* If revision info is not provided, create one. $revision is used for recursion */
476525 if (!is_array ($ revision )) {
477- $ revision = array ();
478- // try to fetch userinfo from session
479- if (!empty ($ _SESSION ["Username " ])) {
480- $ revision ['username ' ] = $ _SESSION ["Username " ];
481- } else {
482- $ revision ['username ' ] = "(system) " ;
483- }
484- if (!empty ($ _SERVER ['REMOTE_ADDR ' ])) {
485- $ revision ['username ' ] .= "@ " . $ _SERVER ['REMOTE_ADDR ' ];
486- }
487- if (!empty ($ _SERVER ['REQUEST_URI ' ])) {
488- // when update revision is called from a controller, log the endpoint uri
489- $ revision ['description ' ] = sprintf (gettext ('%s made changes ' ), $ _SERVER ['REQUEST_URI ' ]);
490- } else {
491- // called from a script, log script name and path
492- $ revision ['description ' ] = sprintf (gettext ('%s made changes ' ), $ _SERVER ['SCRIPT_NAME ' ]);
493- }
526+ $ revision = $ this ->getRevisionContext ();
494527 }
495-
496- // always set timestamp
497- $ revision ['time ' ] = empty ($ timestamp ) ? microtime (true ) : $ timestamp ;
498-
499528 if ($ node == null ) {
500- if (isset ($ this ->simplexml ->revision )) {
501- $ node = $ this ->simplexml ->revision ;
529+ if (! isset ($ this ->simplexml ->revision )) {
530+ $ target = $ this ->simplexml ->addChild ( " revision " ) ;
502531 } else {
503- $ node = $ this ->simplexml ->addChild ("revision " );
532+ $ target = $ this ->simplexml ->revision ;
533+ foreach (iterator_to_array ($ target ->children ()) as $ child ) {
534+ unset($ target ->{$ child ->getName ()});
535+ }
504536 }
537+ } else {
538+ $ target = $ node ;
505539 }
506- foreach ($ revision as $ revKey => $ revItem ) {
507- if (isset ($ node ->{$ revKey })) {
508- // key already in revision object
509- $ childNode = $ node ->{$ revKey };
510- } else {
511- $ childNode = $ node ->addChild ($ revKey );
512- }
513- if (is_array ($ revItem )) {
514- $ this ->updateRevision ($ revItem , $ childNode );
540+
541+ array_walk ($ revision , function ($ value , $ key ) use (&$ target ) {
542+ $ node = $ target ->addChild ($ key );
543+ if (is_array ($ value )) {
544+ $ this ->updateRevision ($ value , $ node );
515545 } else {
516- $ childNode [0 ] = $ revItem ;
546+ $ node [0 ] = $ value ;
517547 }
518- }
548+ });
549+
550+ return $ revision ;
519551 }
520552
521553 /**
522554 * send config change to audit log including the context we currently know of.
555+ * @param string $backup_filename new backup filename
556+ * @param array $revision revision adata used
523557 */
524- private function auditLogChange ($ backup_filename , $ revision = null )
558+ private function auditLogChange ($ backup_filename , $ revision )
525559 {
526560 openlog ("audit " , LOG_ODELAY , LOG_AUTH );
527- $ append_message = "" ;
528- if (is_array ($ revision ) && !empty ($ revision ['description ' ])) {
529- $ append_message = sprintf (" [%s] " , $ revision ['description ' ]);
530- }
531561 syslog (LOG_NOTICE , sprintf (
532562 "user %s%s changed configuration to %s in %s%s " ,
533- ! empty ( $ _SESSION [ " Username " ]) ? $ _SESSION [ " Username " ] : " (system) " ,
534- !empty ($ _SERVER [ ' REMOTE_ADDR ' ]) ? " @ " . $ _SERVER [ ' REMOTE_ADDR ' ] : "" ,
563+ $ revision [ ' username ' ] ,
564+ !empty ($ revision [ ' impersonated_by ' ]) ? sprintf ( " (%s) " , $ revision [ ' impersonated_by ' ]) : '' ,
535565 $ backup_filename ,
536566 !empty ($ _SERVER ['REQUEST_URI ' ]) ? $ _SERVER ['REQUEST_URI ' ] : $ _SERVER ['SCRIPT_NAME ' ],
537- $ append_message
567+ $ revision [ ' description ' ] ?? ''
538568 ));
539569 closelog ();
540570 }
@@ -716,7 +746,7 @@ public function save($revision = null, $backup = true)
716746 $ this ->checkvalid ();
717747 $ time = microtime (true );
718748 // update revision information ROOT.revision tag, align timestamp to backup output
719- $ this ->updateRevision ($ revision , null , $ time );
749+ $ revision = $ this ->updateRevision ($ revision , null , $ time );
720750
721751 if ($ this ->config_file_handle !== null ) {
722752 if (flock ($ this ->config_file_handle , LOCK_EX )) {
0 commit comments