* @throws Exception when file is not readable * @throws Exception when ini file fails to parse * @throws Exception when url not found in ini file * @throws Exception when command not found in ini file * @throws Exception when pagesize is set incorrectly */ function getConfig() { $config = false; if (!is_readable("config.ini")) { throw new Exception('File config.ini does not exist'); } if (!$config = parse_ini_file("config.ini")) { throw new Exception('Could not parse ini file', 1); } if (!isset($config["url"])) { throw new Exception('`url` not found in ini file', 1); } if (!isset($config["command"])) { throw new Exception('`command` not found in ini file', 1); } // Set default page size if it's not in the config if (!isset($config["pagesize"])) { $config["pagesize"] = 3; } elseif (!is_int((int)$config["pagesize"]) || $config["pagesize"] < 1) { throw new Exception('Page size ' . $config["pagesize"] . ' not valid in config', 1); } // hash the password if (isset($config['password'])) { $config['hash'] = hash("sha256", $config['password']); } return $config; } /** * Use curl to find get the plain text file for a url * Using the sha256 hashed password if it's been set in the config * * @param string[] $config * @return StdClass[] * @author Phil Burton */ function getResultsFromUrl($config) { $curl = curl_init($config["url"] . "?format=plain"); if (isset($config["hash"])) { curl_setopt($curl, CURLOPT_HTTPHEADER, array("Cookie: password=" . $config["hash"])); } curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $output = explode("\n", curl_exec($curl)); curl_close($curl); if (!isset($output)) { throw new Exception( "Could not retrive results from http server `" . $config["url"] . "?format=json` using password=" . (isset($config["hash"]) ? "true" : "false"), 1 ); } return $output; } /** * Return the help text * * @param StdClass[] $config * @return string * @author Phil Burton */ function getHelp($config) { return "Usage: !" . $config["command"] . " [query] #[page] | " . "e.g: !" . $config["command"] . " intense | " . "!" . $config["command"] . " intense marcus | " . "!" . $config["command"] . " intense marcus #2 (returns the second page of results)"; } /** * Get the version string * * @param stdClass[] $config * @return string * @author Phil Burton */ function getVersion($config) { return $config["command"] . " v" . VERSION; } /** * Output the given string, adding a new line at the end * If pieces is an array, use the glue to implode and output a single string * * EXIT * * @param string|string[] $pieces * @param string $glue * @param bool $sderr * @author Phil Burton */ function output($pieces, $glue = " - ", $stderr = false) { $out = ""; if (!is_array($pieces)) { $out = $pieces . "\n"; } else { $out = implode($glue, $pieces) . "\n"; } if ($stderr) { fwrite(STDERR, $out . "\n"); } else { echo $out; } exit; } /** * Read stdin and return as a string * * @return string * @author Phil Burton */ function read_stdin() { $fr = fopen("php://stdin", "r"); $input = fgets($fr, 128); $input = rtrim($input); fclose($fr); return $input; } /** * Get the start and end index positions for the required page and * page size * * @param int $page * @param int $pagesize * @return int[] * @author Phil Burton */ function getPaginationBounds($page, $pagesize) { return [ "start" => ($page - 1) * $pagesize, "end" => (($page - 1) * $pagesize) + ($pagesize - 1) ]; } /** * Loop through the stdin and parse the arguments given * If we hit a "special" argument then run the specific code and exit * Otherwise we set the page and search terms and return them as an array * * @param $config * @return mixed[] * @author Phil Burton */ function getFormattedArguments($config) { $args = explode(" ", read_stdin()); if (!isset($args) || empty($args)) { throw new Exception("No arguments found"); } // Loop the raw arguments and create our formated argument array $formatArgs = []; $formatArgs["search"] = []; foreach ($args as $arg) { // Switch to check for special arguments // output should exit but incase it errors we double break switch ($arg) { case "--version": case "-v": // Flow through output(getVersion($config)); break 2; case "--help": case "-h": // Flow through output(getHelp($config)); break 2; } // Check to see if we have a page specified if (strpos($arg, "#") === 0) { $formatArgs["page"] = substr($arg, 1); continue; } // If we reach here, then the argument is a search term $formatArgs["search"][] = $arg; } // If we reach this point we must have at least one search term if (empty($formatArgs["search"])) { throw new Exception("Please Enter a search term"); } if (!isset($formatArgs["page"])) { $formatArgs["page"] = 1; } elseif (!is_int((int)$formatArgs["page"]) || $formatArgs["page"] < 1) { throw new Exception("Page number `" . $formatArgs["page"] . "` is not valid"); } return $formatArgs; } /********************************* * ENTRY POINT FOR FUNCTION HERE * *********************************/ try { $config = getConfig(); $content = getResultsFromUrl($config); $arguments = getFormattedArguments($config); // parse the arguments $page = $arguments["page"]; $out = []; // Really slow search $results = []; $regex = ""; foreach ($arguments["search"] as $arg) { $regex .= "(?=.*" . $arg . ")"; } $content = preg_grep("/" . $regex . "/i", $content); $results = $content; if (empty($results)) { output("No results found"); } $count = count($results); $i = 0; $bounds = getPaginationBounds($page, $config["pagesize"]); if ($bounds["start"] > ($count - 1)) { throw new Exception("No results for this page"); } foreach ($results as $result) { if ($i < $bounds["start"] || $i > $bounds["end"]) { $i++; continue; } $out[] = $i + 1 . ": " . $config["url"] . "/" . rawurlencode($result); $i++; } if ($count > 3) { $out[] = "results (" . $count . ")"; } output($out); } catch (Exception $e) { output($e->getMessage(), " - ", ($e->getCode() == 1)); }