|  | @@ -0,0 +1,330 @@
 | 
	
		
			
				|  |  | +<?php
 | 
	
		
			
				|  |  | +class GraphicsContext {
 | 
	
		
			
				|  |  | +  protected $palette = array();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * A wrapper for XML elements.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +class Element {
 | 
	
		
			
				|  |  | +  public $name = NULL;
 | 
	
		
			
				|  |  | +  public $attributes = array();
 | 
	
		
			
				|  |  | +  public $value = NULL;
 | 
	
		
			
				|  |  | +  public $new_line; // Add a new line after element
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function __construct($name, $attr = NULL, $value = NULL) {
 | 
	
		
			
				|  |  | +    $this->name = $name;
 | 
	
		
			
				|  |  | +    $this->attributes = $attr;
 | 
	
		
			
				|  |  | +    $this->value = $value;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function __toString() {
 | 
	
		
			
				|  |  | +    $ret = '<'. $this->name;
 | 
	
		
			
				|  |  | +    if (!empty($this->attributes)) {
 | 
	
		
			
				|  |  | +      $ret .= ' ' . implode(' ', $this->attributes);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (empty($this->value)) {
 | 
	
		
			
				|  |  | +      $ret .= ' />';
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    else {
 | 
	
		
			
				|  |  | +      $ret .= '>';
 | 
	
		
			
				|  |  | +      if ($this->value instanceof Element) {
 | 
	
		
			
				|  |  | +        $ret .= (string) $this->value; // force __toString()
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      elseif (is_array($this->value)) {
 | 
	
		
			
				|  |  | +        $ret .= implode('', $this->value);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      else {
 | 
	
		
			
				|  |  | +        $ret .= $this->value;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      $ret .= "</$this->name>";
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return $ret;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class Context {
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * Directory in which the current script is located.
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  | +   * Follow symlinks if applicable, to obtain the actual implementation
 | 
	
		
			
				|  |  | +   * directory, instead of just the main file symlink, in order to find the
 | 
	
		
			
				|  |  | +   * other files.
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  | +   * @var string
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  protected $dirname;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * Requested path: <$PHP_SELF>?q=a/b/c
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  | +   * @var string
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  protected $path = NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * Graphics context
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  | +   * @var GraphicsContext
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  protected $gc = NULL;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function getDirname() {
 | 
	
		
			
				|  |  | +    if (!isset($this->dirname)) {
 | 
	
		
			
				|  |  | +      $this->dirname = dirname(__FILE__);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return $this->dirname;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * Return the requested path.
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  | +   * @param string $path
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  public function getPath() {
 | 
	
		
			
				|  |  | +    if (!isset($this->path)) {
 | 
	
		
			
				|  |  | +      $this->path = empty($_GET['q']) ? '' : $_GET['q'];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return $this->path;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * User information: logged or not ?
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  | +   * @var boolean
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  protected $user = FALSE;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  function __construct() {
 | 
	
		
			
				|  |  | +    $this->getPath();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  function __toString() {
 | 
	
		
			
				|  |  | +    $ret = '<pre>' . print_r($this, TRUE) . '</pre>';
 | 
	
		
			
				|  |  | +    return $ret;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class Page extends Element {
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * @var Context
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  protected $context;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * @var array
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  protected $styles;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * @var array
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  protected $finalized = array();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function getHeader($name) {
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function setHeader($name, $value) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function getHead() {
 | 
	
		
			
				|  |  | +    $this->finalizeHead();
 | 
	
		
			
				|  |  | +    $head = new Element('head', NULL, $this->head);
 | 
	
		
			
				|  |  | +    $ret = (string) $head;
 | 
	
		
			
				|  |  | +    return $ret;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function setHead($item) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function getBody() {
 | 
	
		
			
				|  |  | +    $this->finalizeBody();
 | 
	
		
			
				|  |  | +    $body = new Element('body', NULL, $this->body);
 | 
	
		
			
				|  |  | +    $ret = (string) $body;
 | 
	
		
			
				|  |  | +    return $ret;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function setBody($fragment) {
 | 
	
		
			
				|  |  | +    $this->body[] = $fragment;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function finalizeHead() {
 | 
	
		
			
				|  |  | +    if (isset($this->finalized['head'])) {
 | 
	
		
			
				|  |  | +      throw new Exception('Attempt to finalize already finalized head');
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    $cssLink = new Element('link', array(
 | 
	
		
			
				|  |  | +      'rel' => 'stylesheet',
 | 
	
		
			
				|  |  | +      'type' => 'text/css',
 | 
	
		
			
				|  |  | +      'href' => $this->context->getPath() .'/memcache_ui.css',
 | 
	
		
			
				|  |  | +    ));
 | 
	
		
			
				|  |  | +    $this->setHead($cssLink);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    $this->finalized['head'] = TRUE;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function finalizeBody() {
 | 
	
		
			
				|  |  | +    if (isset($this->finalized['body'])) {
 | 
	
		
			
				|  |  | +      throw new Exception('Attempt to finalize already finalized body');
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    $this->finalized['body'] = TRUE;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public function render() {
 | 
	
		
			
				|  |  | +    $html = new Element('html', NULL, $this->getHead() . $this->getBody());
 | 
	
		
			
				|  |  | +    return (string) $html;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * Page constructor.
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  | +   * @param Context $context
 | 
	
		
			
				|  |  | +   * @param array $item
 | 
	
		
			
				|  |  | +   *   A router info array.
 | 
	
		
			
				|  |  | +   *
 | 
	
		
			
				|  |  | +   * @see Router::getInfo()
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  public function __construct(Context $context, array $item) {
 | 
	
		
			
				|  |  | +    parent::__construct('html');
 | 
	
		
			
				|  |  | +    $this->context = $context;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class Router {
 | 
	
		
			
				|  |  | +  function getInfo() {
 | 
	
		
			
				|  |  | +    $ret = array(
 | 
	
		
			
				|  |  | +      '^server/(\w+)/flush/(\w+)$' => array(
 | 
	
		
			
				|  |  | +        'page class' => 'page_server_flush',
 | 
	
		
			
				|  |  | +        'page arguments' => array('$1', '$2'),
 | 
	
		
			
				|  |  | +        'title callback' => 'title_server',
 | 
	
		
			
				|  |  | +        'title arguments' => 'page arguments',
 | 
	
		
			
				|  |  | +      ),
 | 
	
		
			
				|  |  | +      '^server/(\w+)/flush$' => array(
 | 
	
		
			
				|  |  | +        'page class' => 'page_server_flush',
 | 
	
		
			
				|  |  | +        'page arguments' => array('$1'),
 | 
	
		
			
				|  |  | +        'title callback' => 'title_server',
 | 
	
		
			
				|  |  | +        'title arguments' => 'page arguments',
 | 
	
		
			
				|  |  | +      ),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      '^server/(\w+)/slab/(\d+)$' => array(
 | 
	
		
			
				|  |  | +        'page class' => 'page_slab_view',
 | 
	
		
			
				|  |  | +        'page arguments' => array('$1', '$2'),
 | 
	
		
			
				|  |  | +        'title callback' => 'title_slab',
 | 
	
		
			
				|  |  | +        'title arguments' => 'page arguments',
 | 
	
		
			
				|  |  | +      ),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      '^server/(\w+)/key/(.+)/delete/(\w+)$' => array(
 | 
	
		
			
				|  |  | +        'page class' => 'page_variable_delete_confirm',
 | 
	
		
			
				|  |  | +        'page arguments' => array('$1', '$2', '$3'),
 | 
	
		
			
				|  |  | +        'title callback' => 'title_variable',
 | 
	
		
			
				|  |  | +        'title arguments' => 'page arguments',
 | 
	
		
			
				|  |  | +      ),
 | 
	
		
			
				|  |  | +      '^server/(\w+)/key/(.+)/delete$' => array(
 | 
	
		
			
				|  |  | +        'page class' => 'page_variable_delete_form',
 | 
	
		
			
				|  |  | +        'page arguments' => array('$1', '$2'),
 | 
	
		
			
				|  |  | +        'title callback' => 'title_variable',
 | 
	
		
			
				|  |  | +        'title arguments' => 'page arguments',
 | 
	
		
			
				|  |  | +      ),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      '^server/(\w+)/key/(.+)/dump$' => array(
 | 
	
		
			
				|  |  | +        'page class' => 'page_variable_view_php',
 | 
	
		
			
				|  |  | +        'page arguments' => array('$1', '$2'),
 | 
	
		
			
				|  |  | +        'title callback' => 'title_variable',
 | 
	
		
			
				|  |  | +        'title arguments' => 'page arguments',
 | 
	
		
			
				|  |  | +      ),
 | 
	
		
			
				|  |  | +      '^server/(\w+)/key/(.+)/php$' => array(
 | 
	
		
			
				|  |  | +        'page class' => 'page_variable_view_php',
 | 
	
		
			
				|  |  | +        'page arguments' => array('$1', '$2'),
 | 
	
		
			
				|  |  | +        'title callback' => 'title_variable',
 | 
	
		
			
				|  |  | +        'title arguments' => 'page arguments',
 | 
	
		
			
				|  |  | +      ),
 | 
	
		
			
				|  |  | +      '^server/(\w+)/key/(.+)$' => array(
 | 
	
		
			
				|  |  | +        'page class' => 'page_variable_view_text',
 | 
	
		
			
				|  |  | +        'page arguments' => array('$1', '$2'),
 | 
	
		
			
				|  |  | +        'title callback' => 'title_variable',
 | 
	
		
			
				|  |  | +        'title arguments' => 'page arguments',
 | 
	
		
			
				|  |  | +      ),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      '^slabs$' => array(
 | 
	
		
			
				|  |  | +        'page class' => 'page_slab_overview',
 | 
	
		
			
				|  |  | +        'title' => 'Slabs per server',
 | 
	
		
			
				|  |  | +      ),
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      '^$' => array(
 | 
	
		
			
				|  |  | +        'page class' => 'Page_Main',
 | 
	
		
			
				|  |  | +        'title' => 'Overview',
 | 
	
		
			
				|  |  | +      ),
 | 
	
		
			
				|  |  | +    );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return $ret;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  function getRoute() {
 | 
	
		
			
				|  |  | +    $found = FALSE;
 | 
	
		
			
				|  |  | +    $path = $this->context->getPath();
 | 
	
		
			
				|  |  | +    // echo "<pre>Path: [". $path . "]</p>";
 | 
	
		
			
				|  |  | +    $matches = array();
 | 
	
		
			
				|  |  | +    foreach ($this->getInfo() as $regex => $info) {
 | 
	
		
			
				|  |  | +      $regex = "@$regex@";
 | 
	
		
			
				|  |  | +      $count = preg_match($regex, $path, $matches);
 | 
	
		
			
				|  |  | +      // echo "<pre>$regex: $count";
 | 
	
		
			
				|  |  | +      // if ($count) print_r($matches);
 | 
	
		
			
				|  |  | +      // echo "</pre>";
 | 
	
		
			
				|  |  | +      if ($count) {
 | 
	
		
			
				|  |  | +        $found = TRUE;
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if ($found) {
 | 
	
		
			
				|  |  | +      // echo "Found at $regex<pre>";
 | 
	
		
			
				|  |  | +      // print_r($info);
 | 
	
		
			
				|  |  | +      $regexes = array_fill(0, count($info['page arguments']), $regex);
 | 
	
		
			
				|  |  | +      $paths = array_fill(0, count($info['page arguments']), $path);
 | 
	
		
			
				|  |  | +      $info['page arguments'] = preg_replace($regexes, $info['page arguments'], $paths);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    else {
 | 
	
		
			
				|  |  | +      $info = NULL;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return $info;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  function __construct(Context $context) {
 | 
	
		
			
				|  |  | +    $this->context = $context;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class Page_Main extends Page {
 | 
	
		
			
				|  |  | +  function finalizeBody() {
 | 
	
		
			
				|  |  | +    $hello = new Element('p', NULL, 'Hello world');
 | 
	
		
			
				|  |  | +    $this->setBody($hello);
 | 
	
		
			
				|  |  | +    parent::finalizeBody();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function main() {
 | 
	
		
			
				|  |  | +  $context = new Context();
 | 
	
		
			
				|  |  | +  // echo "<p>Dirname: [". $context->getDirname() . "]</p>";
 | 
	
		
			
				|  |  | +  // echo "<p>Path: [". $context->getPath() . "]</p><pre>";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  $router = new Router($context);
 | 
	
		
			
				|  |  | +  $item = $router->getRoute();
 | 
	
		
			
				|  |  | +  $page = new $item['page class']($context, $item);
 | 
	
		
			
				|  |  | +  // echo '<pre>'; var_dump($page);
 | 
	
		
			
				|  |  | +  echo $page->render();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +try {
 | 
	
		
			
				|  |  | +  main();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +catch (Exception $e) {
 | 
	
		
			
				|  |  | +  echo '<pre>';
 | 
	
		
			
				|  |  | +  echo $e->getMessage() . PHP_EOL;
 | 
	
		
			
				|  |  | +  echo $e->getTraceAsString();
 | 
	
		
			
				|  |  | +  echo "</pre>";
 | 
	
		
			
				|  |  | +}
 |