Last commit for src/configs/ConfigureTool.php: 2addb500315b7393a90fe66431d7832b1e7386c7

Adjust copyrights years

Chris Pollett [2024-01-03 21:Jan:rd]
Adjust copyrights years
<?php
/**
 * SeekQuarry/Yioop --
 * Open Source Pure PHP Search Engine, Crawler, and Indexer
 *
 * Copyright (C) 2009 - 2023  Chris Pollett chris@pollett.org
 *
 * LICENSE:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * END LICENSE
 *
 * Used to create and manipulate a profile and work directory from the
 * command-line for Yioop.
 *
 * @author Chris Pollett chris@pollett.org
 * @license https://www.gnu.org/licenses/ GPL3
 * @link https://www.seekquarry.com/
 * @copyright 2009 - 2023
 * @filesource
 */
namespace seekquarry\yioop\configs;

use seekquarry\yioop\library as L;
use seekquarry\yioop\library\CrawlConstants;
use seekquarry\yioop\controllers\AdminController;

if (php_sapi_name() != 'cli' ||
    defined("seekquarry\\yioop\\configs\\IS_OWN_WEB_SERVER")) {
    echo "BAD REQUEST"; exit();
}
/** Loads common utility functions*/
require_once  __DIR__."/../library/Utility.php";
/** Loads common constants for web crawling*/
require_once __DIR__."/../library/LocaleFunctions.php";
mb_internal_encoding("UTF-8");
mb_regex_encoding("UTF-8");
/**
 * shorthand for echo
 *
 * @param string $text string to send to the current output
 */
function e($text)
{
    echo $text;
}
$locale_tag = L\guessLocale();
$locale = null;
L\setLocaleObject($locale_tag);
/**
 * Provides a command-line interface way to configure a Yioop Instance.
 * Unlike the web interface this interface is English-only.
 */
class ConfigureTool
{
    /**
     * Used to hold an AdminController object used to manipulate the
     * Yioop configuration
     * @var object
     */
    public $admin;
    /**
     * Holds the main menu data for the configuration tool
     * @var array
     */
    public $menu = ["workDirectory" => "Create/Set Work Directory",
        "rootPassword" => "Change root password",
        "defaultLocale"=> "Set Default Locale",
        "debugDisplay"=> "Debug Display Set-up",
        "searchAccess"=> "Search Access Set-up",
        "searchPageElementLinks" => "Search Page Elements and Links",
        "nameServer" => "Name Server Set-up",
        "robotSetUp"=> "Crawl Robot Set-up",
        "quit" => "Exit program"
    ];
    /**
     * To change configuration parameters of Yioop, this program
     * invokes AdminController methods. These methods expect, data
     * passed to them in super globals set up as a result of an HTTP
     * request. This program fakes the settings of these variables.
     * To keep things simple this constructor initializes each of the
     * relevant super globals to be empty arrays.
     */
    function __construct()
    {
        $_REQUEST = [];
        $_POST = [];
        $_GET = [];
        $_SERVER = [];
        $_SESSION = [];
        $this->admin = new AdminController();
    }
    /**
     * This is the main loop where options of what the user can configure
     * are presented, a choice is requested, and so on...
     */
    function loop()
    {
        $done = false;
        $activities = array_keys($this->menu);
        $activities[] = "configureMenu";
        $state = "configureMenu";
        while($state != "quit") {
            if (in_array($state, $activities) ) {
                $state = $this->$state();
            }
        }
    }
    /**
     * This is used to draw the main configuration menu and ask for a
     * user selection
     */
    function configureMenu()
    {
        $this->banner();
        $data = $this->callConfigure();
        e("Checking Yioop configuration...".
            "\n===============================\n");
        $check_status = str_replace("<br>", "\n", $data["SYSTEM_CHECK"]);
        e($check_status."\n===============================\n");
        $items = ["workDirectory" => "Create/Set Work Directory",
            "quit" => "Exit program"];
        if ($data["PROFILE"]) {
            $items = $this->menu;
        }
        return $this->drawChooseItems($items, "configureMenu");
    }
    /**
     * Used to create/change the location of this Yioop instances work
     * directory
     */
    function workDirectory()
    {
        $this->banner();
        $data = $this->callConfigure();
        $directory = (isset($data["WORK_DIRECTORY"]) &&
            $data["WORK_DIRECTORY"] != "") ? $data["WORK_DIRECTORY"]
            : "No value set yet.";
        e("CURRENT WORK DIRECTORY: $directory\n\n");
        e("Enter a new value:\n");
        if (!isset($_SERVER['REQUEST_URI'])) {
            $_SERVER['REQUEST_URI'] = "";
        }
        $this->prepareGlobals($data);
        $_REQUEST["WORK_DIRECTORY"] = L\readInput();
        $_REQUEST["arg"] = "directory";
        $next_menu = $this->confirmChange("configure", "workDirectory");
        return $next_menu;
    }
    /**
     * Used to change the password of the root account of this Yioop Instance
     */
    function rootPassword()
    {
        $this->banner();
        $data = $this->callConfigure();
        if ($data["PROFILE"] != 1) {
            $_REQUEST["MESSAGE"] = "Work directory needs to be set/created!";
            return "configureMenu";
        }
        e("Enter old password:");
        $_REQUEST["password"] = L\readPassword();
        e("Enter new password:");
        $_REQUEST["new_password"] = L\readPassword();
        e("Re-Enter new password:");
        $_REQUEST["retype_password"] = L\readPassword();
        $_SESSION['USER_ID'] = ROOT_ID;
        $_REQUEST['arg'] = "updateuser";
        $_REQUEST['edit_pass'] = "true";
        $next_menu = $this->confirmChange("manageAccount", "rootPassword");
        return $next_menu;
    }
    /**
     * Changes the default locale (language) used by Yioop when it cannot
     * determine that information from the user's browser
     */
    function defaultLocale()
    {
        $this->banner();
        $data = $this->callConfigure();
        if ($data["PROFILE"] != 1) {
            $_REQUEST["MESSAGE"] = "Work directory needs to be set/created!";
            return "configureMenu";
        }
        e("CURRENT LANGUAGE: ".$data["LANGUAGES"][
            $data["DEFAULT_LOCALE"]]."\n\n");
        $_SESSION = [];
        $items = $data["LANGUAGES"];
        $items["configureMenu"] = "Return to Main Menu";
        do {
            $choice = $this->drawChooseItems($items, "defaultLocale");
        } while( $choice == "defaultLocale");
        $this->prepareGlobals($data);
        if ($choice == "configureMenu") {
            $_REQUEST = [];
            $_SERVER = [];
            return "configureMenu";
        }
        $_REQUEST["DEFAULT_LOCALE"] = $choice;
        return "defaultLocale";
    }
    /**
     * Used to configure debugging information for this Yioop instance.
     * i.e., whether PHP notices, warnings, errors, should be displayed,
     * whether query statistics and info should be displayed, and whether
     * unit tests should be viewable from the web
     */
    function debugDisplay()
    {
        $this->banner();
        $data = $this->callConfigure();
        if ($data["PROFILE"] != 1) {
            $_REQUEST["MESSAGE"] = "Work directory needs to be set/created!";
            return "configureMenu";
        }
        e("CURRENT DEBUG SETTINGS\n======================\n");
        $dlevel = $data["DEBUG_LEVEL"];
        $setting = ($dlevel & ERROR_INFO) ? "On" : "Off";
        e("Error Info: [$setting]\n");
        $setting = ($dlevel & QUERY_INFO) ? "On" : "Off";
        e("Query Info: [$setting]\n");
        $setting = ($dlevel & TEST_INFO) ? "On" : "Off";
        e("Test Info: [$setting]\n");
        $items = ["ERROR_INFO" => "Toggle Error Info",
            "QUERY_INFO" => "Toggle Query Info",
            "TEST_INFO" => "Toggle Test Info",
            "configureMenu" => "Return to Main Menu"];
        do {
            $choice = $this->drawChooseItems($items, "debugDisplay");
        } while( $choice == "debugDisplay");
        $this->prepareGlobals($data);
        if ($choice == "configureMenu") {
            $_REQUEST = [];
            $_SERVER = [];
            return "configureMenu";
        }
        $flag = constant(NS_CONFIGS . $choice);
        $dlevel = ($dlevel & $flag) ? $dlevel - $flag : $dlevel + $flag;
        if ($dlevel & ERROR_INFO) {$_REQUEST["ERROR_INFO"] = "true";}
        if ($dlevel & QUERY_INFO) {$_REQUEST["QUERY_INFO"] = "true";}
        if ($dlevel & TEST_INFO) {$_REQUEST["TEST_INFO"] = "true";}
        return "debugDisplay";
    }
    /**
     * Configures which methods are allowed by this Yioop instance to access
     * search results, (via the web, via open rss search results, via the
     * API)
     */
    function searchAccess()
    {
        $this->banner();
        $data = $this->callConfigure();
        if ($data["PROFILE"] != 1) {
            $_REQUEST["MESSAGE"] = "Work directory needs to be set/created!";
            return "configureMenu";
        }
        e("CURRENT SEARCH ACCESS SETTINGS\n==============================\n");
        $settings = ["WEB_ACCESS" => "Web",
            "RSS_ACCESS" => "RSS", "API_ACCESS" => "API"];
        $items = [];
        foreach ($settings as $setting => $setting_string) {
            $toggle = ($data[$setting]) ? "On" : "Off";
            e("$setting_string: [$toggle]\n");
            $items[$setting] = "Toggle $setting_string";
        }
        $items["configureMenu"] = "Return to Main Menu";
        do {
            $choice = $this->drawChooseItems($items, "searchAccess");
        } while( $choice == "searchAccess");
        $this->prepareGlobals($data);
        if ($choice == "configureMenu") {
            $_REQUEST = [];
            $_SERVER = [];
            return "configureMenu";
        }
        $_REQUEST[$choice] = ($data[$choice]) ? false : true;
        return "searchAccess";
    }
    /**
     * Configures which of the various links of the SERPS page such as
     * Cache, etc should be displayed. Also, configures whether the signin
     * links, etc should be displayed.
     */
    function searchPageElementLinks()
    {
        $this->banner();
        $data = $this->callConfigure();
        if ($data["PROFILE"] != 1) {
            $_REQUEST["MESSAGE"] = "Work directory needs to be set/created!";
            return "configureMenu";
        }
        e("CURRENT SEARCH PAGE ELEMENTS AND LINKS SETTINGS".
            "\n===================================================\n");
        $settings = ["WORD_SUGGEST" => "Word Suggest",
            "SUBSEARCH_LINK"  => "Subsearch Links",
            "SIGNIN_LINK" => "Sign-in Links",
            "MORE_RESULT" => "More Result Info",
            "CACHE_LINK" => "Cache Link",
            "SIMILAR_LINK" => "Similar Link", "IN_LINK" => "Inlinks",
            "IP_LINK"=> "IP Links"];
        $items = [];
        foreach ($settings as $setting => $setting_string) {
            $toggle = ($data[$setting]) ? "On" : "Off";
            e("$setting_string: [$toggle]\n");
            $items[$setting] = "Toggle $setting_string";
        }
        $items["configureMenu"] = "Return to Main Menu";
        do {
            $choice = $this->drawChooseItems($items, "searchPageElementLinks");
        } while( $choice == "searchPageElementLinks");
        $this->prepareGlobals($data);
        if ($choice == "configureMenu") {
            $_REQUEST = [];
            $_SERVER = [];
            return "configureMenu";
        }
        $_REQUEST[$choice] = ($data[$choice]) ? false : true;
        return "searchPageElementLinks";
    }
    /**
     * Configures settings relating to the location of the name server and
     * the salt used when communicating with it. Also, configures caching
     * mechanisms the name server should use when returning results.
     */
    function nameServer()
    {
        $this->banner();
        $data = $this->callConfigure();
        if ($data["PROFILE"] != 1) {
            $_REQUEST["MESSAGE"] = "Work directory needs to be set/created!";
            return "configureMenu";
        }
        e("NAME SERVER SETTINGS\n====================\n");
        e("Server Key: [".$data["AUTH_KEY"]."]\n");
        e("Name Server URL: [".$data["NAME_SERVER"]."]\n");
        $settings = ["USE_FILECACHE" => "Use File Cache"];
        $items = ["serverKey" => "Edit Server Key",
            "nameServer" => "Edit Name Server Url"];
        foreach ($settings as $setting => $setting_string) {
            $toggle = ($data[$setting]) ? "On" : "Off";
            e("$setting_string: [$toggle]\n");
            $items[$setting] = "Toggle $setting_string";
        }
        $items["configureMenu"] = "Return to Main Menu";
        do {
            $choice = $this->drawChooseItems($items, "nameServerMenu");
        } while( $choice == "nameServerMenu");
        $this->prepareGlobals($data);
        switch ($choice) {
            case "configureMenu":
                $_REQUEST = [];
                $_SERVER = [];
                return "configureMenu";
                break;
            case "serverKey":
                e("Enter a new server key: ");
                $_REQUEST["AUTH_KEY"] = L\readInput();
                break;
            case "nameServer":
                e("Enter a new name server url: ");
                $_REQUEST["NAME_SERVER"] = L\readInput();
                break;
            default:
                $_REQUEST[$choice] = ($data[$choice]) ? false : true;
        }
        return "nameServer";
    }
    /**
     * Used to set up the name of this instance of the Yioop robot as well
     * as its description page.
     */
    function robotSetUp()
    {
        $this->banner();
        $data = $this->callConfigure();
        if ($data["PROFILE"] != 1) {
            $_REQUEST["MESSAGE"] = "Work directory needs to be set/created!";
            return "configureMenu";
        }
        e("CRAWL ROBOT SETTINGS\n====================\n");
        e("Crawl Robot Name: [".$data["USER_AGENT_SHORT"]."]\n");
        e("Robot Instance: [".$data["ROBOT_INSTANCE"]."]\n");
        e("\nRobot Description:\n=================\n".
            $data["ROBOT_DESCRIPTION"] . "\n=================\n");
        $items = ["robotName" => "Edit Robot Name",
            "robotInstance" => "Edit Robot Instance",
            "robotDescription" => "Edit Robot Description",
            "configureMenu" => "Return to Main Menu"];
        do {
            $choice = $this->drawChooseItems($items, "robotSetUp");
        } while( $choice == "robotSetUp");
        $this->prepareGlobals($data);
        switch ($choice) {
            case "configureMenu":
                $_REQUEST = [];
                $_SERVER = [];
                return "configureMenu";
                break;
            case "robotName":
                e("Enter a new robot name: ");
                $_REQUEST["USER_AGENT_SHORT"] = L\readInput();
                break;
            case "robotInstance":
                e("Enter a new robot instance value: ");
                $_REQUEST["ROBOT_INSTANCE"] = L\readInput();
                break;
            case "robotDescription":
                e("Enter a description of your web crawler robot.\n".
                  "Terminate input with a line with only '.' on it:\n");
                $_REQUEST["ROBOT_DESCRIPTION"] = L\readMessage();
                break;
        }
        return "robotSetUp";
    }
    /**
     * Used to select to confirm, cancel, or re-enter the last profile
     * change
     *
     * @param string $admin_method to call if confirmed
     * @param string $reenter_method , return value if reenter chosen
     * @return string menu name to do to next
     */
    function confirmChange($admin_method, $reenter_method)
    {
        $component_activities = AdminController::$component_activities;
        $items = ["confirm" => "Confirm Change",
            "reenter" => "Re-enter the information",
            "configureMenu" => "Return to the Configure Menu"];
        $first = true;
        do {
            $choice = $this->drawChooseItems($items, "confirmChange");
        } while( $choice == "confirmChange");
        switch ($choice) {
            case "confirm":
                $component = "system";
                foreach ($component_activities as $available_component =>
                    $activities) {
                    if (in_array($admin_method, $activities)) {
                        $component = $available_component;
                        break;
                    }
                }
                $data = $this->admin->component($component)->$admin_method();
                $_SERVER = [];
                $_SESSION = [];
                $_REQUEST = [];
                $_REQUEST["MESSAGE"] = $data["MESSAGE"];
                $next_menu = "configureMenu";
                break;
            case "reenter":
                $_SERVER = [];
                $_SESSION = [];
                $_REQUEST = [];
                $next_menu = $reenter_method;
                break;
            default:
                $_SERVER = [];
                $_SESSION = [];
                $_REQUEST = [];
                $next_menu = "configureMenu";
        }
        return $next_menu;
    }
    /**
     * Draws a list of options to the screen and gets a choice
     * from this list from the user.
     *
     * @param array $items as associative array (return value => description)
     * @param string $currentView value to return if invalid choice made
     * @return string a choice from the user
     */
    function drawChooseItems($items, $currentView)
    {
        $choice_nums = [];
        $i = 1;
        e("\nAvailable Options:\n==================\n");
        foreach ($items as $name => $description) {
            e("($i) $description\n");
            $choice_nums[$i] = $name;
            $i++;
        }
        if (!empty($_REQUEST["MESSAGE"])) {
            e("\n+++ ".$_REQUEST["MESSAGE"]." +++\n");
            unset($_REQUEST["MESSAGE"]);
        }
        e("\nPlease choose an option:\n");
        $user_data = strtolower(trim(L\readInput()));
        if ($user_data >= 1 && $user_data < $i) {
            $_REQUEST["MESSAGE"] = "";
            return $choice_nums[$user_data];
        } else {
            $_REQUEST["MESSAGE"] = "Invalid choice. Please choose again.";
            return $currentView;
        }
    }
    /**
     * Used to call system components configure method. It detects if
     * a redirect happened by the fact that $data['PROFILE'] is not set.
     * If so it passes along the redirect message and re-calls configure()
     */
    function callConfigure()
    {
        $data = $this->admin->component("system")->configure();
        if (!isset($data["PROFILE"])) {
            $_REQUEST = [];
            $message = (isset($data['MESSAGE'])) ? $data['MESSAGE'] : "";
            $data = $this->admin->component("system")->configure();
            $data['MESSAGE'] = $message;
        }
        return $data;
    }
    /**
     * Prints the banner used by this configuration tool
     */
    function banner()
    {
        e(chr(27) . "[2J" . chr(27) . "[;H");
        e("\n\nYIOOP! CONFIGURATION TOOL\n");
        e("+++++++++++++++++++++++++\n\n");
    }
    /**
     * Sets-up the field values of the super globals used by AdminController
     * when changing a profile or managing passwords. These particular
     * values don't change with respect to what this tool does.
     *
     * @param array $data current profile state
     */
    function prepareGlobals($data)
    {
        $_SESSION = [];
        $_REQUEST = $this->copyProfileFields($data);
        $_REQUEST["arg"] = "profile";
        $_REQUEST['YIOOP_TOKEN'] = "";
        if (!isset($_SERVER['REQUEST_URI'])) {
            if (!empty($data['WEB_URI'])) {
                $_SERVER['REQUEST_URI'] = $data['WEB_URI'];
            } else {
                e("Enter web path for Yioop instance:\n");
                $_SERVER['REQUEST_URI'] = L\readInput();
            }
        }
    }
    /**
     * Used to copy the contents of $data which are profile fields to a
     * new array.
     *
     * @param array $data an array of profile and other fields
     * @return array a new array containing a copy of just the profile fields
     *     from the original array
     */
    function copyProfileFields($data)
    {
        $profile = [];
        foreach ($this->admin->model("profile")->profile_fields as $field) {
            if (isset($data[$field])) {
                $profile[$field] = $data[$field];
            }
        }
        return $profile;
    }
}
$configure_tool = new ConfigureTool();
$configure_tool->loop();
ViewGit