137748cd8SNickeau<?php 237748cd8SNickeau/** 337748cd8SNickeau * Copyright (c) 2020. ComboStrap, Inc. and its affiliates. All Rights Reserved. 437748cd8SNickeau * 537748cd8SNickeau * This source code is licensed under the GPL license found in the 637748cd8SNickeau * COPYING file in the root directory of this source tree. 737748cd8SNickeau * 837748cd8SNickeau * @license GPL 3 (https://www.gnu.org/licenses/gpl-3.0.en.html) 937748cd8SNickeau * @author ComboStrap <support@combostrap.com> 1037748cd8SNickeau * 1137748cd8SNickeau */ 1237748cd8SNickeau 1337748cd8SNickeaunamespace ComboStrap; 1437748cd8SNickeau 1537748cd8SNickeaurequire_once(__DIR__ . '/PluginUtility.php'); 1637748cd8SNickeau 1737748cd8SNickeauclass LogUtility 1837748cd8SNickeau{ 1937748cd8SNickeau 2037748cd8SNickeau /** 2137748cd8SNickeau * Constant for the function {@link msg()} 2237748cd8SNickeau * -1 = error, 0 = info, 1 = success, 2 = notify 2337748cd8SNickeau * (Not even in order of importance) 2437748cd8SNickeau */ 2537748cd8SNickeau const LVL_MSG_ERROR = 4; //-1; 2637748cd8SNickeau const LVL_MSG_WARNING = 3; //2; 2737748cd8SNickeau const LVL_MSG_SUCCESS = 2; //1; 2837748cd8SNickeau const LVL_MSG_INFO = 1; //0; 2937748cd8SNickeau const LVL_MSG_DEBUG = 0; //3; 3037748cd8SNickeau 3137748cd8SNickeau 3237748cd8SNickeau /** 3337748cd8SNickeau * Id level to name 3437748cd8SNickeau */ 3537748cd8SNickeau const LVL_NAME = array( 3637748cd8SNickeau 0 => "debug", 3737748cd8SNickeau 1 => "info", 3837748cd8SNickeau 3 => "warning", 3937748cd8SNickeau 2 => "success", 4037748cd8SNickeau 4 => "error" 4137748cd8SNickeau ); 4237748cd8SNickeau 4337748cd8SNickeau /** 4437748cd8SNickeau * Id level to name 4537748cd8SNickeau * {@link msg()} constant 4637748cd8SNickeau */ 4737748cd8SNickeau const LVL_TO_MSG_LEVEL = array( 4837748cd8SNickeau 0 => 3, 4937748cd8SNickeau 1 => 0, 5037748cd8SNickeau 2 => 1, 5137748cd8SNickeau 3 => 2, 5237748cd8SNickeau 4 => -1 5337748cd8SNickeau ); 5437748cd8SNickeau 5537748cd8SNickeau 5637748cd8SNickeau const LOGLEVEL_URI_QUERY_PROPERTY = "loglevel"; 5737748cd8SNickeau 5837748cd8SNickeau /** 5937748cd8SNickeau * Send a message to a manager and log it 6037748cd8SNickeau * Fail if in test 6137748cd8SNickeau * @param string $message 6237748cd8SNickeau * @param int $level - the level see LVL constant 6337748cd8SNickeau * @param string $canonical - the canonical 6437748cd8SNickeau */ 65c3437056SNickeau public static function msg(string $message, int $level = self::LVL_MSG_ERROR, string $canonical = "support") 6637748cd8SNickeau { 6737748cd8SNickeau 68*d61dea15Sgerardnico try { 69*d61dea15Sgerardnico self::messageNotEmpty($message); 70*d61dea15Sgerardnico } catch (ExceptionCombo $e) { 71*d61dea15Sgerardnico self::log2file($e->getMessage(), LogUtility::LVL_MSG_ERROR, $canonical); 72e7bbc4b8Sgerardnico } 73e7bbc4b8Sgerardnico 7437748cd8SNickeau /** 7537748cd8SNickeau * Log to frontend 7637748cd8SNickeau */ 77c3437056SNickeau self::log2FrontEnd($message, $level, $canonical); 7837748cd8SNickeau 7937748cd8SNickeau /** 8037748cd8SNickeau * Log level passed for a page (only for file used) 8137748cd8SNickeau * to not allow an attacker to see all errors in frontend 8237748cd8SNickeau */ 8337748cd8SNickeau global $INPUT; 8437748cd8SNickeau $loglevelProp = $INPUT->str(self::LOGLEVEL_URI_QUERY_PROPERTY, null); 8537748cd8SNickeau if (!empty($loglevelProp)) { 8637748cd8SNickeau $level = $loglevelProp; 8737748cd8SNickeau } 882f4da794Sgerardnico /** 892f4da794Sgerardnico * TODO: Make it a configuration ? 902f4da794Sgerardnico */ 912f4da794Sgerardnico if ($level >= self::LVL_MSG_WARNING) { 9237748cd8SNickeau self::log2file($message, $level, $canonical); 932f4da794Sgerardnico } 9437748cd8SNickeau 9537748cd8SNickeau /** 9637748cd8SNickeau * If test, we throw an error 9737748cd8SNickeau */ 98c3437056SNickeau self::throwErrorIfTest($level, $message); 9937748cd8SNickeau } 10037748cd8SNickeau 10137748cd8SNickeau /** 10237748cd8SNickeau * Print log to a file 10337748cd8SNickeau * 10437748cd8SNickeau * Adapted from {@link dbglog} 10537748cd8SNickeau * Note: {@link dbg()} dbg print to the web page 10637748cd8SNickeau * 10737748cd8SNickeau * @param string $msg 10837748cd8SNickeau * @param int $logLevel 10937748cd8SNickeau * @param null $canonical 11037748cd8SNickeau */ 111*d61dea15Sgerardnico static function log2file(string $msg, int $logLevel = self::LVL_MSG_INFO, $canonical = null) 11237748cd8SNickeau { 11337748cd8SNickeau 114*d61dea15Sgerardnico try { 115*d61dea15Sgerardnico self::messageNotEmpty($msg); 116*d61dea15Sgerardnico } catch (ExceptionCombo $e) { 117*d61dea15Sgerardnico $msg = $e->getMessage(); 118*d61dea15Sgerardnico $logLevel = self::LVL_MSG_ERROR; 119*d61dea15Sgerardnico } 120*d61dea15Sgerardnico 121c3437056SNickeau if (PluginUtility::isTest() || $logLevel >= self::LVL_MSG_WARNING) { 12237748cd8SNickeau 12337748cd8SNickeau $prefix = PluginUtility::$PLUGIN_NAME; 12437748cd8SNickeau if (!empty($canonical)) { 12537748cd8SNickeau $prefix .= ' - ' . $canonical; 12637748cd8SNickeau } 12737748cd8SNickeau $msg = $prefix . ' - ' . $msg; 12837748cd8SNickeau 12937748cd8SNickeau global $INPUT; 13037748cd8SNickeau global $conf; 13137748cd8SNickeau 132c3437056SNickeau /** 133c3437056SNickeau * Adding page - context information 134c3437056SNickeau * We are not using {@link Page::createPageFromRequestedPage()} 135c3437056SNickeau * because it throws an error message when the environment 136c3437056SNickeau * is not good, creating a recursive call. 137c3437056SNickeau */ 138c3437056SNickeau $id = PluginUtility::getMainPageDokuwikiId(); 13937748cd8SNickeau 14037748cd8SNickeau $file = $conf['cachedir'] . '/debug.log'; 14137748cd8SNickeau $fh = fopen($file, 'a'); 14237748cd8SNickeau if ($fh) { 14337748cd8SNickeau $sep = " - "; 14437748cd8SNickeau fwrite($fh, date('c') . $sep . self::LVL_NAME[$logLevel] . $sep . $msg . $sep . $INPUT->server->str('REMOTE_ADDR') . $sep . $id . "\n"); 14537748cd8SNickeau fclose($fh); 14637748cd8SNickeau } 147c3437056SNickeau 148c3437056SNickeau 149c3437056SNickeau self::throwErrorIfTest($logLevel, $msg); 150c3437056SNickeau 151c3437056SNickeau 15237748cd8SNickeau } 15337748cd8SNickeau 15437748cd8SNickeau } 15537748cd8SNickeau 15637748cd8SNickeau /** 15737748cd8SNickeau * @param $message 15837748cd8SNickeau * @param $level 159*d61dea15Sgerardnico * @param string $canonical 16037748cd8SNickeau * @param bool $withIconURL 16137748cd8SNickeau */ 16237748cd8SNickeau public static function log2FrontEnd($message, $level, $canonical = "support", $withIconURL = true) 16337748cd8SNickeau { 164*d61dea15Sgerardnico 165*d61dea15Sgerardnico try { 166*d61dea15Sgerardnico self::messageNotEmpty($message); 167*d61dea15Sgerardnico } catch (ExceptionCombo $e) { 168*d61dea15Sgerardnico $message = $e->getMessage(); 169*d61dea15Sgerardnico $level = self::LVL_MSG_ERROR; 170*d61dea15Sgerardnico } 171*d61dea15Sgerardnico 17237748cd8SNickeau /** 17337748cd8SNickeau * If we are not in the console 17437748cd8SNickeau * and not in test 17537748cd8SNickeau * we test that the message comes in the front end 17637748cd8SNickeau * (example {@link \plugin_combo_frontmatter_test} 17737748cd8SNickeau */ 178c3437056SNickeau $isTerminal = Console::isConsoleRun(); 179c3437056SNickeau if ($isTerminal) { 18037748cd8SNickeau if (!defined('DOKU_UNITTEST')) { 181c3437056SNickeau /** 182c3437056SNickeau * such as {@link cli_plugin_combo} 183c3437056SNickeau */ 184c3437056SNickeau $userAgent = "cli"; 185c3437056SNickeau } else { 186c3437056SNickeau $userAgent = "phpunit"; 18737748cd8SNickeau } 188c3437056SNickeau } else { 189c3437056SNickeau $userAgent = "browser"; 19037748cd8SNickeau } 191c3437056SNickeau 192c3437056SNickeau switch ($userAgent) { 193c3437056SNickeau case "cli": 194c3437056SNickeau echo "$message\n"; 195c3437056SNickeau break; 196c3437056SNickeau case "phpunit": 197c3437056SNickeau case "browser": 198c3437056SNickeau default: 199c3437056SNickeau $htmlMsg = PluginUtility::getDocumentationHyperLink("", PluginUtility::$PLUGIN_NAME, $withIconURL); 20037748cd8SNickeau if ($canonical != null) { 201c3437056SNickeau $htmlMsg = PluginUtility::getDocumentationHyperLink($canonical, ucfirst(str_replace(":", " ", $canonical))); 20237748cd8SNickeau } 20337748cd8SNickeau 20437748cd8SNickeau /** 20537748cd8SNickeau * Adding page - context information 20637748cd8SNickeau * We are not creating the page 207c3437056SNickeau * direction from {@link Page::createPageFromRequestedPage()} 20837748cd8SNickeau * because it throws an error message when the environment 20937748cd8SNickeau * is not good, creating a recursive call. 21037748cd8SNickeau */ 211c3437056SNickeau $id = PluginUtility::getMainPageDokuwikiId(); 21237748cd8SNickeau if ($id != null) { 213c3437056SNickeau 214c3437056SNickeau /** 215c3437056SNickeau * We don't use any Page object to not 216c3437056SNickeau * create a cycle while building it 217c3437056SNickeau */ 218c3437056SNickeau $url = wl($id, [], true); 219c3437056SNickeau $htmlMsg .= " - <a href=\"$url\">$id</a>"; 220c3437056SNickeau 22137748cd8SNickeau } 22237748cd8SNickeau 22337748cd8SNickeau /** 22437748cd8SNickeau * 22537748cd8SNickeau */ 22637748cd8SNickeau $htmlMsg .= " - " . $message; 22737748cd8SNickeau if ($level > self::LVL_MSG_DEBUG) { 22837748cd8SNickeau $dokuWikiLevel = self::LVL_TO_MSG_LEVEL[$level]; 22937748cd8SNickeau msg($htmlMsg, $dokuWikiLevel, '', '', MSG_USERS_ONLY); 23037748cd8SNickeau } 23137748cd8SNickeau } 23237748cd8SNickeau } 23337748cd8SNickeau 23437748cd8SNickeau /** 23537748cd8SNickeau * Log a message to the browser console 23637748cd8SNickeau * @param $message 23737748cd8SNickeau */ 23837748cd8SNickeau public static function log2BrowserConsole($message) 23937748cd8SNickeau { 24037748cd8SNickeau // TODO 24137748cd8SNickeau } 242c3437056SNickeau 243c3437056SNickeau private static function throwErrorIfTest($level, $message) 244c3437056SNickeau { 245c3437056SNickeau if (PluginUtility::isTest() 246c3437056SNickeau && ($level >= self::LVL_MSG_WARNING) 247c3437056SNickeau ) { 248c3437056SNickeau throw new LogException($message); 249c3437056SNickeau } 250c3437056SNickeau } 251*d61dea15Sgerardnico 252*d61dea15Sgerardnico /** 253*d61dea15Sgerardnico * @param string $message 254*d61dea15Sgerardnico * @throws ExceptionCombo 255*d61dea15Sgerardnico */ 256*d61dea15Sgerardnico private static function messageNotEmpty(string $message) 257*d61dea15Sgerardnico { 258*d61dea15Sgerardnico $message = trim($message); 259*d61dea15Sgerardnico if ($message === "" || $message === null) { 260*d61dea15Sgerardnico $newMessage = "The passed message to the log was empty or null. BackTrace: \n"; 261*d61dea15Sgerardnico ob_start(); 262*d61dea15Sgerardnico debug_print_backtrace(); 263*d61dea15Sgerardnico $trace = ob_get_contents(); 264*d61dea15Sgerardnico ob_end_clean(); 265*d61dea15Sgerardnico $newMessage .= $trace; 266*d61dea15Sgerardnico throw new ExceptionCombo($newMessage); 267*d61dea15Sgerardnico } 268*d61dea15Sgerardnico } 26937748cd8SNickeau} 270