1<?php
2// multiconference.php -- HotCRP multiconference installations
3// Copyright (c) 2006-2018 Eddie Kohler; see LICENSE.
4
5class Multiconference {
6    static private $original_opt = null;
7
8    static function init() {
9        global $Opt, $argv;
10        assert(self::$original_opt === null);
11        self::$original_opt = $Opt;
12
13        $confid = get($Opt, "confid");
14        if (!$confid && PHP_SAPI == "cli") {
15            for ($i = 1; $i != count($argv); ++$i) {
16                if ($argv[$i] === "-n" || $argv[$i] === "--name") {
17                    if (isset($argv[$i + 1]))
18                        $confid = $argv[$i + 1];
19                    break;
20                } else if (substr($argv[$i], 0, 2) === "-n") {
21                    $confid = substr($argv[$i], 2);
22                    break;
23                } else if (substr($argv[$i], 0, 7) === "--name=") {
24                    $confid = substr($argv[$i], 7);
25                    break;
26                } else if ($argv[$i] === "--") {
27                    break;
28                }
29            }
30        } else if (!$confid) {
31            $base = Navigation::site_absolute(true);
32            if (($multis = get($Opt, "multiconferenceAnalyzer"))) {
33                foreach (is_array($multis) ? $multis : array($multis) as $multi) {
34                    list($match, $replace) = explode(" ", $multi);
35                    if (preg_match("`\\A$match`", $base, $m)) {
36                        $confid = $replace;
37                        for ($i = 1; $i < count($m); ++$i)
38                            $confid = str_replace("\$$i", $m[$i], $confid);
39                        break;
40                    }
41                }
42            } else if (preg_match(',/([^/]+)/\z,', $base, $m))
43                $confid = $m[1];
44        }
45
46        if (!$confid)
47            $confid = "__nonexistent__";
48        else if (!preg_match(',\A[-a-zA-Z0-9_][-a-zA-Z0-9_.]*\z,', $confid))
49            $confid = "__invalid__";
50
51        self::assign_confid($Opt, $confid);
52    }
53
54    static function assign_confid(&$opt, $confid) {
55        foreach (array("dbName", "dbUser", "dbPassword", "dsn") as $k)
56            if (isset($opt[$k]) && is_string($opt[$k]))
57                $opt[$k] = preg_replace(',\*|\$\{conf(?:id|name)\}|\$conf(?:id|name)\b,', $confid, $opt[$k]);
58        if (!get($opt, "dbName") && !get($opt, "dsn"))
59            $opt["dbName"] = $confid;
60        $opt["confid"] = $confid;
61    }
62
63    static function load_confid($confid) {
64        global $Opt;
65        $save_opt = $Opt;
66        $Opt = self::$original_opt;
67        self::assign_confid($Opt, $confid);
68        if (get($Opt, "include"))
69            read_included_options($Opt["include"]);
70        $newconf = get($Opt, "missing") ? null : new Conf($Opt, true);
71        $Opt = $save_opt;
72        return $newconf;
73    }
74
75    static function fail_message($errors) {
76        global $Conf, $Me, $Opt;
77
78        if (is_string($errors))
79            $errors = array($errors);
80        if (get($Opt, "maintenance"))
81            $errors = array("The site is down for maintenance. " . (is_string($Opt["maintenance"]) ? $Opt["maintenance"] : "Please check back later."));
82
83        if (PHP_SAPI == "cli") {
84            fwrite(STDERR, join("\n", $errors) . "\n");
85            exit(1);
86        } else if (get($_GET, "ajax")) {
87            $ctype = get($_GET, "text") ? "text/plain" : "application/json";
88            header("Content-Type: $ctype; charset=utf-8");
89            if (get($Opt, "maintenance"))
90                echo "{\"error\":\"maintenance\"}\n";
91            else
92                echo "{\"error\":\"unconfigured installation\"}\n";
93        } else {
94            if (!$Conf)
95                $Conf = Conf::$g = new Conf($Opt, false);
96            $Me = null;
97            header("HTTP/1.1 404 Not Found");
98            $Conf->header("HotCRP Error", "", ["action_bar" => false]);
99            foreach ($errors as $i => &$e)
100                $e = ($i ? "<div class=\"hint\">" : "<p>") . htmlspecialchars($e) . ($i ? "</div>" : "</p>");
101            echo join("", $errors);
102            $Conf->footer();
103        }
104        exit;
105    }
106
107    static function fail_bad_options() {
108        global $Opt;
109        $errors = array();
110        if (get($Opt, "multiconference") && $Opt["confid"] === "__nonexistent__")
111            $errors[] = "You haven’t specified a conference and this is a multiconference installation.";
112        else if (get($Opt, "multiconference"))
113            $errors[] = "The “" . $Opt["confid"] . "” conference does not exist. Check your URL to make sure you spelled it correctly.";
114        else if (!get($Opt, "loaded"))
115            $errors[] = "HotCRP has been installed, but not yet configured. You must run `lib/createdb.sh` to create a database for your conference. See `README.md` for further guidance.";
116        else
117            $errors[] = "HotCRP was unable to load. A system administrator must fix this problem.";
118        if (!get($Opt, "loaded") && defined("HOTCRP_OPTIONS"))
119            $errors[] = "Error: Unable to load options file `" . HOTCRP_OPTIONS . "`";
120        else if (!get($Opt, "loaded"))
121            $errors[] = "Error: Unable to load options file";
122        if (get($Opt, "missing"))
123            $errors[] = "Error: Unable to load options from " . commajoin($Opt["missing"]);
124        self::fail_message($errors);
125    }
126
127    static function fail_bad_database() {
128        global $Conf, $Opt;
129        $errors = array();
130        if (get($Opt, "multiconference") && $Opt["confid"] === "__nonexistent__")
131            $errors[] = "You haven’t specified a conference and this is a multiconference installation.";
132        else if (get($Opt, "multiconference"))
133            $errors[] = "The “" . $Opt["confid"] . "” conference does not exist. Check your URL to make sure you spelled it correctly.";
134        else {
135            $errors[] = "HotCRP was unable to load. A system administrator must fix this problem.";
136            $errors[] = "Error: Unable to connect to database " . Dbl::sanitize_dsn($Conf->dsn);
137            if (defined("HOTCRP_TESTHARNESS"))
138                $errors[] = "You may need to run `lib/createdb.sh -c test/options.php` to create the database.";
139        }
140        self::fail_message($errors);
141    }
142}
143