Fix a bunch of bugs. We're getting there~
This commit is contained in:
parent
37aa996385
commit
184097b324
10 changed files with 189 additions and 140 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,5 +1,7 @@
|
||||||
# The application's data directory
|
# The application's data directory
|
||||||
data/
|
data/
|
||||||
|
# The custom settings file
|
||||||
|
/settings.toml
|
||||||
|
|
||||||
# Created by https://www.gitignore.io/api/composer,git
|
# Created by https://www.gitignore.io/api/composer,git
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace Sandpiper;
|
||||||
|
|
||||||
abstract class AbstractAction
|
abstract class AbstractAction
|
||||||
{
|
{
|
||||||
public abstract function handle();
|
public abstract function handle();
|
||||||
|
@ -8,11 +10,11 @@ abstract class AbstractAction
|
||||||
return !empty($_GET[$key]);
|
return !empty($_GET[$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_param($key, $default_value) {
|
public function param_get($key, $default_value) {
|
||||||
return $_GET[$key] ?? $default_value;
|
return $_GET[$key] ?? $default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get_post_body() {
|
public function get_post_body() {
|
||||||
return file_get_contents("php://input");
|
return file_get_contents("php://input");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
namespace Sandpiper\Actions;
|
namespace Sandpiper\Actions;
|
||||||
|
|
||||||
|
use \Yosymfony\Toml\Toml;
|
||||||
|
|
||||||
|
use \SBRL\Utilities\SimpleXmlWriter;
|
||||||
|
|
||||||
class Report extends \Sandpiper\AbstractAction
|
class Report extends \Sandpiper\AbstractAction
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -11,6 +15,106 @@ class Report extends \Sandpiper\AbstractAction
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle() {
|
public function handle() {
|
||||||
|
global $settings;
|
||||||
|
|
||||||
|
header("content-type: text/plain");
|
||||||
|
|
||||||
|
if(!$this->param_exists("place_id"))
|
||||||
|
exit("Error: No place id provided.\n");
|
||||||
|
if(!$this->param_exists("summary"))
|
||||||
|
exit("Error: No summary provided.\n");
|
||||||
|
if(!$this->param_exists("version"))
|
||||||
|
exit("No version provided.\n");
|
||||||
|
|
||||||
|
/******************************************************/
|
||||||
|
|
||||||
|
$place = null;
|
||||||
|
foreach($settings->get("places") as $current_place) {
|
||||||
|
var_dump($current_place);
|
||||||
|
if($current_place["key"] == $this->param_get("place_id", null)) {
|
||||||
|
$place = $current_place;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($place == null)
|
||||||
|
exit("Error: Place id doesn't match.\n");
|
||||||
|
|
||||||
|
$new_report = new \stdClass();
|
||||||
|
$new_report->version = escape4xml($this->param_get("version", "?"));
|
||||||
|
$new_report->summary = escape4xml($this->param_get("summary", "(Unknown error)"));
|
||||||
|
$new_report->details = escape4xml($this->param_get("details", ""));
|
||||||
|
$new_report->stack_trace = escape4xml($this->get_post_body());
|
||||||
|
|
||||||
|
$report_dir = ROOT_DIR . "/{$settings->get("data_dir")}/places/" . slugify($place["name"]);
|
||||||
|
$report_filename = "$report_dir/" . slugify($new_report->summary) . ".xml";
|
||||||
|
|
||||||
|
// Create the directory if it doesn't exist already
|
||||||
|
if(!file_exists($report_dir))
|
||||||
|
mkdir($report_dir, 0750, true);
|
||||||
|
|
||||||
|
// Save the individual report
|
||||||
|
|
||||||
|
if(!file_exists($report_filename)) {
|
||||||
|
$writer = new \SBRL\Utilities\SimpleXmlWriter(); // It's started automagically
|
||||||
|
$writer->prettyprint = true;
|
||||||
|
$writer->add_xslt("/theme/stack_traces.xslt");
|
||||||
|
$writer->open("error_info");
|
||||||
|
$writer->addtag("project_name", [], $place["name"]); // For aesthetic purposes
|
||||||
|
$writer->addtag("summary", [], $new_report->summary);
|
||||||
|
$writer->open("reports");
|
||||||
|
$writer->close();
|
||||||
|
$writer->close();
|
||||||
|
file_put_contents($report_filename, $writer->render());
|
||||||
|
}
|
||||||
|
|
||||||
|
$report_xml = simplexml_load_file($report_filename);
|
||||||
|
|
||||||
|
if($report_xml === false)
|
||||||
|
exit("Error: invalid XML generated when creating a new report file.\n");
|
||||||
|
|
||||||
|
$report_node = $report_xml->reports->addChild("report");
|
||||||
|
$report_node->addChild("timestamp", date(DATE_ATOM));
|
||||||
|
$report_node->addChild("version", $new_report->version);
|
||||||
|
$report_node->addChild("details", $new_report->details);
|
||||||
|
$report_node->addChild("stack_trace", $new_report->stack_trace);
|
||||||
|
|
||||||
|
file_put_contents($report_filename, $report_xml->asXML());
|
||||||
|
|
||||||
|
// Update the place index
|
||||||
|
$place_index_filename = "$report_dir/index.xml";
|
||||||
|
|
||||||
|
if(!file_exists($place_index_filename)) {
|
||||||
|
$writer = new SimpleXmlWriter();
|
||||||
|
$writer->prettyprint = true;
|
||||||
|
|
||||||
|
$writer->add_xslt(ROOT_DIR . "/theme/place_index.xslt");
|
||||||
|
$writer->open("errors");
|
||||||
|
$writer->close();
|
||||||
|
file_put_contents($place_index_filename, $writer->render());
|
||||||
|
}
|
||||||
|
$index_xml = simplexml_load_file($place_index_filename);
|
||||||
|
|
||||||
|
$index_entry = null;
|
||||||
|
foreach($index_xml as $entry) {
|
||||||
|
if($entry->summary->__toString() != $new_report->summary)
|
||||||
|
continue;
|
||||||
|
$index_entry = $entry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($index_entry == null) {
|
||||||
|
$index_entry = $index_xml->addChild("error");
|
||||||
|
$index_entry->summary = $new_report->summary;
|
||||||
|
$index_entry->last_report = date(DATE_ATOM);
|
||||||
|
$index_entry->report_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$index_entry->report_count = intval($index_entry->report_count) + 1;
|
||||||
|
|
||||||
|
file_put_contents($place_index_filename, $index_xml->asXML());
|
||||||
|
|
||||||
|
http_response_code(200);
|
||||||
|
exit("Report submitted successfully!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
default_settings.toml
Normal file
16
default_settings.toml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
###################################
|
||||||
|
# Default Sandpiper settings file #
|
||||||
|
###################################
|
||||||
|
|
||||||
|
# Don't edit this unless you know what you are doing! You probably want to edit
|
||||||
|
# the `settings.toml` file in this directory instead.
|
||||||
|
|
||||||
|
# The data directory
|
||||||
|
# Relative to this directory - and shouldn't contain a trailing slash.
|
||||||
|
data_dir = "data"
|
||||||
|
|
||||||
|
[places]
|
||||||
|
|
||||||
|
# [places.example-project]
|
||||||
|
# name = "An Awesome Project";
|
||||||
|
# key = "A very sekret key"; # Required by clients to report an error to this project. Should be unique!
|
|
@ -1,8 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require("settings.php");
|
|
||||||
require("utilities/comment_key.php");
|
|
||||||
|
|
||||||
header("content-type: text/plain");
|
|
||||||
|
|
||||||
exit(key_generate($settings->comment_key_pass));
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
define("ROOT_DIR", dirname(__FILE__));
|
||||||
|
|
||||||
require("vendor/autoload.php");
|
require("vendor/autoload.php");
|
||||||
require("utilities/transform.php");
|
require("utilities/transform.php");
|
||||||
|
|
||||||
|
@ -12,7 +14,7 @@ $aura_loader->register();
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
$settings = new \SBRL\Utilities\TomlConfig("settings.toml", "default_settings.toml");
|
||||||
|
|
||||||
function send_error($code, $message) {
|
function send_error($code, $message) {
|
||||||
http_response_code($code);
|
http_response_code($code);
|
||||||
|
|
106
report.php
106
report.php
|
@ -1,106 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require("settings.php");
|
|
||||||
require("utilities/comment_key.php");
|
|
||||||
require("utilities/transform.php");
|
|
||||||
require("utilities/simplexmlwriter.php");
|
|
||||||
|
|
||||||
header("content-type: text/plain");
|
|
||||||
|
|
||||||
if(empty($_GET["place_id"]))
|
|
||||||
exit("Error: No place id provided.\n");
|
|
||||||
if(empty($_GET["summary"]))
|
|
||||||
exit("Error: No summary provided.\n");
|
|
||||||
if(empty($_GET["version"]))
|
|
||||||
exit("No version provided.\n");
|
|
||||||
|
|
||||||
/*if(empty($_GET["key"]))
|
|
||||||
exit("Error: No key provided.\n");
|
|
||||||
|
|
||||||
if(!key_verify(
|
|
||||||
$_GET["key"],
|
|
||||||
$settings->comment_key_pass,
|
|
||||||
$settings->comment_key_min_age, $settings->comment_key_max_age
|
|
||||||
))
|
|
||||||
exit("Error: Invalid key.\n");
|
|
||||||
*/
|
|
||||||
/******************************************************/
|
|
||||||
|
|
||||||
$places = json_decode(file_get_contents("$settings->data_dir/places.json"));
|
|
||||||
|
|
||||||
$place = null;
|
|
||||||
foreach($places as $current_place) {
|
|
||||||
if($place->key == $_GET["place_id"]) {
|
|
||||||
$place = $current_place;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if($place == null)
|
|
||||||
exit("Error: Place id doesn't match.\n");
|
|
||||||
|
|
||||||
$new_report = new stdClass();
|
|
||||||
$new_report->version = escape4xml($_GET["version"]);
|
|
||||||
$new_report->summary = escape4xml($_GET["summary"]);
|
|
||||||
$new_report->stack_trace = escape4xml(file_get_contents('php://input'));
|
|
||||||
|
|
||||||
$report_dir = "$settings->data_dir/places/$place->name";
|
|
||||||
$report_filename = "$report_dir/" . slugify($new_report->summary) . ".xml";
|
|
||||||
|
|
||||||
// Save the individual report
|
|
||||||
|
|
||||||
if(!file_exists($report_filename)) {
|
|
||||||
$writer = new SimpleXmlWriter();
|
|
||||||
$writer->start();
|
|
||||||
$writer->add_xslt("../../theme/stack_traces.xslt");
|
|
||||||
$writer->open("error_info");
|
|
||||||
$writer->addtag("summary", [], $new_report->summary);
|
|
||||||
$writer->open("reports");
|
|
||||||
$writer->close();
|
|
||||||
$writer->close();
|
|
||||||
file_put_contents($report_filename, $writer->render());
|
|
||||||
}
|
|
||||||
|
|
||||||
$report_xml = simplexml_load_file($report_filename);
|
|
||||||
|
|
||||||
if($report_xml === false)
|
|
||||||
exit("Error: invalid XML generated when creating a new report file.\n");
|
|
||||||
|
|
||||||
$report_node = $report_xml->reports->addChild("report");
|
|
||||||
$report_node->addChild("timestamp", date(DATE_ATOM));
|
|
||||||
$report_node->addChild("version", $new_report->version);
|
|
||||||
$report_node->addChild("summary", $new_report->summary);
|
|
||||||
$report_node->addChild("stack_trace", $new_report->stack_trace);
|
|
||||||
|
|
||||||
file_put_contents($report_filename, $report_xml->asXML());
|
|
||||||
|
|
||||||
// Update the place index
|
|
||||||
$place_index_filename = "$report_dir/index.xml";
|
|
||||||
if(!file_exists($place_index_filename)) {
|
|
||||||
$writer = new SimpleXmlWriter();
|
|
||||||
$writer->start();
|
|
||||||
$writer->add_xslt("../../theme/place_index.xslt");
|
|
||||||
$writer->open("errors");
|
|
||||||
$writer->close();
|
|
||||||
file_put_contents($place_index_filename, $writer->render());
|
|
||||||
}
|
|
||||||
$index_xml = simplexml_load_file($place_index_filename);
|
|
||||||
|
|
||||||
$index_entry = null;
|
|
||||||
foreach($index_xml as $entry) {
|
|
||||||
if($entry->summary->__toString() != $new_report->summary)
|
|
||||||
continue;
|
|
||||||
$index_entry = $entry;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($index_entry == null) {
|
|
||||||
$index_entry = $index_xml->addChild("error");
|
|
||||||
$index_entry->summary = $new_report->summary;
|
|
||||||
$index_entry->last_report = date(DATE_ATOM);
|
|
||||||
$index_entry->report_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$index_entry->report_count = intval($index_entry->report_count) + 1;
|
|
||||||
|
|
||||||
file_put_contents($place_index_filename, $index_xml->asXML());
|
|
|
@ -123,19 +123,16 @@ class SimpleXmlWriter {
|
||||||
{
|
{
|
||||||
$result = $this->xml;
|
$result = $this->xml;
|
||||||
|
|
||||||
$revopentags = array_reverse($this->opentags);
|
$this->closeall();
|
||||||
foreach($revopentags as $tagname)
|
|
||||||
{
|
|
||||||
if($this->prettyprint)
|
|
||||||
$result .= str_repeat("\t", count($revopentags)) . "</$tagname>\n";
|
|
||||||
else
|
|
||||||
$result .= "</$tagname>";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function indent()
|
||||||
|
{
|
||||||
|
$this->add($this->getindent());
|
||||||
|
}
|
||||||
|
|
||||||
//get the appropriate number of tab characters for indentation purposes
|
//get the appropriate number of tab characters for indentation purposes
|
||||||
protected function getindent()
|
protected function getindent()
|
||||||
{
|
{
|
||||||
|
@ -145,7 +142,6 @@ class SimpleXmlWriter {
|
||||||
//function to add to the rendered XML string
|
//function to add to the rendered XML string
|
||||||
protected function add($text = "", $newline = true)
|
protected function add($text = "", $newline = true)
|
||||||
{
|
{
|
||||||
|
|
||||||
if($newline and $this->prettyprint)
|
if($newline and $this->prettyprint)
|
||||||
$this->xml .= $this->getindent();
|
$this->xml .= $this->getindent();
|
||||||
|
|
|
@ -133,10 +133,16 @@ class TomlConfig
|
||||||
$pathParts = explode(".", $path);
|
$pathParts = explode(".", $path);
|
||||||
$subObj = $obj;
|
$subObj = $obj;
|
||||||
foreach($pathParts as $part) {
|
foreach($pathParts as $part) {
|
||||||
|
if(is_array($part)) {
|
||||||
|
if(!isset($subObj[$part]))
|
||||||
|
return false;
|
||||||
|
$subObj = $subObj[$part];
|
||||||
|
} else {
|
||||||
if(!isset($subObj->$part))
|
if(!isset($subObj->$part))
|
||||||
return false;
|
return false;
|
||||||
$subObj = $subObj->$part;
|
$subObj = $subObj->$part;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -146,12 +152,23 @@ class TomlConfig
|
||||||
* @param string $path The path to extract from the given object.
|
* @param string $path The path to extract from the given object.
|
||||||
* @return mixed The property identified by the given object.
|
* @return mixed The property identified by the given object.
|
||||||
*/
|
*/
|
||||||
public static function getPropertyByPath($obj, $path) {
|
public static function getPropertyByPath($obj, $path, $defaultValue = null) {
|
||||||
$pathParts = explode(".", $path);
|
$pathParts = explode(".", $path);
|
||||||
$subObj = $obj;
|
$subObj = $obj;
|
||||||
foreach($pathParts as $part) {
|
foreach($pathParts as $part) {
|
||||||
|
if(is_array($part)) {
|
||||||
|
if(!isset($subObj[$part]))
|
||||||
|
return $defaultValue;
|
||||||
|
|
||||||
|
$subObj = $subObj[$part];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(!isset($subObj->$part))
|
||||||
|
return $defaultValue;
|
||||||
|
|
||||||
$subObj = $subObj->$part;
|
$subObj = $subObj->$part;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return $subObj;
|
return $subObj;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -169,14 +186,14 @@ class TomlConfig
|
||||||
for($i = 0; $i < $pathPartsCount; $i++) {
|
for($i = 0; $i < $pathPartsCount; $i++) {
|
||||||
// Set the property on the last iteration
|
// Set the property on the last iteration
|
||||||
if($i + 1 == $pathPartsCount) {
|
if($i + 1 == $pathPartsCount) {
|
||||||
$subObj->$part = $value;
|
$subObj[$part] = $value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Create sub-objects if they dobn't exist already
|
// Create sub-objects if they dobn't exist already
|
||||||
if(!isset($subObj->$part)) {
|
if(!isset($subObj->$part)) {
|
||||||
$subObj->$part = new stdClass();
|
$subObj[$part] = new stdClass();
|
||||||
}
|
}
|
||||||
$subObj = $subObj->$part;
|
$subObj = $subObj[$part];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,42 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalises and removes any unknown characters from a string, making it safe
|
||||||
|
* for use as a filename.
|
||||||
|
* @param string $string The string to slugificate.
|
||||||
|
* @param integer $maxlength The maximum desired length of the resultant string.
|
||||||
|
* @return string The slugified string.
|
||||||
|
*/
|
||||||
function slugify($string, $maxlength = 50) {
|
function slugify($string, $maxlength = 50) {
|
||||||
return preg_replace([
|
var_dump($string);
|
||||||
'\s+',
|
return substr(preg_replace([
|
||||||
'[^a-z0-9\-_]'
|
'/\s+/',
|
||||||
|
'/[^a-z0-9\-_]/'
|
||||||
], [
|
], [
|
||||||
'-',
|
'-',
|
||||||
''
|
''
|
||||||
],
|
],
|
||||||
strtolower(trim($string))
|
strtolower(trim($string))
|
||||||
);
|
), 0, $maxlength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escapes a string ready for inclusion in an XML document.
|
||||||
|
* @param string $string The string to escape.
|
||||||
|
* @return string The escaped string.
|
||||||
|
*/
|
||||||
function escape4xml($string) {
|
function escape4xml($string) {
|
||||||
return htmlspecialchars($string, ENT_QUOTES | ENT_XML1);
|
return htmlspecialchars($string, ENT_QUOTES | ENT_XML1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a SimpleXML element node to a pretty-printed XML document.
|
||||||
|
* @param SimpleXmlElement $simplexml_node The SimpleXML node to render.
|
||||||
|
* @return string The pretty-printed XML representation of the provided SimpleXML node.
|
||||||
|
*/
|
||||||
|
function simplexml_asxml_pretty($simplexml_node) {
|
||||||
|
$dom = dom_import_simplexml($simplexml_node);
|
||||||
|
$dom->preserveWhitespace = false;
|
||||||
|
$dom->formatOutput = true;
|
||||||
|
return $dom->saveXML();
|
||||||
|
}
|
||||||
|
|
Reference in a new issue