<?php /** * File: triggers * Scans the installation for Trigger calls and filters. */ header("Content-Type: text/html; charset=UTF-8"); define('DEBUG', true); define('CHYRP_VERSION', "2024.03"); define('CHYRP_CODENAME', "Oak"); define('CHYRP_IDENTITY', "Chyrp/".CHYRP_VERSION." (".CHYRP_CODENAME.")"); define('MAIN', false); define('ADMIN', false); define('AJAX', false); define('UPGRADING', false); define('INSTALLING', false); define('COOKIE_LIFETIME', 2592000); define('PASSWORD_RESET_TOKEN_LIFETIME', 3600); define('MAX_TIME_LIMIT', 600); define('MAX_MEMORY_LIMIT', "100M"); define('SQL_DATETIME_ZERO', "1000-01-01 00:00:00"); define('SQL_DATETIME_ZERO_VARIANTS', array( "0000-00-00 00:00:00", "0001-01-01 00:00:00", "1000-01-01 00:00:00" ) ); define('BOT_UA', false); define('DIR', DIRECTORY_SEPARATOR); define('MAIN_DIR', dirname(__FILE__)); define('INCLUDES_DIR', MAIN_DIR.DIR."includes"); define('CACHES_DIR', INCLUDES_DIR.DIR."caches"); define('MODULES_DIR', MAIN_DIR.DIR."modules"); define('FEATHERS_DIR', MAIN_DIR.DIR."feathers"); define('THEMES_DIR', MAIN_DIR.DIR."themes"); define('UPDATE_XML', null); define('UPDATE_INTERVAL', null); define('UPDATE_PAGE', null); define('SESSION_DENY_BOT', true); define('SLUG_STRICT', true); define('GET_REMOTE_UNSAFE', false); define('USE_GETTEXT_SHIM', stripos(PHP_OS, "Win") === 0); define('USE_OB', true); define('HTTP_ACCEPT_ZSTD', false); define('HTTP_ACCEPT_DEFLATE', false); define('HTTP_ACCEPT_GZIP', false); define('CAN_USE_ZSTD', false); define('CAN_USE_ZLIB', false); define('USE_COMPRESSION', false); define('PREVIEWING', false); define('THEME_DIR', null); define('THEME_URL', null); ob_start(); define('OB_BASE_LEVEL', ob_get_level()); # File: error # Functions for handling and reporting errors. require_once INCLUDES_DIR.DIR."error.php"; # File: helpers # Various functions used throughout the codebase. require_once INCLUDES_DIR.DIR."helpers.php"; # Array: $exclude # Paths to be excluded from directory recursion. $exclude = array( MAIN_DIR.DIR."tools", MAIN_DIR.DIR."uploads", MAIN_DIR.DIR."includes".DIR."caches", MAIN_DIR.DIR."includes".DIR."lib".DIR."Twig", MAIN_DIR.DIR."includes".DIR."lib".DIR."IXR", MAIN_DIR.DIR."includes".DIR."lib".DIR."cebe" ); # Array: $trigger # Contains the calls and filters. $trigger = array( "call" => array(), "filter" => array() ); # String: $str_reg # Regular expression representing a string. $str_reg = '(\"[^\"]+\"|\'[^\']+\')'; # String: $arr_reg # Regular expression representing an array construct. $arr_reg = 'array\(([^\)]+)\)'; /** * Function: scan_dir * Scans a directory in search of files or subdirectories. */ function scan_dir($pathname) { global $exclude; $dir = new DirectoryIterator($pathname); foreach ($dir as $item) { if (!$item->isDot()) { $item_path = $item->getPathname(); $extension = $item->getExtension(); switch ($item->getType()) { case "file": scan_file($item_path, $extension); break; case "dir": if (!in_array($item_path, $exclude)) scan_dir($item_path); break; } } } } /** * Function: scan_file * Scans a file in search of triggers. */ function scan_file($pathname, $extension) { if ($extension != "php" and $extension != "twig") return; $file = fopen($pathname, "r"); $line = 1; if ($file === false) return; while (!feof($file)) { $text = fgets($file); switch ($extension) { case "php": scan_call($pathname, $line, $text); scan_call_array($pathname, $line, $text); scan_filter($pathname, $line, $text); scan_filter_array($pathname, $line, $text); break; case "twig": scan_twig($pathname, $line, $text); break; } $line++; } fclose($file); } /** * Function: make_place * Makes a string detailing the place a trigger was found. */ function make_place($pathname, $line) { return str_replace( array(MAIN_DIR.DIR, DIR), array("", "/"), $pathname )." on line ".$line; } /** * Function: make_arguments * Makes an array from a string of arguments. */ function make_arguments($text) { $array = explode(",", $text); foreach ($array as &$arg) { $arg = trim($arg, ", "); } return array_diff($array, array("")); } /** * Function: scan_call * Scans text for trigger calls. */ function scan_call($pathname, $line, $text) { global $trigger; global $str_reg; if ( preg_match_all( "/(\\\$trigger|Trigger::current\(\))->call\($str_reg(,\s*(.+))?\)/", $text, $matches, PREG_SET_ORDER ) ) { foreach ($matches as $match) { $call = trim($match[2], "'\""); if (isset($trigger["call"][$call])) $trigger["call"][$call]["places"][] = make_place( $pathname, $line ); else $trigger["call"][$call] = array( "places" => array(make_place($pathname, $line)), "arguments" => make_arguments(fallback($match[4], "")) ); } } } /** * Function: scan_call_array * Scans text for trigger call arrays. */ function scan_call_array($pathname, $line, $text) { global $trigger; global $arr_reg; if ( preg_match_all( "/(\\\$trigger|Trigger::current\(\))->call\($arr_reg(,\s*(.+))?\)/", $text, $matches, PREG_SET_ORDER ) ) { foreach ($matches as $match) { $calls = explode(",", $match[2]); foreach ($calls as $call) { $call = trim($call, "'\" "); if (empty($call) or preg_match('/[^A-Za-z0-9_]/', $call)) continue; if (isset($trigger["call"][$call])) $trigger["call"][$call]["places"][] = make_place( $pathname, $line ); else $trigger["call"][$call] = array( "places" => array(make_place($pathname, $line)), "arguments" => make_arguments(fallback($match[4], "")) ); } } } } /** * Function: scan_filter * Scans text for trigger filters. */ function scan_filter($pathname, $line, $text) { global $trigger; global $str_reg; if ( preg_match_all( "/(\\\$trigger|Trigger::current\(\))->filter\(([^,]+),\s*$str_reg(,\s*(.+))?\)/", $text, $matches, PREG_SET_ORDER ) ) { foreach ($matches as $match) { $filter = trim($match[3], "'\""); if (isset($trigger["filter"][$filter])) $trigger["filter"][$filter]["places"][] = make_place( $pathname, $line ); else $trigger["filter"][$filter] = array( "places" => array(make_place($pathname, $line)), "target" => trim($match[2], ", "), "arguments" => make_arguments(fallback($match[5], "")) ); } } } /** * Function: scan_filter_array * Scans text for trigger filter arrays. */ function scan_filter_array($pathname, $line, $text) { global $trigger; global $arr_reg; if ( preg_match_all( "/(\\\$trigger|Trigger::current\(\))->filter\(([^,]+),\s*$arr_reg(,\s*(.+))?\)/", $text, $matches, PREG_SET_ORDER ) ) { foreach ($matches as $match) { $filters = explode(",", $match[3]); foreach ($filters as $filter) { $filter = trim($filter, "'\" "); if (empty($filter) or preg_match('/[^A-Za-z0-9_]/', $filter)) continue; if (isset($trigger["filter"][$filter])) $trigger["filter"][$filter]["places"][] = make_place( $pathname, $line ); else $trigger["filter"][$filter] = array( "places" => array(make_place($pathname, $line)), "target" => trim($match[2], ", "), "arguments" => make_arguments(fallback($match[5], "")) ); } } } } /** * Function: scan_twig * Scans text for trigger calls in Twig statements. */ function scan_twig($pathname, $line, $text) { global $trigger; global $str_reg; if ( preg_match_all( "/\{\{\s*trigger\.call\($str_reg(,\s*(.+))?\)\s*\}\}/", $text, $matches, PREG_SET_ORDER ) ) { foreach ($matches as $match) { $call = trim($match[1], "'\""); if (isset($trigger["call"][$call])) $trigger["call"][$call]["places"][] = make_place( $pathname, $line ); else $trigger["call"][$call] = array( "places" => array(make_place($pathname, $line)), "arguments" => make_arguments(fallback($match[3], "")) ); } } } /** * Function: create_file * Generates the triggers list and writes it to disk. */ function create_file() { global $trigger; $contents = "==============================================\n". " Trigger Calls\n". "==============================================\n"; foreach ($trigger["call"] as $call => $attributes) { $contents.= "\n\n"; $contents.= $call."\n"; $contents.= str_repeat("-", strlen($call))."\n"; $contents.= "Called from:\n"; foreach ($attributes["places"] as $place) $contents.= "\t".$place."\n"; if (!empty($attributes["arguments"])) { $contents.= "\nArguments:\n"; foreach ($attributes["arguments"] as $argument) $contents.= "\t".$argument."\n"; } } $contents.= "\n\n\n\n"; $contents.= "==============================================\n". " Trigger Filters\n". "==============================================\n"; foreach ($trigger["filter"] as $filter => $attributes) { $contents.= "\n\n"; $contents.= $filter."\n"; $contents.= str_repeat("-", strlen($filter))."\n"; $contents.= "Called from:\n"; foreach ($attributes["places"] as $place) $contents.= "\t".$place."\n"; $contents.= "\nTarget:\n"; $contents.= "\t".$attributes["target"]."\n"; if (!empty($attributes["arguments"])) { $contents.= "\nArguments:\n"; foreach ($attributes["arguments"] as $argument) $contents.= "\t".$argument."\n"; } } @file_put_contents( MAIN_DIR.DIR."tools".DIR."triggers_list.txt", $contents ); echo fix($contents); } #--------------------------------------------- # Output Starts #--------------------------------------------- ?> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=640"> <title><?php echo "Triggers"; ?></title> <style type="text/css"> @font-face { font-family: 'Open Sans webfont'; src: url('../fonts/OpenSans-Regular.woff') format('woff'); font-weight: normal; font-style: normal; } @font-face { font-family: 'Open Sans webfont'; src: url('../fonts/OpenSans-SemiBold.woff') format('woff'); font-weight: 600; font-style: normal; } @font-face { font-family: 'Open Sans webfont'; src: url('../fonts/OpenSans-Bold.woff') format('woff'); font-weight: bold; font-style: normal; } @font-face { font-family: 'Open Sans webfont'; src: url('../fonts/OpenSans-Italic.woff') format('woff'); font-weight: normal; font-style: italic; } @font-face { font-family: 'Open Sans webfont'; src: url('../fonts/OpenSans-SemiBoldItalic.woff') format('woff'); font-weight: 600; font-style: italic; } @font-face { font-family: 'Open Sans webfont'; src: url('../fonts/OpenSans-BoldItalic.woff') format('woff'); font-weight: bold; font-style: italic; } @font-face { font-family: 'Cousine webfont'; src: url('../fonts/Cousine-Regular.woff') format('woff'); font-weight: normal; font-style: normal; } @font-face { font-family: 'Cousine webfont'; src: url('../fonts/Cousine-Bold.woff') format('woff'); font-weight: bold; font-style: normal; } @font-face { font-family: 'Cousine webfont'; src: url('../fonts/Cousine-Italic.woff') format('woff'); font-weight: normal; font-style: italic; } @font-face { font-family: 'Cousine webfont'; src: url('../fonts/Cousine-BoldItalic.woff') format('woff'); font-weight: bold; font-style: italic; } *::selection { color: #ffffff; background-color: #ff7f00; } html, body, div, dl, dt, dd, ul, ol, li, p, h1, h2, h3, h4, h5, h6, img, pre, code, form, fieldset, input, select, textarea, table, tbody, tr, th, td, legend, caption, blockquote, aside, figure, figcaption { margin: 0em; padding: 0em; border: 0em; } html { font-size: 16px; } body { font-size: 1rem; font-family: "Open Sans webfont", sans-serif; line-height: 1.5; color: #1f1f23; tab-size: 4; background: #efefef; margin: 2rem; } h1 { font-size: 2em; text-align: center; font-weight: bold; margin: 1rem 0rem; } h2 { font-size: 1.5em; text-align: center; font-weight: bold; margin: 1rem 0rem; } h3 { font-size: 1em; font-weight: 600; margin: 1rem 0rem; border-bottom: 1px solid #cfcfcf; } p { margin-bottom: 1rem; } strong { font: inherit; font-weight: bold; color: #c11600; } em, dfn, cite, var { font: inherit; font-style: italic; } ul, ol { margin-bottom: 1rem; margin-inline-start: 2rem; list-style-position: outside; } pre { font-family: "Cousine webfont", monospace; font-size: 0.85em; background-color: #efefef; margin: 1rem 0rem; padding: 1rem; overflow-x: auto; white-space: pre; } code { font-family: "Cousine webfont", monospace; font-size: 0.85em; background-color: #efefef; padding: 0px 2px; border: 1px solid #cfcfcf; vertical-align: bottom; white-space: break-spaces; } pre > code { font-size: 0.85rem; display: block; border: none; padding: 0px; white-space: inherit; } a:link, a:visited { color: #1f1f23; text-decoration: underline; text-underline-offset: 0.125em; } a:focus { outline: #ff7f00 dashed 2px; outline-offset: 1px; } a:hover, a:focus, a:active { color: #1e57ba; text-decoration: underline; text-underline-offset: 0.125em; } a.big, button { box-sizing: border-box; display: block; clear: both; font: inherit; font-size: 1.25em; text-align: center; color: #1f1f23; text-decoration: none; margin: 1rem 0rem; padding: 0.5rem 1rem; background-color: #f2fbff; border: 2px solid #b8cdd9; border-radius: 0.25em; cursor: pointer; } button { width: 100%; } a.big:hover, button:hover, a.big:focus, button:focus, a.big:active, button:active { border-color: #1e57ba; outline: none; } aside { margin-bottom: 1rem; padding: 0.5rem 1rem; border: 1px solid #e5d7a1; border-radius: 0.25em; background-color: #fffecd; } .window { width: 30rem; background: #ffffff; padding: 2rem; margin: 0rem auto 0rem auto; border-radius: 2rem; } .window > *:first-child { margin-top: 0rem; } .window > *:last-child { margin-bottom: 0rem; } </style> </head> <body> <div class="window"> <pre role="status" class="pane"><?php #--------------------------------------------- # Processing Starts #--------------------------------------------- scan_dir(MAIN_DIR); create_file(); #--------------------------------------------- # Processing Ends #--------------------------------------------- ?></pre> </div> </body> </html>