1<?php 2/** 3 * e107 website system 4 * 5 * Copyright (C) 2008-2010 e107 Inc (e107.org) 6 * Released under the terms and conditions of the 7 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) 8 * 9 * Admin Log Handler 10 * 11 * USAGE: 12 * 13 * @example Log and Add to Message Handler: e107::getAdminLog()->addSuccess("Successfully executed")->save('PREF_01'); 14 * @example Log Only: e107::getAdminLog()->addSuccess("Successfully executed",false)->save('PREF_01'); 15 * @example Log Array Diff: e107::getAdminLog()->addArray($array1, $array2)->save('PREF_01'); 16 * @example Log Array Diff and Add to Message Handler: e107::getAdminLog()->addArray($array1, $array2, E_MESSAGE_ERROR )->save('PREF_01'); 17 * 18*/ 19 20if (!defined('e107_INIT')) 21{ 22 exit; 23} 24 25define('LOG_MESSAGE_NODISPLAY', 'nodisplay'); 26 27/** 28 * Admin logging class. 29 * 30 * @package e107 31 * @subpackage e107_handlers 32 * @version $Id$; 33 * @author e107steved 34 */ 35class e_admin_log 36{ 37 38 /** 39 * Contains default class options, plus any that are overidden by the constructor 40 * 41 * @var array 42 */ 43 protected $_options = array('log_level'=>2, 'backtrace'=>false, ); 44 45 protected $rldb = NULL; // Database used by logging routine 46 47 48 49 protected $logFile = null; 50 /** 51 * Log messages 52 * @var array 53 */ 54 protected $_messages; 55 56 57 protected $_allMessages; // similar to $_messages except it is never flushed. 58 59 60 protected $_current_plugin = null; 61 62 63 /** 64 * Constructor. Sets up constants and overwrites default options where set. 65 * 66 * @param array $options 67 * @return null 68 */ 69 public function __construct($options = array()) 70 { 71 if(!empty($options)) 72 { 73 foreach ($options as $key=>$val) 74 { 75 $this->_options[$key] = $val; 76 } 77 } 78 79 define("E_LOG_INFORMATIVE", 0); // Minimal Log Level, including really minor stuff 80 define("E_LOG_NOTICE", 1); // More important than informative, but less important than notice 81 define("E_LOG_WARNING", 2); // Not anything serious, but important information 82 define("E_LOG_FATAL", 3); // An event so bad your site ceased execution. 83 define("E_LOG_PLUGIN", 4); // Plugin information 84 85 // Logging actions 86 define("LOG_TO_ADMIN", 1); 87 define("LOG_TO_AUDIT", 2); 88 define("LOG_TO_ROLLING", 4); 89 90 // User audit logging (intentionally start at 10 - stick to 2 digits) 91 // The last two digits must match that for the corresponding log message 92 define('USER_AUDIT_ADMIN', 10); // User data changed by admin 93 define('USER_AUDIT_SIGNUP', 11); // User signed up 94 define('USER_AUDIT_EMAILACK', 12); // User responded to registration email 95 define('USER_AUDIT_LOGIN', 13); // User logged in 96 define('USER_AUDIT_LOGOUT', 14); // User logged out 97 define('USER_AUDIT_NEW_DN', 15); // User changed display name 98 define('USER_AUDIT_NEW_PW', 16); // User changed password 99 define('USER_AUDIT_NEW_EML', 17); // User changed email 100 define('USER_AUDIT_PW_RES', 18); // Password reset/resent activation email 101 define('USER_AUDIT_NEW_SET', 19); // User changed other settings 102 define('USER_AUDIT_ADD_ADMIN', 20); // User added by admin 103 define('USER_AUDIT_MAIL_BOUNCE', 21); // User mail bounce 104 define('USER_AUDIT_BANNED', 22); // User banned 105 define('USER_AUDIT_BOUNCE_RESET', 23); // User bounce reset 106 define('USER_AUDIT_TEMP_ACCOUNT', 24); // User temporary account 107 108 // Init E_MESSAGE_* constants if not already done 109 // e107::getMessage(); - just include, message handler is creating session in construct 110 // it breaks stuff (see class2 - language detection and comments) 111 require_once(e_HANDLER.'message_handler.php'); 112 $this->_messages = array(); 113 $this->_allMessages = array(); 114 115 return null; 116 } 117 118 /** 119 * @DEPRECATED 120 * BC Alias of add(); 121 */ 122 public function log_event($event_title, $event_detail, $event_type = E_LOG_INFORMATIVE , $event_code = '') 123 { 124 return $this->add($event_title, $event_detail, $event_type, $event_code); 125 } 126 127 128 /** 129 * Save all logs in the queue to the database and render any unhidden messages with the message handler. 130 * @see alias flushMessages() method below. 131 * @param string $logTitle - title for log entry eg. 'PREF_01' 132 * @param int $logImportance [optional] default E_LOG_INFORMATIVE - passed directly to admin log 133 * @param string $logEventCode [optional] - passed directly to admin log 134 * @param string $mstack [optional] message stack passed to message handler 135 * @param int LOG_TO_ADMIN|LOG_TO_ROLLING|LOG_TO_AUDIT 136 * @return \e_admin_log 137 */ 138 public function save($logTitle, $logImportance = E_LOG_INFORMATIVE, $logEventCode = '', $mstack = false, $target = LOG_TO_ADMIN) 139 { 140 return $this->flushMessages($logTitle, $logImportance, $logEventCode, $mstack, $target); 141 } 142 143 144 145 146 /** 147 * Add and Save an event into the admin, rolling or user log. 148 * @param string $event_title 149 * @param mixed $event_details 150 * @param integer $event_type [optional] Log level eg. E_LOG_INFORMATIVE, E_LOG_NOTICE, E_LOG_WARNING, E_LOG_FATAL 151 * @param string $event_code [optional] - eg. 'BOUNCE' 152 * @param integer $target [optional] LOG_TO_ADMIN, LOG_TO_AUDIT, LOG_TO_ROLLING 153 * @param array $user - user to attribute the log to. array('user_id'=>2, 'user_name'=>'whoever'); 154 * @return e_admin_log 155 * 156 * Alternative admin log entry point - compatible with legacy calls, and a bit simpler to use than the generic entry point. 157 * ($eventcode has been added - give it a reference to identify the source module, such as 'NEWS_12' or 'ECAL_03') 158 * We also log everything (unlike 0.7, where admin log and debug stuff were all mixed up together) 159 * 160 * For multi-lingual logging (where the event title is shown in the language of the current user), LAN defines may be used in the title 161 * 162 * For generic calls, leave $event_code as empty, and specify a constant string STRING_nn of less than 10 characters for the event title 163 * Typically the 'STRING' part of the name defines the area originating the log event, and the 'nn' is a numeric code 164 * This is stored as 'LAN_AL_STRING_NN', and must be defined in a language file which is loaded during log display. 165 * 166 167 */ 168 public function add($event_title, $event_detail, $event_type = E_LOG_INFORMATIVE , $event_code = '', $target = LOG_TO_ADMIN, $userData=null ) 169 { 170 if ($event_code == '') 171 { 172 if (strlen($event_title) <= 12) 173 { // Assume the title is actually a reference to the event 174 $event_code = $event_title; 175 $event_title = 'LAN_AL_'.$event_title; 176 } 177 else 178 { 179 $event_code = 'ADMIN'; 180 } 181 } 182 183 if (!is_array($event_detail)) 184 { 185 // auto-format long details - TODO - shrink details on administration log page, expand/show in DHTML window full details. 186 $event_detail = str_replace("\n", "[!br!]", $event_detail); 187 } 188 189 if ($this->_options['backtrace'] == true) 190 { 191 $event_detail .= "\n\n".debug_backtrace(false); 192 } 193 194 195 $this->e_log_event($event_type, -1, $event_code, $event_title, $event_detail, FALSE, $target, $userData); 196 197 return $this; 198 } 199 200 /** 201 * Alias for deprecated e_log_event 202 * @param $importance 203 * @param $source_call 204 * @param string $eventcode 205 * @param string $event_title 206 * @param string $explain 207 * @param bool $finished 208 * @param int $target_logs 209 * @param null $userData 210 * @return null 211 */ 212 public function addEvent($importance, $source_call, $eventcode = "GEN", $event_title = "Untitled", $explain = "", $finished = FALSE, $target_logs = LOG_TO_AUDIT, $userData=null ) 213 { 214 return $this->e_log_event($importance, $source_call, $eventcode, $event_title, $explain, $finished, $target_logs, $userData); 215 216 } 217 218 /** 219 Generic log entry point 220 ----------------------- 221 Example call: (Deliberately pick separators that shouldn't be in file names) 222 e_log_event(E_LOG_NOTICE,__FILE__."|".__FUNCTION__."@".__LINE__,"ECODE","Event Title","explanatory message",FALSE,LOG_TO_ADMIN); 223 or: 224 e_log_event(E_LOG_NOTICE,debug_backtrace(),"ECODE","Event Title","explanatory message",TRUE,LOG_TO_ROLLING); 225 * 226 * @param int $importance - importance of event - 0..4 or so 227 * @param mixed $source_call - either: string identifying calling file/routine 228 * or: a number 0..9 identifying info to log from debug_backtrace() 229 * or: empty string, in which case first entry from debug_backtrace() logged 230 * or: an array, assumed to be from passing debug_backtrace() as a parameter, in which case relevant 231 * information is extracted and the argument list from the first entry logged 232 * or: -1, in which case no information logged 233 * @param string $eventcode - abbreviation listing event type 234 * @param string $event_title - title of event - pass standard 'LAN_ERROR_nn' defines to allow language translation 235 * @param string $explain - detail of event 236 * @param bool $finished - if TRUE, aborts execution 237 * @param int $target_logs - flags indicating which logs to update - if entry to be posted in several logs, add (or 'OR') their defines: 238 * LOG_TO_ADMIN - admin log 239 * LOG_TO_AUDIT - audit log 240 * LOG_TO_ROLLING - rolling log 241 * @param array $userData - attribute user to log entry. array('user_id'=>2, 'user_name'=>'whatever'); 242 * @return null 243 244 * @todo - check microtime() call 245 * @deprecated - use add() method instead or addEvent() as a direct replacement. 246 */ 247 public function e_log_event($importance, $source_call, $eventcode = "GEN", $event_title = "Untitled", $explain = "", $finished = FALSE, $target_logs = LOG_TO_AUDIT, $userData=null ) 248 { 249 $e107 = e107::getInstance(); 250 $pref = e107::getPref(); 251 $tp = e107::getParser(); 252 253 list($time_usec, $time_sec) = explode(" ", microtime(FALSE)); // Log event time immediately to minimise uncertainty 254 $time_usec = $time_usec * 1000000; 255 256 if ($this->rldb == NULL) 257 $this->rldb = e107::getDb('adminlog'); // Better use our own db - don't know what else is going on 258 259 if (is_bool($target_logs)) 260 { // Handle the legacy stuff for now - some old code used a boolean to select admin or rolling logs 261 $target_logs = $target_logs ? LOG_TO_ADMIN : LOG_TO_ROLLING; 262 } 263 264 //--------------------------------------- 265 // Calculations common to all logs 266 //--------------------------------------- 267 268 $userid = deftrue('USER') ? USERID : 0; 269 $userstring = deftrue('USER') ? USERNAME : 'LAN_ANONYMOUS'; 270 $userIP = e107::getIPHandler()->getIP(FALSE); 271 272 if(!empty($userData['user_id'])) 273 { 274 $userid = $userData['user_id']; 275 } 276 277 if(!empty($userData['user_name'])) 278 { 279 $userstring = $userData['user_name']; 280 } 281 282 if(!empty($userData['user_ip'])) 283 { 284 $userIP = $userData['user_ip']; 285 } 286 287 $importance = $tp->toDB($importance, true, false, 'no_html'); 288 $eventcode = $tp->toDB($eventcode, true, false, 'no_html'); 289 290 if (is_array($explain)) 291 { 292 /* 293 $line = ''; 294 $spacer = ''; 295 foreach ($explain as $k=>$v) 296 { 297 $line .= $spacer.$k.'=>'.$v; 298 $spacer = '[!br!]'; 299 } 300 $explain = $line; 301 unset($line); 302 */ 303 $explain = str_replace("\n",'[!br!]',print_r($explain,true)); 304 305 } 306 307 308 $explain = e107::getDb()->escape($tp->toDB($explain, true, false, 'no_html')); 309 $event_title = $tp->toDB($event_title, true, false, 'no_html'); 310 311 //--------------------------------------- 312 // Admin Log 313 //--------------------------------------- 314 if ($target_logs & LOG_TO_ADMIN) // Admin log - assume all fields valid 315 { 316 // $qry = " null, ".intval($time_sec).','.intval($time_usec).", '{$importance}', '{$eventcode}', {$userid}, '{$userIP}', '{$event_title}', '{$explain}' "; 317 318 $adminLogInsert = array( 319 'dblog_id' => null, 320 'dblog_type' => $importance, 321 'dblog_eventcode' => $eventcode, 322 'dblog_datestamp' => time(), 323 'dblog_microtime' => intval($time_usec), 324 'dblog_user_id' => $userid, 325 'dblog_ip' => $userIP, 326 'dblog_title' => $event_title, 327 'dblog_remarks' => $explain 328 ); 329 330 $this->rldb->insert("admin_log", $adminLogInsert); 331 } 332 333 //--------------------------------------- 334 // Audit Log 335 //--------------------------------------- 336 // Add in audit log here 337 338 //--------------------------------------- 339 // Rolling Log 340 //--------------------------------------- 341 if (($target_logs & LOG_TO_ROLLING) && vartrue($pref['roll_log_active'])) 342 { // Rolling log 343 344 // Process source_call info 345 //--------------------------------------- 346 if (is_numeric($source_call) && ($source_call >= 0)) 347 { 348 $back_count = 1; 349 $i = 0; 350 if (is_numeric($source_call) || ($source_call == '')) 351 { 352 $back_count = $source_call + 1; 353 $source_call = debug_backtrace(); 354 $i = 1; // Don't want to print the entry parameters to this function - we know all that! 355 } 356 } 357 358 if (is_array($source_call)) 359 { // Print the debug_backtrace() array 360 while ($i < $back_count) 361 { 362 $source_call[$i]['file'] = $e107->fix_windows_paths($source_call[$i]['file']); // Needed for Windoze hosts. 363 $source_call[$i]['file'] = str_replace($e107->file_path, "", $source_call[$i]['file']); // We really just want a e107 root-relative path. Strip out the root bit 364 $tmp = $source_call[$i]['file']."|".$source_call[$i]['class'].$source_call[$i]['type'].$source_call[$i]['function']."@".$source_call[$i]['line']; 365 foreach ($source_call[$i]['args'] as $k=>$v) 366 { // Add in the arguments 367 $explain .= "[!br!]".$k."=".$v; 368 } 369 $i++; 370 if ($i < $back_count) 371 $explain .= "[!br!]-------------------"; 372 if (!isset($tmp1)) 373 $tmp1 = $tmp; // Pick off the immediate caller as the source 374 } 375 if (isset($tmp1)) $source_call = $tmp1; 376 else $source_call = 'Root level'; 377 } 378 else 379 { 380 $source_call = $e107->fix_windows_paths($source_call); // Needed for Windoze hosts. 381 $source_call = str_replace($e107->file_path, "", $source_call); // We really just want a e107 root-relative path. Strip out the root bit 382 $source_call = $tp->toDB($source_call, true, false, 'no_html'); 383 } 384 // else $source_call is a string 385 386 // Save new rolling log record 387 $this->rldb->insert("dblog", "0, ".intval($time_sec).', '.intval($time_usec).", '{$importance}', '{$eventcode}', {$userid}, '{$userstring}', '{$userIP}', '{$source_call}', '{$event_title}', '{$explain}' "); 388 389 // Now delete any old stuff 390 if(!empty($pref['roll_log_days'])) 391 { 392 $days = intval($pref['roll_log_days']); 393 $this->rldb->delete("dblog", "dblog_datestamp < '".intval(time() - ($days * 86400))."' "); 394 } 395 } 396 397 if ($finished) 398 exit; // Optional abort for all logs 399 400 return null; 401 } 402 403 public function setCurrentPlugin($plugdir) 404 { 405 $this->_current_plugin = $plugdir; 406 407 return $this; 408 } 409 410 /**-------------------------------------- 411 * USER AUDIT ENTRY 412 *-------------------------------------- 413 * Log user-related events 414 * @param int $event_code is a defined constant (see above) which specifies the event 415 * @param array $event_data is an array of data fields whose keys and values are logged (usually user data, but doesn't have to be - can add messages here) 416 * @param int $id 417 * @param string $u_name 418 * both $id and $u_name are left blank except for admin edits and user login, where they specify the id and login name of the 'target' user 419 * 420 * @return bool 421 */ 422 function user_audit($event_type, $event_data, $id = '', $u_name = '') 423 { 424 list($time_usec, $time_sec) = explode(" ", microtime()); // Log event time immediately to minimise uncertainty 425 426 $time_usec = $time_usec * 1000000; 427 428 if(!is_numeric($event_type)) 429 { 430 $title = "User Audit Event-Type Failure: "; 431 $title .= (string) $event_type; 432 $debug = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,4); 433 $debug[0] = e_REQUEST_URI; 434 435 $this->e_log_event(4, $debug[1]['file']."|".$debug[1]['function']."@".$debug[1]['line'], "USERAUDIT", $title, $debug, FALSE); 436 return false; 437 } 438 439 // See whether we should log this 440 $user_logging_opts = e107::getConfig()->get('user_audit_opts'); 441 442 if (!isset($user_logging_opts[$event_type])) // Finished if not set to log this event type 443 { 444 return false; 445 } 446 447 if(empty($event_data)) 448 { 449 $backt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS,4); 450 $event_data = $backt; 451 } 452 453 454 if($this->rldb == null) 455 { 456 $this->rldb = e107::getDb('rldb'); // Better use our own db - don't know what else is going on 457 } 458 459 if(!empty($id)) 460 { 461 $userid = $id; 462 } 463 else 464 { 465 $userid = (USER === true) ? USERID : 0; 466 } 467 468 if(!empty($u_name)) 469 { 470 $userstring = $u_name; 471 } 472 else 473 { 474 $userstring = (USER === true ? USERNAME : "LAN_ANONYMOUS"); 475 } 476 477 $userIP = e107::getIPHandler()->getIP(false); 478 479 $eventcode = 'USER_'.$event_type; 480 481 $title = 'LAN_AUDIT_LOG_0'.$event_type; // This creates a string which will be displayed as a constant 482 483 $insertQry = array( 484 'dblog_id' => 0, 485 'dblog_datestamp' => intval($time_sec), 486 'dblog_microtime' => intval($time_usec), 487 'dblog_eventcode' => $eventcode, 488 'dblog_user_id' => $userid, 489 'dblog_user_name' => $userstring, 490 'dblog_ip' => $userIP, 491 'dblog_title' => $title, 492 'dblog_remarks' => print_r($event_data,true), 493 ); 494 495 if($this->rldb->insert("audit_log", $insertQry)) 496 { 497 return true; 498 } 499 500 return false; 501 } 502 503 504 /* Legacy function probably not needed 505 function get_log_events($count = 15, $offset) 506 { 507 global $sql; 508 $count = intval($count); 509 return "Not implemented yet"; 510 } 511 */ 512 513 514 515 /** 516 * Removes all events older than $days, or truncates the table if $days == false 517 * 518 * @param integer|false $days 519 * @return void 520 */ 521 public function purge_log_events($days) 522 { 523 global $sql; 524 if ($days == false) 525 { // $days is false, so truncate the log table 526 $sql->gen("TRUNCATE TABLE #dblog "); 527 } 528 else 529 { // $days is set, so remove all entries older than that. 530 $days = intval($days); 531 $mintime = $days * 24 * 60 * 60; 532 $time = time() - $mintime; 533 $sql->db_Delete("dblog", "WHERE `dblog_datestamp` < {$time}", true); 534 } 535 } 536 537 //-------------------------------------- 538 // HELPER ROUTINES 539 //-------------------------------------- 540 /** 541 * Generic routine to log changes to an array. Only elements in $new are checked 542 * 543 * @param array $new - most recent data being saved 544 * @param array $old existing data - array is updated with changes, but not saved anywhere 545 * @param string $event - LAN define or string used as title in log 546 * 547 * @return bool true if changes found and logged, false otherwise. 548 */ 549 function logArrayDiffs($new, $old, $event, $logNow = true) 550 { 551 // $changes = array(); 552 553 $changes = array_diff_recursive($new,$old); 554 555 if (count($changes)) 556 { 557 if($logNow) 558 { 559 $this->add($event, print_r($changes,true), E_LOG_INFORMATIVE, ''); 560 } 561 else 562 { 563 $this->logMessage($changes, LOG_MESSAGE_NODISPLAY, E_MESSAGE_INFO); 564 } 565 566 return TRUE; 567 } 568 569 return FALSE; 570 } 571 572 573 /** 574 * Logs an entry with all the data from an array, one field per line. 575 * @deprecated 576 * @param string $event - LAN define or string used as title in log 577 * @param array $target - data to be logged 578 * @param string $extra - if non-empty, it goes on the first line. 579 * @param array $niceNames - Normally data is logged in the format keyname=>value, one per line. 580 * If the $niceName array exists and has a definition, the 'nice Name' is displayed instead of the key name 581 * 582 * @return null 583 */ 584 public function logArrayAll($event, $target, $extra = '', $niceNames = NULL) 585 { 586 587 if($extra == '' && $niceNames == null) 588 { 589 return $this->add($event, $target, E_LOG_INFORMATIVE, ''); // supports arrays 590 591 } 592 593 594 $logString = ''; 595 if ($extra) 596 { 597 $logString = $extra.'[!br!]'; 598 } 599 $spacer = ''; 600 $checkNice = ($niceNames != NULL) && is_array($niceNames); 601 foreach ($target as $k=>$v) 602 { 603 if ($checkNice && isset($niceNames[$k]['niceName'])) 604 { 605 $logString .= $spacer.$niceNames[$k]['niceName'].'=>'.$v; 606 } 607 else 608 { 609 $logString .= $spacer.$k.'=>'.$v; 610 } 611 $spacer = '[!br!]'; 612 } 613 $this->add($event, $logString, E_LOG_INFORMATIVE, ''); 614 615 return null; 616 } 617 618 /** 619 * The next two routines accept and buffers messages which are destined for both admin log and message handler 620 */ 621 622 /** 623 * Add a message to the queue 624 * 625 * @param string|array $text - the message text for logging/display 626 * @param int $type - the 'importance' of the message. E_MESSAGE_SUCCESS|E_MESSAGE_ERROR|E_MESSAGE_INFO|E_MESSAGE_DEBUG|E_MESSAGE_NODISPLAY 627 * (Values as used in message handler, apart from the last, which causes the message to not be passed to the message handler 628 * @param boolean|int $logLevel - TRUE to give same importance as for message display. FALSE to not log. 629 * one of the values specified for $mesLevel to determine the prefix attached to the log message 630 * @param boolean $session add session message 631 * 632 * @return e_admin_log 633 */ 634 public function logMessage($text, $type = '', $logLevel = TRUE, $session = FALSE) 635 { 636 637 if(is_array($text)) 638 { 639 $text = print_r($text,true); 640 } 641 elseif(empty($text)) 642 { 643 $bt = debug_backtrace(true); 644 e107::getMessage()->addDebug("Log Message was empty: ".print_a($bt[1],true)); 645 return $this; // changing to text will break chained methods. 646 } 647 648 if(!$type) $type = E_MESSAGE_INFO; 649 if($logLevel === TRUE) $logLevel = $type; 650 651 $logArray = array('message' => $text, 'dislevel' => $type, 'loglevel' => $logLevel, 'session' => $session, 'time'=>time()); 652 653 $this->_messages[] = $logArray; 654 $this->_allMessages[] = $logArray; 655 656 return $this; 657 } 658 659 660 661 /** 662 * @DEPRECATED 663 * BC Alias for addSuccess(); 664 */ 665 public function logSuccess($text, $message = true, $session = false) 666 { 667 return $this->addSuccess($text,$message,$session); 668 } 669 670 671 672 /** 673 * @DEPRECATED 674 * BC Alias for addError(); 675 */ 676 public function logError($text, $message = true, $session = false) 677 { 678 return $this->addError($text,$message,$session); 679 } 680 681 682 /** 683 * Add a success message to the log queue 684 * 685 * @param string|array $text 686 * @param boolean $message if true - register with eMessage handler 687 * @param boolean $session add session message 688 * @return e_admin_log 689 */ 690 public function addSuccess($text, $message = true, $session = false) 691 { 692 return $this->logMessage($text, ($message ? E_MESSAGE_SUCCESS : LOG_MESSAGE_NODISPLAY), E_MESSAGE_SUCCESS, $session); 693 } 694 695 696 /** 697 * Add an error message to the log queue 698 * 699 * @param string $text 700 * @param boolean $message if true (default) - register with eMessage handler, set to false to hide. 701 * @param boolean $session add session message 702 * @return e_admin_log 703 */ 704 public function addError($text, $message = true, $session = false) 705 { 706 return $this->logMessage($text, ($message ? E_MESSAGE_ERROR : LOG_MESSAGE_NODISPLAY), E_MESSAGE_ERROR, $session); 707 } 708 709 710 /** 711 * Add an Debug message to the log queue 712 * 713 * @param string $text 714 * @param boolean $message if true (default) - register with eMessage handler, set to false to hide . 715 * @param boolean $session add session message 716 * @return e_admin_log 717 */ 718 public function addDebug($text, $message = true, $session = false) 719 { 720 return $this->logMessage($text, ($message ? E_MESSAGE_DEBUG : LOG_MESSAGE_NODISPLAY), E_MESSAGE_DEBUG, $session); 721 } 722 723 724 /** 725 * Add an Warning message to the log queue 726 * 727 * @param string $text 728 * @param boolean $message if true (default) - register with eMessage handler, set to false to hide. 729 * @param boolean $session add session message 730 * @return e_admin_log 731 */ 732 public function addWarning($text, $message = true, $session = false) 733 { 734 return $this->logMessage($text, ($message ? E_MESSAGE_WARNING : LOG_MESSAGE_NODISPLAY), E_MESSAGE_WARNING, $session); 735 } 736 737 738 /** 739 * Add an array to the log queue 740 * @param $array 741 * @param $oldArray (optional) - when included, only the changes between the arrays is saved. 742 * @param $type (optional) default: LOG_MESSAGE_NODISPLAY. or E_MESSAGE_WARNING, E_MESSAGE_DEBUG, E_MESSAGE_SUCCESS 743 */ 744 public function addArray($array, $oldArray= null, $type = LOG_MESSAGE_NODISPLAY , $session = false) 745 { 746 if(is_array($oldArray)) 747 { 748 $text = array_diff_recursive($array,$oldArray); // Located in core_functions.php 749 if(count($text) < 1) 750 { 751 $text = "No differences found"; 752 } 753 754 } 755 else 756 { 757 $text = $array; 758 } 759 760 return $this->logMessage($text, $type, $type, $session); 761 } 762 763 /** 764 * Empty the messages - pass to both admin log and message handler 765 * 766 * @param string $logTitle - title for log entry 767 * @param int $logImportance - passed directly to admin log 768 * @param string $logEventCode - passed directly to admin log 769 * @param string $mstack [optional] message stack passed to message handler 770 * @return e_admin_log 771 */ 772 public function flushMessages($logTitle, $logImportance = E_LOG_INFORMATIVE, $logEventCode = '', $mstack = false, $target =LOG_TO_ADMIN) 773 { 774 $mes = e107::getMessage(); 775 776 $resultTypes = array(E_MESSAGE_SUCCESS => 'Success', E_MESSAGE_ERROR => 'Fail'); // Add LANS here. Could add other codes 777 $separator = ''; 778 $logString = ''; 779 foreach ($this->_messages as $m) 780 { 781 if ($m['loglevel'] !== FALSE) 782 { 783 $logString .= $separator; 784 if ($m['loglevel'] == LOG_MESSAGE_NODISPLAY) { $logString .= ' '; } // Indent supplementary messages 785 // Not sure about next line - might want to log the <br /> as text, rather than it forcing a newline 786 $logString .= strip_tags(str_replace(array('<br>', '<br/>', '<br />'), '[!br!]', $m['message'])); 787 if (isset($resultTypes[$m['loglevel']])) 788 { 789 $logString .= ' - '.$resultTypes[$m['loglevel']]; 790 } 791 $separator = '[!br!]'; 792 } 793 if ($m['dislevel'] != LOG_MESSAGE_NODISPLAY) 794 { 795 if($mstack) 796 { 797 $mes->addStack($m['message'], $mstack, $m['dislevel'], $m['session']); 798 // move to main stack OUTSIDE if needed 799 } 800 else $mes->add($m['message'], $m['dislevel'], $m['session']); 801 } 802 } 803 $this->add($logTitle, $logString, $logImportance, $logEventCode, $target); 804 $this->_messages = array(); // Clear the memory for reuse 805 806 return $this; 807 } 808 809 810 811 812 813 /** 814 * Clear all messages in 'memory'. 815 */ 816 public function clear() 817 { 818 $this->_messages = array(); 819 820 return $this; 821 } 822 823 824 /** 825 * Save Message stack to File. 826 */ 827 private function saveToFile($logTitle='', $append=false, $opts = array()) 828 { 829 if($this->logFile == null) 830 { 831 return null; 832 } 833 834 if(count($this->_allMessages)) 835 { 836 $head = " e107 CMS Log file : ".$logTitle." ".date('Y-m-d_H-i-s')."\n"; 837 $head .= "-------------------------------------------------------------------------------------------\n\n"; 838 } 839 else 840 { 841 return null; 842 } 843 844 $text = ''; 845 846 foreach($this->_allMessages as $m) 847 { 848 $text .= date('Y-m-d H:i:s', $m['time'])." \t".str_pad($m['loglevel'],10," ",STR_PAD_RIGHT)."\t".strip_tags($m['message'])."\n"; 849 } 850 851 $date = ($append == true) ? date('Y-m-d') : date('Y-m-d_H-i-s').'_'.crc32($text); 852 853 854 855 $dir = e_LOG; 856 857 if(empty($this->_current_plugin)) 858 { 859 $this->_current_plugin = deftrue('e_CURRENT_PLUGIN'); 860 } 861 862 if(!empty($this->_current_plugin)) // If it's a plugin, create a subfolder. 863 { 864 $dir = e_LOG.$this->_current_plugin."/"; 865 866 if(!is_dir($dir)) 867 { 868 mkdir($dir,0755); 869 } 870 } 871 872 $fileName = $dir.$date."_".$this->logFile.".log"; 873 874 if(!empty($opts['filename'])) 875 { 876 $fileName = $dir.basename($opts['filename']); 877 } 878 879 if($append == true) 880 { 881 $app = FILE_APPEND; 882 if(!file_exists($fileName)) 883 { 884 $text = $head . $text; 885 } 886 } 887 else 888 { 889 $app = null; 890 $text = $head . $text; 891 } 892 893 if(file_put_contents($fileName, $text, $app)) 894 { 895 $this->_allMessages = array(); 896 $this->_current_plugin = null; 897 return $this->logFile; 898 } 899 elseif(getperms('0') && E107_DEBUG_LEVEL > 0) 900 { 901 e107::getMessage()->addDebug("Couldn't Save to Log File: ".$fileName); 902 } 903 904 $this->_current_plugin = null; 905 906 return false; 907 } 908 909 910 911 912 /** 913 * Set and save accumulated log to a file. 914 * Use addDebug(), addError() or addSuccess() prior to executing. 915 * @param string name without the extension. (ie. date prefix and .log suffix will be added automatically) 916 * @param string Title for use inside the Log file 917 * @param boolean true = append to file, false = new file each save. 918 */ 919 public function toFile($name, $logTitle='',$append=false, $opts=array()) 920 { 921 922 $this->logFile = $name; 923 $file = $this->saveToFile($logTitle,$append,$opts); 924 925 $this->logFile = null; 926 return $file; 927 } 928 929 930} 931