346 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			346 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php declare(strict_types=1);
 | 
						|
/**
 | 
						|
 * Generic parent class for all events.
 | 
						|
 *
 | 
						|
 * An event is anything that can be passed around via send_event($blah)
 | 
						|
 */
 | 
						|
abstract class Event
 | 
						|
{
 | 
						|
    public $stop_processing = false;
 | 
						|
 | 
						|
    public function __construct()
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    public function __toString()
 | 
						|
    {
 | 
						|
        return var_export($this, true);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * A wake-up call for extensions. Upon recieving an InitExtEvent an extension
 | 
						|
 * should check that it's database tables are there and install them if not,
 | 
						|
 * and set any defaults with Config::set_default_int() and such.
 | 
						|
 *
 | 
						|
 * This event is sent before $user is set to anything
 | 
						|
 */
 | 
						|
class InitExtEvent extends Event
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * A signal that a page has been requested.
 | 
						|
 *
 | 
						|
 * User requests /view/42 -> an event is generated with $args = array("view",
 | 
						|
 * "42"); when an event handler asks $event->page_matches("view"), it returns
 | 
						|
 * true and ignores the matched part, such that $event->count_args() = 1 and
 | 
						|
 * $event->get_arg(0) = "42"
 | 
						|
 */
 | 
						|
class PageRequestEvent extends Event
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * @var array
 | 
						|
     */
 | 
						|
    public $args;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var int
 | 
						|
     */
 | 
						|
    public $arg_count;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var int
 | 
						|
     */
 | 
						|
    public $part_count;
 | 
						|
 | 
						|
    public function __construct(string $path)
 | 
						|
    {
 | 
						|
        parent::__construct();
 | 
						|
        global $config;
 | 
						|
 | 
						|
        // trim starting slashes
 | 
						|
        $path = ltrim($path, "/");
 | 
						|
 | 
						|
        // if path is not specified, use the default front page
 | 
						|
        if (empty($path)) {   /* empty is faster than strlen */
 | 
						|
            $path = $config->get_string(SetupConfig::FRONT_PAGE);
 | 
						|
        }
 | 
						|
 | 
						|
        // break the path into parts
 | 
						|
        $args = explode('/', $path);
 | 
						|
 | 
						|
        // voodoo so that an arg can contain a slash; is
 | 
						|
        // this still needed?
 | 
						|
        if (strpos($path, "^") !== false) {
 | 
						|
            $unescaped = [];
 | 
						|
            foreach ($args as $part) {
 | 
						|
                $unescaped[] = _decaret($part);
 | 
						|
            }
 | 
						|
            $args = $unescaped;
 | 
						|
        }
 | 
						|
 | 
						|
        $this->args = $args;
 | 
						|
        $this->arg_count = count($args);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Test if the requested path matches a given pattern.
 | 
						|
     *
 | 
						|
     * If it matches, store the remaining path elements in $args
 | 
						|
     */
 | 
						|
    public function page_matches(string $name): bool
 | 
						|
    {
 | 
						|
        $parts = explode("/", $name);
 | 
						|
        $this->part_count = count($parts);
 | 
						|
 | 
						|
        if ($this->part_count > $this->arg_count) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        for ($i=0; $i<$this->part_count; $i++) {
 | 
						|
            if ($parts[$i] != $this->args[$i]) {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the n th argument of the page request (if it exists.)
 | 
						|
     */
 | 
						|
    public function get_arg(int $n): string
 | 
						|
    {
 | 
						|
        $offset = $this->part_count + $n;
 | 
						|
        if ($offset >= 0 && $offset < $this->arg_count) {
 | 
						|
            return $this->args[$offset];
 | 
						|
        } else {
 | 
						|
            throw new SCoreException("Requested an invalid argument #$n");
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public function try_page_num(int $n): int
 | 
						|
    {
 | 
						|
        if ($this->count_args() > $n) {
 | 
						|
            $i = $this->get_arg($n);
 | 
						|
            if (is_numeric($i) && int_escape($i) > 0) {
 | 
						|
                return int_escape($i);
 | 
						|
            } else {
 | 
						|
                return 1;
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            return 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the number of arguments the page request has.
 | 
						|
     */
 | 
						|
    public function count_args(): int
 | 
						|
    {
 | 
						|
        return $this->arg_count - $this->part_count;
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
     * Many things use these functions
 | 
						|
     */
 | 
						|
 | 
						|
    public function get_search_terms(): array
 | 
						|
    {
 | 
						|
        $search_terms = [];
 | 
						|
        if ($this->count_args() === 2) {
 | 
						|
            $search_terms = Tag::explode($this->get_arg(0));
 | 
						|
        }
 | 
						|
        return $search_terms;
 | 
						|
    }
 | 
						|
 | 
						|
    public function get_page_number(): int
 | 
						|
    {
 | 
						|
        $page_number = 1;
 | 
						|
        if ($this->count_args() === 1) {
 | 
						|
            $page_number = int_escape($this->get_arg(0));
 | 
						|
        } elseif ($this->count_args() === 2) {
 | 
						|
            $page_number = int_escape($this->get_arg(1));
 | 
						|
        }
 | 
						|
        if ($page_number === 0) {
 | 
						|
            $page_number = 1;
 | 
						|
        } // invalid -> 0
 | 
						|
        return $page_number;
 | 
						|
    }
 | 
						|
 | 
						|
    public function get_page_size(): int
 | 
						|
    {
 | 
						|
        global $config;
 | 
						|
        return $config->get_int(IndexConfig::IMAGES);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * Sent when index.php is called from the command line
 | 
						|
 */
 | 
						|
class CommandEvent extends Event
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    public $cmd = "help";
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var array
 | 
						|
     */
 | 
						|
    public $args = [];
 | 
						|
 | 
						|
    /**
 | 
						|
     * #param string[] $args
 | 
						|
     */
 | 
						|
    public function __construct(array $args)
 | 
						|
    {
 | 
						|
        parent::__construct();
 | 
						|
        global $user;
 | 
						|
 | 
						|
        $opts = [];
 | 
						|
        $log_level = SCORE_LOG_WARNING;
 | 
						|
        $arg_count = count($args);
 | 
						|
 | 
						|
        for ($i=1; $i<$arg_count; $i++) {
 | 
						|
            switch ($args[$i]) {
 | 
						|
                case '-u':
 | 
						|
                    $user = User::by_name($args[++$i]);
 | 
						|
                    if (is_null($user)) {
 | 
						|
                        die("Unknown user");
 | 
						|
                    } else {
 | 
						|
                        send_event(new UserLoginEvent($user));
 | 
						|
                    }
 | 
						|
                    break;
 | 
						|
                case '-q':
 | 
						|
                    $log_level += 10;
 | 
						|
                    break;
 | 
						|
                case '-v':
 | 
						|
                    $log_level -= 10;
 | 
						|
                    break;
 | 
						|
                default:
 | 
						|
                    $opts[] = $args[$i];
 | 
						|
                    break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        define("CLI_LOG_LEVEL", $log_level);
 | 
						|
 | 
						|
        if (count($opts) > 0) {
 | 
						|
            $this->cmd = $opts[0];
 | 
						|
            $this->args = array_slice($opts, 1);
 | 
						|
        } else {
 | 
						|
            print "\n";
 | 
						|
            print "Usage: php {$args[0]} [flags] [command]\n";
 | 
						|
            print "\n";
 | 
						|
            print "Flags:\n";
 | 
						|
            print "\t-u [username]\n";
 | 
						|
            print "\t\tLog in as the specified user\n";
 | 
						|
            print "\t-q / -v\n";
 | 
						|
            print "\t\tBe quieter / more verbose\n";
 | 
						|
            print "\t\tScale is debug - info - warning - error - critical\n";
 | 
						|
            print "\t\tDefault is to show warnings and above\n";
 | 
						|
            print "\n";
 | 
						|
            print "Currently known commands:\n";
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * A signal that some text needs formatting, the event carries
 | 
						|
 * both the text and the result
 | 
						|
 */
 | 
						|
class TextFormattingEvent extends Event
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * For reference
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    public $original;
 | 
						|
 | 
						|
    /**
 | 
						|
     * with formatting applied
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    public $formatted;
 | 
						|
 | 
						|
    /**
 | 
						|
     * with formatting removed
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    public $stripped;
 | 
						|
 | 
						|
    public function __construct(string $text)
 | 
						|
    {
 | 
						|
        parent::__construct();
 | 
						|
        $h_text = html_escape(trim($text));
 | 
						|
        $this->original  = $h_text;
 | 
						|
        $this->formatted = $h_text;
 | 
						|
        $this->stripped  = $h_text;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * A signal that something needs logging
 | 
						|
 */
 | 
						|
class LogEvent extends Event
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * a category, normally the extension name
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    public $section;
 | 
						|
 | 
						|
    /**
 | 
						|
     * See python...
 | 
						|
     *
 | 
						|
     * @var int
 | 
						|
     */
 | 
						|
    public $priority = 0;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Free text to be logged
 | 
						|
     *
 | 
						|
     * @var string
 | 
						|
     */
 | 
						|
    public $message;
 | 
						|
 | 
						|
    /**
 | 
						|
     * The time that the event was created
 | 
						|
     *
 | 
						|
     * @var int
 | 
						|
     */
 | 
						|
    public $time;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Extra data to be held separate
 | 
						|
     *
 | 
						|
     * @var array
 | 
						|
     */
 | 
						|
    public $args;
 | 
						|
 | 
						|
    public function __construct(string $section, int $priority, string $message, array $args)
 | 
						|
    {
 | 
						|
        parent::__construct();
 | 
						|
        $this->section = $section;
 | 
						|
        $this->priority = $priority;
 | 
						|
        $this->message = $message;
 | 
						|
        $this->args = $args;
 | 
						|
        $this->time = time();
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
class DatabaseUpgradeEvent extends Event
 | 
						|
{
 | 
						|
}
 |