* @link http://www.steffenvogel.de */ /* * This file is part of sddns * * sddns 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 * any later version. * * sddns 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 sddns. If not, see . */ class JsonOutput extends Output { public function __construct($debug) { parent::__construct('application/json', 'UTF-8', $debug); } protected function getOutput() { $json = array(); foreach ($this->getMessages() as $index => $message) { array_push($json, $message); } // JSONP if (!empty($_REQUEST['callback'])) { return $_REQUEST['callback'] . '(' . json_encode($json) . ');'; } else { return json_encode($json); } } } class XmlOutput extends Output { public function __construct($debug) { parent::__construct('text/xml', 'UTF-8', $debug); } protected function getOutput() { $doc = new DomDocument('1.0', $this->encoding); $doc->formatOutput = true; $xmlSddns = $doc->createElement('sddns'); $doc->appendChild($xmlSddns); foreach ($this->getMessages() as $index => $message) { $xmlMessage = $doc->createElement('message'); $xmlMessage->setAttribute('type', $message['type']); if ($message['type'] == 'debug') { $xmlMessage->setAttribute('level', $message['level']); } $xmlMessage->appendChild($doc->createElement('description', $message['description'])); foreach ($message['data'] as $object) { if (method_exists($object, 'toXml')) { $xmlMessage->appendChild($object->toXml($doc)); } else { $xmlMessage->appendChild($doc->createElement(gettype($object), $object)); } } $xmlSddns->appendChild($xmlMessage); } return $doc->saveXML(); } } // needs JPGraph >= 3.0.7! class GraphOutput extends Output { private $graph; public function __construct($debug) { parent::__construct('text/html', 'UTF-8', $debug); global $site; require_once 'jpgraph/jpgraph.php'; } public function getGraph($width, $height, $type = 'line') { switch ($type) { case 'line': $this->graph = new Graph($width, $height); break; case 'pie': $this->graph = new PieGraph($width, $height); break; } return $this->graph; } public function showGraph() { if (isset($this->graph)) $this->graph->Stroke(); } protected function getOutput() { // TODO if (count($this->getMessages()) > 0) { echo '
';
			print_r($this->getMessages());
			echo '
'; } } } class GifOutput extends Output { public function __construct() { parent::__construct('image/gif'); } protected function getOutput() { $im = imagecreate(1, 1); $red = imagecolorallocate($im, 255, 0, 0); $green = imagecolorallocate($im, 0, 255, 0); imagefill($im, 0, 0, (count($this->getMessages(false, array('error', 'exception'))) > 0) ? $red : $green); imagegif($im); imagedestroy($im); } } class PlainLineOutput extends Output { public function __construct($debug, $fields = array('index', 'time', 'type', 'description', 'data'), $delimiter = "\t", $lineDelimiter = "\n", $escape = true) { parent::__construct('text/plain', 'UTF-8', $debug); $this->fields = $fields; $this->delimiter = $delimiter; $this->lineDelimiter = $lineDelimiter; } protected function getOutput() { global $argv; $fd = fopen('php://memory', 'w+'); foreach($this->getMessages() as $index => $message) { if (isset($argv)) { $fd = (in_array($message['type'], array('error', 'exception', 'warning'))) ? STDERR : STDOUT; } foreach ($this->fields as $fieldIndex => $field) { switch ($field) { case 'type': fwrite($fd, '[' . $message['type'] . ']'); break; case 'index': fwrite($fd, $index); break; case 'time': fwrite($fd, date('Y-m-d H:i:s', $message['time'])); break; case 'description': fwrite($fd, $message['description']); break; case 'data': fwrite($fd, implode(', ', $message['data'])); break; default: fwrite($fd, $message[$field]); } fwrite($fd, ($fieldIndex == count($this->fields) - 1) ? $this->lineDelimiter : $this->delimiter); } } if (isset($argv)) { exit( (count($this->getMessages(false, array('error', 'exception')))) ? 1 : 0 ); } else { rewind($fd); $str = stream_get_contents($fd); fclose($fd); return $str; } } } class HtmlOutput extends Output { public function __construct($debug) { parent::__construct('text/html', 'UTF-8', $debug); ob_start(); } protected function getOutput() { global $site; $columnCount = 0; $messages = $this->getMessages(); $html = ob_get_clean(); foreach ($messages as $message) { if (count($message['data']) > $columnCount) $columnCount = count($message['data']); } $str = ' /dev/nulll - Simple Dynamic Domain Name Service
'; $str .= '
' . $html . '
'; if (count($messages)) { $str .= ''; foreach ($messages as $index => $message) { $str .= ''; for($i = 0; $i < $columnCount; $i++) { $str .= ''; } $str .= ''; } $str .= '
typeindextimedescriptiondata
' . $message['type'] . ' #' . $index . ' ' . date('Y-m-d H:i', $message['time']) . ' ' . $message['description'] . ''; if (isset($message['data'][$i])) { $data = $message['data'][$i]; if (is_object($data) && method_exists($data, 'toHtml')) { $str .= $data->toHtml(); } else { $str .= $data; } } $str .= '
'; } $str .= '
'; return $str; } } abstract class Output { protected $messages = array(); public $debug = 0; public $format; protected $contentType; protected $encoding; function __construct($contentType = 'text/plain', $encoding = 'UTF-8', $debug = 0) { $this->contentType = $contentType; $this->encoding = $encoding; $this->debug = $debug; header('Content-type: ' . $this->contentType . (($this->encoding != null) ? '; charset=' . $this->encoding : '')); } function add($description, $type = 'notice') { $message['time'] = time(); $message['description'] = $description; $message['type'] = $type; $message['data'] = array(); $argv = func_get_args(); $argc = count($argv); if ($type == 'debug') { $message['level'] = $argv[2]; } for ($i = ($type == 'debug') ? 3 : 2; $i < $argc; $i++) { if (empty($argv[$i])) continue; if (!is_array($argv[$i])) { $message['data'][] = $argv[$i]; } else { $message['data'] = array_merge($message['data'], array_values($argv[$i])); } } array_push($this->messages, $message); } protected function getMessages($exclude = true, $args = null) { $types = array('notice', 'success', 'error', 'exception', 'warning', 'data', 'debug'); if ($args == null) $args = array(); $types = ($exclude) ? array_diff($types, $args) : $args; $messages = array(); foreach ($this->messages as $message) { if (in_array($message['type'], $types) && ($message['type'] != 'debug' || $message['level'] <= $this->debug)) { $messages[] = $message; } } return $messages; } static function getInstance($format = null, $debug = 0) { switch (strtolower($format)) { case 'xml': return new XmlOutput($debug); break; case 'txt': return new PlainLineOutput($debug, array('type', 'description', 'data'), "\t", "\n"); break; case 'csv': return new PlainLineOutput($debug, array('time', 'type', 'description', 'data'), ";", "\n"); break; case 'png': return new GraphOutput($debug); break; case 'gif': return new GifOutput(); break; case 'json': return new JsonOutput($debug); case 'html': case 'php': default: return new HtmlOutput($debug); break; } } static function start($forced = null) { global $argc; global $site; if (isset($forced)) $format = $forced; elseif (isset($argc)) $format = 'txt'; elseif (empty($_REQUEST['format']) || @$_REQUEST['format'] == 'php') $format = 'html'; else $format = $_REQUEST['format']; $output = self::getInstance($format, $site['debug']); // errorhandling set_exception_handler(array($output, 'exception_handler')); set_error_handler(array($output, 'error_handler'), E_ALL); // shutdown register_shutdown_function(array($output, 'send')); // debugging $parameters = array(); foreach ($_REQUEST as $parName => $parValue) { $parameters[] = $parName . ' => ' . $parValue; } $output->add('debug level', 'debug', 2, $output->debug); $output->add('parameters', 'debug', 2, $parameters); return $output; } function exception_handler($exception) { if (is_subclass_of($exception, 'CustomException')) { $this->add($exception->getMessage(), 'error', $exception->getData()); } else { $this->debug = 7; // increase verbosity in case of an exception $this->add(get_class($exception), 'exception', (array) $exception); } switch (get_class($exception)) { case 'CustomException': http_response_code(500); break; case 'UserException': http_response_code(400); break; case 'ValidationException': http_response_code(400); break; case 'AuthentificationException': http_response_code(403); break; default: $code = 500; break; } exit(1); } function error_handler($errno, $errstr, $errfile, $errline) { if (($errno & error_reporting()) != 0) { switch ($errno) { case E_USER_WARNING: case E_WARNING: $type = 'warning'; $str = $type; break; case E_USER_NOTICE: case E_NOTICE: $type = 'warning'; $str = 'notice'; break; case E_USER_ERROR: case E_ERROR: default: $type = 'error'; $str = $type; break; } $this->add($str, $type, $errstr . ' in ' . $errfile . ':' . $errline); } } abstract protected function getOutput(); function send() { echo $this->getOutput(); } }