initialize
authorMichael Wallner <mike@php.net>
Wed, 30 Oct 2013 09:02:36 +0000 (10:02 +0100)
committerMichael Wallner <mike@php.net>
Wed, 30 Oct 2013 09:02:36 +0000 (10:02 +0100)
38 files changed:
http/Env.md [new file with mode: 0644]
http/Env/Request.md [new file with mode: 0644]
http/Env/Request/__construct.md [new file with mode: 0644]
http/Env/getRequestBody.md [new file with mode: 0644]
http/Env/getRequestHeader.md [new file with mode: 0644]
http/Env/getResponseCode.md [new file with mode: 0644]
http/Env/getResponseHeader.md [new file with mode: 0644]
http/Env/getResponseStatusForAllCodes.md [new file with mode: 0644]
http/Env/getResponseStatusForCode.md [new file with mode: 0644]
http/Env/negotiate.md [new file with mode: 0644]
http/Env/negotiateCharset.md [new file with mode: 0644]
http/Env/negotiateContentType.md [new file with mode: 0644]
http/Env/negotiateEncoding.md [new file with mode: 0644]
http/Env/negotiateLanguage.md [new file with mode: 0644]
http/Env/setResoponseCode.md [new file with mode: 0644]
http/Env/setResponseHeader.md [new file with mode: 0644]
http/Header.md [new file with mode: 0644]
http/Header/__construct.md [new file with mode: 0644]
http/Header/__toString.md [new file with mode: 0644]
http/Header/getParams.md [new file with mode: 0644]
http/Header/match.md [new file with mode: 0644]
http/Header/negotiate.md [new file with mode: 0644]
http/Header/parse.md [new file with mode: 0644]
http/Header/serialize.md [new file with mode: 0644]
http/Header/toString.md [new file with mode: 0644]
http/Header/unserialize.md [new file with mode: 0644]
http/Params.md [new file with mode: 0644]
http/Params/__construct.md [new file with mode: 0644]
http/Params/__toString.md [new file with mode: 0644]
http/Params/offsetExists.md [new file with mode: 0644]
http/Params/offsetGet.md [new file with mode: 0644]
http/Params/offsetSet.md [new file with mode: 0644]
http/Params/offsetUnset.md [new file with mode: 0644]
http/Params/toArray.md [new file with mode: 0644]
http/Params/toString.md [new file with mode: 0644]
index.css [new file with mode: 0644]
index.js [new file with mode: 0644]
index.php [new file with mode: 0644]

diff --git a/http/Env.md b/http/Env.md
new file mode 100644 (file)
index 0000000..d75dbf2
--- /dev/null
@@ -0,0 +1,11 @@
+# class http\Env extends http\Object
+
+The http\Env class provides static methods to manipulate and inspect the server's current request's HTTP environment.
+
+## Request startup
+
+The http\Env module overrides PHP's builtin POST data parser to be run also if
+the request method is not POST. Additionally it will handle 
+```application/json``` payloads if ```ext/json``` is available. Successfully 
+parsed JSON will be put right into the $_POST array.
+
diff --git a/http/Env/Request.md b/http/Env/Request.md
new file mode 100644 (file)
index 0000000..5c4b32f
--- /dev/null
@@ -0,0 +1,14 @@
+# class http\Env\Request extends http\Message
+
+## Constants:
+
+> None.
+
+## Properties:
+
+* ```protected $query = NULL```  
+  The request's query parameters. ($_GET)
+* ```protected $form = NULL```  
+  The request's form parameters. ($_POST)
+* ```protected $files = NULL```  
+  The request's form uploads. ($_FILES)
diff --git a/http/Env/Request/__construct.md b/http/Env/Request/__construct.md
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/http/Env/getRequestBody.md b/http/Env/getRequestBody.md
new file mode 100644 (file)
index 0000000..512128d
--- /dev/null
@@ -0,0 +1,16 @@
+# static http\Message\Body http\Env::getRequestBody([string $body_class_name])
+
+Retreive the current HTTP request's body.
+
+## Parameters:
+
+* Optional ```string $body_class_name```  
+  A user class extending http\Body.
+
+## Returns:
+
+* ```http\Message\Body``` instance representing the request body
+
+## Throws:
+
+* http\Exception
diff --git a/http/Env/getRequestHeader.md b/http/Env/getRequestHeader.md
new file mode 100644 (file)
index 0000000..b33718b
--- /dev/null
@@ -0,0 +1,14 @@
+# static mixed http\Env::getRequestHeader([string $header_name])
+
+Retrieve one or all headers of the current HTTP request.
+
+## Parameters:
+
+* Optional ```string $header_name```  
+  The key of a header to retrieve.
+  
+## Returns:  
+
+* ```NULL```, if $header_name was not found
+* ```string```, the compound header when $header_name was found
+* ```array``` of all headers if $header_name was not specified
diff --git a/http/Env/getResponseCode.md b/http/Env/getResponseCode.md
new file mode 100644 (file)
index 0000000..11feca8
--- /dev/null
@@ -0,0 +1,12 @@
+# static int http\Env::getResponseCode()
+
+Get the HTTP response code to send.
+
+## Parameters:
+
+> None.
+
+## Returns:
+
+* ```int```, the HTTP response code.
+
diff --git a/http/Env/getResponseHeader.md b/http/Env/getResponseHeader.md
new file mode 100644 (file)
index 0000000..c30a4d7
--- /dev/null
@@ -0,0 +1,14 @@
+# static mixed http\Env::getResponseHeader([string $header_name])
+
+Get one or all HTTP response headers to be sent.
+
+## Parameters:
+
+* Optional ```string $header_name```  
+  The name of the response header to retrieve.
+  
+## Returns:
+
+* ```string```, the compound value of the response header to send
+* ```NULL```, if the header was not found
+* ```array```, of all response headers, if $header_name was not specified
diff --git a/http/Env/getResponseStatusForAllCodes.md b/http/Env/getResponseStatusForAllCodes.md
new file mode 100644 (file)
index 0000000..2e37783
--- /dev/null
@@ -0,0 +1,15 @@
+# static array http\Env::getResponseStatusForAllCodes()
+
+Retrieve a list of all known HTTP response status.
+
+## Parameters:
+
+> None.
+
+## Returns:
+
+* ```array``` mapping of the form \[  
+  ...  
+  ```int $code``` => ```string $status```  
+  ...  
+  \]
diff --git a/http/Env/getResponseStatusForCode.md b/http/Env/getResponseStatusForCode.md
new file mode 100644 (file)
index 0000000..d2bfa85
--- /dev/null
@@ -0,0 +1,14 @@
+# static string http\Env::getResponseStatusForCode(int $code)
+
+Retrieve the string representation of specified HTTP response code.
+
+## Parameters:
+
+* ```int $code```  
+  The HTTP response code to get the string representation for.
+  
+## Returns:
+
+* ```string```, the HTTP response status message
+* empty ```string```, if no message for this code was found
+
diff --git a/http/Env/negotiate.md b/http/Env/negotiate.md
new file mode 100644 (file)
index 0000000..0230bc6
--- /dev/null
@@ -0,0 +1,21 @@
+# static string http\Env::negotiate(string $params, array $supported[, string $prim_typ_sep[, array &$result]])
+
+Generic negotiator. For specific client negotiation see http\Env::negotiateContentType() and related methods.
+
+> ***NOTE:*** The first elemement of $supported serves as a default if no operand matches.
+
+## Params:
+
+* ```string $params```  
+  HTTP header parameter's value to negotiate.
+* ```array $supported```  
+  List of supported negotiation operands.
+* Optional ```string $prim_typ_sep```  
+  A "primary type separator", i.e. that would be a hyphen for content language negotiation (en-US, de-DE, etc.).
+* Optional reference ```array &$result```  
+  Out parameter recording negotiation results.
+  
+## Returns:
+
+* ```NULL```, if negotiation fails.
+* ```string```, the closest match negotiated, or the default (first entry of $supported).
diff --git a/http/Env/negotiateCharset.md b/http/Env/negotiateCharset.md
new file mode 100644 (file)
index 0000000..20cc01b
--- /dev/null
@@ -0,0 +1,17 @@
+# static string http\Env::negotiateCharset(array $supported[, array &$result)
+
+Negotiate the client's preferred character set.
+
+> ***NOTE:*** The first elemement of $supported character sets serves as a default if no character set matches.
+
+## Params:
+
+* ```array $supported```  
+  List of supported content character sets.
+* Optional reference ```array &$result```  
+  Out parameter recording negotiation results.
+  
+## Returns:
+
+* ```NULL```, if negotiation fails.
+* ```string```, the negotiated character set.
diff --git a/http/Env/negotiateContentType.md b/http/Env/negotiateContentType.md
new file mode 100644 (file)
index 0000000..510e33f
--- /dev/null
@@ -0,0 +1,56 @@
+# static string http\Env::negotiateContentType(array $supported[, array &$result)
+
+Negotiate the client's preferred MIME content type.
+
+> ***NOTE:*** The first elemement of $supported content types serves as a default if no content-type matches.
+
+## Params:
+
+* ```array $supported```  
+  List of supported MIME content types.
+* Optional reference ```array &$result```  
+  Out parameter recording negotiation results.
+  
+## Returns:
+
+* ```NULL```, if negotiation fails.
+* ```string```, the negotiated content type.
+
+## Example:
+
+A client indicates his accepted MIME content types by sending an ```Accept```
+header. The static ```http\Env``` class provides a facility to negotiate the
+client's preferred content type:
+
+    <?php
+    $_SERVER["HTTP_ACCEPT"] = implode(",", array(
+        "text/html",
+        "text/plain",
+        "text/*;q=0.9",
+        "*/*;q=0.1",
+        "application/xml;q=0"
+    ));
+    $supported = array(
+        "text/html", 
+        "text/plain",
+        "application/json", 
+        "application/xml"
+    );
+    $preferred = http\Env::negotiateContentType($supported, $ranking);
+    var_dump($preferred, $ranking);
+    ?>
+
+Running this script should give the following output:
+
+    string(9) "text/html"
+    array(3) {
+        'text/html' =>
+        float(0.99)
+        'text/plain' =>
+        float(0.98)
+        'application/json' =>
+        float(0.1)
+    }
+
+
+
diff --git a/http/Env/negotiateEncoding.md b/http/Env/negotiateEncoding.md
new file mode 100644 (file)
index 0000000..4c070b7
--- /dev/null
@@ -0,0 +1,17 @@
+# static string http\Env::negotiateEncoding(array $supported[, array &$result)
+
+Negotiate the client's preferred encoding.
+
+> ***NOTE:*** The first elemement of $supported encodings serves as a default if no encoding matches.
+
+## Params:
+
+* ```array $supported```  
+  List of supported content encodings.
+* Optional reference ```array &$result```  
+  Out parameter recording negotiation results.
+  
+## Returns:
+
+* ```NULL```, if negotiation fails.
+* ```string```, the negotiated encoding.
diff --git a/http/Env/negotiateLanguage.md b/http/Env/negotiateLanguage.md
new file mode 100644 (file)
index 0000000..3baf48a
--- /dev/null
@@ -0,0 +1,17 @@
+# static string http\Env::negotiateLanguage(array $supported[, array &$result)
+
+Negotiate the client's preferred language.
+
+> ***NOTE:*** The first elemement of $supported languages serves as a default if no language matches.
+
+## Params:
+
+* ```array $supported```  
+  List of supported content languages.
+* Optional reference ```array &$result```  
+  Out parameter recording negotiation results.
+  
+## Returns:
+
+* ```NULL```, if negotiation fails.
+* ```string```, the negotiated language.
diff --git a/http/Env/setResoponseCode.md b/http/Env/setResoponseCode.md
new file mode 100644 (file)
index 0000000..376a13d
--- /dev/null
@@ -0,0 +1,12 @@
+# static bool http\Env::setResponseCode(int $code)
+
+Set the HTTP response code to send.
+
+## Params:
+
+* ```int $code```  
+  The HTTP response status code.
+  
+## Returns:
+
+* ```bool``` Success.
diff --git a/http/Env/setResponseHeader.md b/http/Env/setResponseHeader.md
new file mode 100644 (file)
index 0000000..69adfa3
--- /dev/null
@@ -0,0 +1,18 @@
+# static bool http\Env::setResponseHeader(string $header_name, [mixed $header_value = NULL[, int $response_code = 0[, bool $replace = true]]]
+
+Set a response header, either replacing a prior set header, or appending the new header value, depending on $replace.
+
+If no $header_value is specified, or $header_value is ```NULL```, then a previously set header with the same key will be deleted from the list.
+
+If $response_code is not ```0```, the response status code is updated accordingly.
+
+## Parameters:
+
+* ```string $header_name```, the name of the response header.
+* Optional ```mixed $header_value```, the header value.
+* Optional ```int $response_code```, any HTTP response status code to set.
+* Optional ```bool $replace```, whether to replace a previously set response header with the same name.
+
+## Returns:
+
+* ```bool``` Success.
diff --git a/http/Header.md b/http/Header.md
new file mode 100644 (file)
index 0000000..101b0dc
--- /dev/null
@@ -0,0 +1,23 @@
+# class http\Header extends http\Object implements Serializable
+
+The http\Header class provides methods to manipulate, match, negotiate and serialize HTTP headers.
+
+## Constants:
+
+* ```MATCH_LOOSE```  
+  None of the following match constraints applies.
+* ```MATCH_CASE```  
+  Perform case sensitive matching.
+* ```MATCH_WORD```  
+  Match only on word boundaries (according by CTYPE alpha-numeric).
+* ```MATCH_FULL```  
+  Match the complete string.
+* ```MATCH_STRICT```  
+  Case sensitively match the full string (same as ```MATCH_CASE|MATCH_FULL```).
+
+## Properties:
+
+* ```public $name = NULL```  
+  The name of the HTTP header.
+* ```public $value = NULL```  
+  The value of the HTTP header.
diff --git a/http/Header/__construct.md b/http/Header/__construct.md
new file mode 100644 (file)
index 0000000..c477ab3
--- /dev/null
@@ -0,0 +1,14 @@
+# void http\Header::__construct([string $name[, mixed $value]])
+
+Create an http\Header instance for use of simple matching or negotiation. If the value of the header is an array it may be compounded to a single comma separated string.
+
+## Params:
+
+* Optional ```string $name```  
+  The HTTP header name.
+* Optional ```mixed $value```  
+  The value of the header.
+
+# Throws: 
+
+* http\Exception
diff --git a/http/Header/__toString.md b/http/Header/__toString.md
new file mode 100644 (file)
index 0000000..602768a
--- /dev/null
@@ -0,0 +1,11 @@
+# string http\Header::__toString()
+
+String cast handler. Alias of http\Header::serialize().
+
+## Params:
+
+> None.
+
+## Returns:
+
+* ```string```, the serialized form of the HTTP header (i.e. "Name: value").
diff --git a/http/Header/getParams.md b/http/Header/getParams.md
new file mode 100644 (file)
index 0000000..d3645c2
--- /dev/null
@@ -0,0 +1,18 @@
+# http\Params http\Header::getParams([mixed $ps = ","[, mixed $as = ";"[, mixed $vs = "="[, int $flags = http\Params::PARSE_DEFAULT]]]])
+
+Create a parameter list out of the HTTP header value.
+
+## Params:
+
+* Optional ```mixed $ps```  
+  The parameter separator(s).
+* Optional ```mixed $as```  
+  The argument separator(s).
+* Optional ```mixed```  
+  The value separator(s).
+* Optional ```int $flags```  
+  The modus operandi. See http\Params constants.
+
+## Returns:
+
+* ```http\Params``` instance
diff --git a/http/Header/match.md b/http/Header/match.md
new file mode 100644 (file)
index 0000000..7635cd2
--- /dev/null
@@ -0,0 +1,14 @@
+# bool http\Header::match(string $value[, int $flags = http\Header::MATCH_LOOSE])
+
+Match the HTTP header's value against provided $value according to $flags.
+
+## Params:
+
+* ```string $value```  
+  The comparison value.
+* Optional ```int $flags```  
+  The modus operandi. See http\Header constants.
+  
+## Returns:
+
+* ```bool```, whether $value matches the header value according to $flags.
diff --git a/http/Header/negotiate.md b/http/Header/negotiate.md
new file mode 100644 (file)
index 0000000..af0547f
--- /dev/null
@@ -0,0 +1,21 @@
+# string http\Header::negotiate(array $supported[, array &$result])
+
+Negotiate the header's value against a list of supported values in $supported. 
+Negotiation operation is adopted according to the header name, i.e. if the 
+header being negotiated is ```Accept```, then a slash is used as primary type 
+separator, and if the header is ```Accept-Language``` respectively, a hyphen is 
+used instead.
+
+> ***NOTE:*** The first elemement of $supported serves as a default if no operand matches.
+
+## Params:
+
+* ```array $supported```  
+  The list of supported values to negotiate.
+* Optional reference ```array &$result```
+  Out parameter recording the negotiation results.
+  
+## Returns:
+
+* ```NULL```, if negotiation fails.
+* ```string```, the closest match negotiated, or the default (first entry of $supported).
diff --git a/http/Header/parse.md b/http/Header/parse.md
new file mode 100644 (file)
index 0000000..c1965c1
--- /dev/null
@@ -0,0 +1,14 @@
+# static array http\Header::parse(string $header[, string $header_class = null])
+
+Parse HTTP headers.
+
+## Params:
+
+* ```string $header```  
+  The complete string of headers.
+* Optional ```string $header_class```  
+  A class extending http\Header.
+  
+## Returns:
+
+* ```array``` of parsed headers, where the elements are instances of $header_class if specified.
diff --git a/http/Header/serialize.md b/http/Header/serialize.md
new file mode 100644 (file)
index 0000000..2afe46e
--- /dev/null
@@ -0,0 +1,11 @@
+# string http\Header::serialize()
+
+Implements Serializable.
+
+## Params:
+
+> None.
+
+## Returns:
+
+* ```string```, serialized representation of HTTP header (i.e. "Name: value")
diff --git a/http/Header/toString.md b/http/Header/toString.md
new file mode 100644 (file)
index 0000000..2eec780
--- /dev/null
@@ -0,0 +1,11 @@
+# string http\Header::toString()
+
+Convenience method. Alias of http\Header::serialize().
+
+## Params:
+
+> None.
+
+## Returns:
+
+* ```string```, the serialized form of the HTTP header (i.e. "Name: value").
diff --git a/http/Header/unserialize.md b/http/Header/unserialize.md
new file mode 100644 (file)
index 0000000..2ccd6c4
--- /dev/null
@@ -0,0 +1,9 @@
+# void http\Header::unserialize(string $serialized)
+
+Implements Serializable.
+
+## Params:
+
+* ```string $serialized```  
+  The serialized HTTP header (i.e. "Name: value")
+
diff --git a/http/Params.md b/http/Params.md
new file mode 100644 (file)
index 0000000..f479223
--- /dev/null
@@ -0,0 +1,37 @@
+# class http\Params extends http\Object implements ArrayAccess
+
+Parse, interpret and compose HTTP (header) parameters.
+
+## Constants:
+
+* ```DEF_PARAM_SEP```  
+  The default parameter separator (",").
+* ```DEF_ARG_SEP```  
+  The default argument separator (";").
+* ```DEF_VAL_SEP```  
+  The default value separator ("=").
+* ```COOKIE_PARAM_SEP```  
+  TBD
+* ```PARSE_RAW```  
+  Do not interpret the parsed parameters.
+* ```PARSE_DEFAULT```  
+  Interpret input as default formatted parameters.
+* ```PARSE_URLENCODED```  
+  Urldecode single units of parameters, arguments and values.
+* ```PARSE_DIMENSION```  
+  Parse sub dimensions indicated by square brackets.
+* ```PARSE_QUERY```  
+  Parse URL query string (same as http\Params::PARSE_URLENCODED|http\Params::PARSE_DIMENSION).
+
+## Properties:
+
+* ```public $params = NULL```  
+  The (parsed) parameters.
+* ```public $param_sep = http\Header::DEF_PARAM_SEP```  
+  The parameter separator(s).
+* ```public $arg_sep = http\Header::DEF_ARG_SEP```  
+  The argument separator(s).
+* ```public $val_sep = http\Header::DEF_VAL_SEP```  
+  The value separator(s).
+* ```public $flags = http\Params::PARSE_DEFAULT```  
+  The modus operandi of the parser. See http\Params::PARSE_* constants.
diff --git a/http/Params/__construct.md b/http/Params/__construct.md
new file mode 100644 (file)
index 0000000..76034a9
--- /dev/null
@@ -0,0 +1,21 @@
+# void http\Params::__construct([mixed $params = NULL[, mixed $ps = http\Params::DEF_PARAM_SEP[, mixed $as = http\Params::DEF_ARG_SEP[, mixed $vs = http\Params::DEF_VAL_SEP[, int $flags = http\Params::PARSE_DEFAULT]]]]])
+
+Instantiate a new HTTP (header) parameter set.
+
+## Params:
+
+* Optional ```mixed $params```  
+  Pre-parsed parameters or a string to be parsed.
+* Optional ```mixed $ps```  
+  The parameter separator(s).
+* Optional ```mixed $as```  
+  The argument separator(s).
+* Optional ```mixed $vs```  
+  The value separator(s).
+* Optional ```int $flags```  
+  The modus operandi. See http\Params::PARSE_* constants.
+
+## Throws:
+
+* http\Exception
+
diff --git a/http/Params/__toString.md b/http/Params/__toString.md
new file mode 100644 (file)
index 0000000..c1bd91c
--- /dev/null
@@ -0,0 +1,12 @@
+# string http\Params::__toString()
+
+String cast handler. Alias of http\Params::toString().
+Returns a stringified version of the parameters.
+
+## Params:
+
+> None.
+
+## Returns:
+
+* ```string``` version of the parameters.
diff --git a/http/Params/offsetExists.md b/http/Params/offsetExists.md
new file mode 100644 (file)
index 0000000..b3d7b29
--- /dev/null
@@ -0,0 +1,12 @@
+# bool http\Params::offsetExists(string $name)
+
+Implements ArrayAccess.
+
+## Params:
+
+* ```string $name```  
+  The offset to look after.
+
+## Returns:
+
+* ```bool``` Existence.
diff --git a/http/Params/offsetGet.md b/http/Params/offsetGet.md
new file mode 100644 (file)
index 0000000..cc96a9a
--- /dev/null
@@ -0,0 +1,12 @@
+# mixed http\Params::offsetGet(string $name)
+
+Implements ArrayAccess.
+
+## Params:
+
+* ```string $name```  
+  The offset to retrieve.
+  
+## Returns:
+
+* ```mixed```, contents at offset.
diff --git a/http/Params/offsetSet.md b/http/Params/offsetSet.md
new file mode 100644 (file)
index 0000000..4a24d41
--- /dev/null
@@ -0,0 +1,11 @@
+# void http\Params::offsetSet(string $name, mixed $value)
+
+Implements ArrayAccess.
+
+## Params:
+
+* ```string $name```  
+  The offset to modify.
+* ```mixed $value```  
+  The value to set.
+  
diff --git a/http/Params/offsetUnset.md b/http/Params/offsetUnset.md
new file mode 100644 (file)
index 0000000..4c5af78
--- /dev/null
@@ -0,0 +1,9 @@
+# void http\Params::offsetUnset(string $name)
+
+Implements ArrayAccess.
+
+## Params:
+
+* ```string $name```  
+  The offset to delete.
+  
diff --git a/http/Params/toArray.md b/http/Params/toArray.md
new file mode 100644 (file)
index 0000000..e7ca841
--- /dev/null
@@ -0,0 +1,11 @@
+# array http\Params::toArray()
+
+Convenience method that simply returns http\Params::$params.
+
+## Params:
+
+> None.
+
+## Returns:
+
+* ```array``` of paramters.
diff --git a/http/Params/toString.md b/http/Params/toString.md
new file mode 100644 (file)
index 0000000..34400be
--- /dev/null
@@ -0,0 +1,11 @@
+# string http\Params::toString()
+
+Returns a stringified version of the parameters.
+
+## Params:
+
+> None.
+
+## Returns:
+
+* ```string``` version of the parameters.
diff --git a/index.css b/index.css
new file mode 100644 (file)
index 0000000..b61f515
--- /dev/null
+++ b/index.css
@@ -0,0 +1,73 @@
+* { 
+       font-size: 99.9%;
+}
+
+body {
+       font-family: monospace;
+       font-size: 1.5em;
+       margin: 0;
+       padding: 4em 0 0 0;
+}
+
+body>* {
+       margin-left: 2em;
+       margin-right: 2em;
+}
+
+code { 
+       display: inline-block;
+       border-radius: 2px;
+       padding: 0px 2px 2px 2px;
+       background: #e0e0e0;
+       color: #606060;
+       box-shadow: 0 0 1px #999;
+}
+
+h1 {
+       position: fixed;
+       top: 0;
+       left: 0;
+       width: 100%;
+       margin: 0;
+       padding: 1em;
+}
+p {
+       color: #3f3f3f;
+       margin: 1em;
+}
+
+blockquote {
+       padding: 1em;
+       border-radius: 4px;
+       max-width: 1000px;
+}
+blockquote, blockquote p {
+       color: #f0f0f0;
+}
+ul {
+       margin-bottom: 2em;
+}
+li {
+       margin-bottom: .5em;
+}
+a {
+       color: #2f4f4f;
+}
+
+.var {
+       color: #800000;
+}
+
+.invert, h1, blockquote, blockquote p {
+       background: #030303;
+       color: #f0f0f0;
+}
+
+.invert .var, h1 .var, blockquote .var {
+       color: #f4a460;
+}
+
+.invert a, h1 a, blockquote a {
+       color: #b0e0e6;
+}
+
diff --git a/index.js b/index.js
new file mode 100644 (file)
index 0000000..6334108
--- /dev/null
+++ b/index.js
@@ -0,0 +1,101 @@
+function type(s) {
+       
+       // nothing
+       if (!s.match(/[a-zA-Z]/)) {
+               return;
+       }
+       
+       switch (s) {
+       // types
+       case "void":
+       case "bool":
+       case "int":
+       case "float":
+       case "string":
+       case "array":
+       case "object":
+       case "callable":
+               return "<code>";
+               
+       // keywords
+       case "class":
+       case "interface":
+       case "namespace":
+       case "extends":
+       case "implements":
+       case "public":
+       case "protected":
+       case "private":
+       case "static":
+       case "final":
+       case "abstract":
+       // phrases
+       case "Optional":
+       case "optional":
+               return "<em>";
+       }
+       
+       var is_namespace, is_method;
+       
+       if ((is_method = (s.indexOf("::") !== -1)) || (is_namespace = (s.indexOf("\\") !== -1))) {
+               return "<a href=\"/" + s.replace(/::|\\/g, "/") + (is_method ? ".md":"") + "\">";
+       }
+       
+       switch (s.toLowerCase()) {
+       // variables
+       default:
+               if (s.substring(0,1) !== "$") {
+                       break;
+               }
+       // special constants
+       case "null":
+       case "true":
+       case "false":
+               return "<span class=\"var\">";
+       }
+       
+       // constants
+       if (s.toUpperCase() === s) {
+               return "<code>";
+       }
+}
+function node(s) {
+       //console.log("node", s);
+       
+       var t;
+       
+       if ((t = type(s))) {
+               return $(t).text(s);
+       }
+       return document.createTextNode(s);
+}
+function wrap(n) {
+       var $n = $(n)
+       var a = [];
+
+       $n.text().split(/([^a-zA-Z_\\\$:]+)/).forEach(function(v) {
+               a.push(node(v));
+       });
+       $n.replaceWith(a);
+}
+function walk(i, e) {
+       //console.log("walk", i, e);
+
+       e && $.each(e.childNodes, function(i, n) {
+               //console.log(n.nodeName);
+               switch (n.nodeName) {
+               case "A":
+                       break;
+               case "#text":
+                       wrap(n);
+                       break;
+               default:
+                       walk(n);
+               }
+       });
+}
+$(document).ready(function() {
+       //console.log("ready");
+
+       $("h1,h2,h3,h4,h5,h6,p,li,code").each(walk);
+});
diff --git a/index.php b/index.php
new file mode 100644 (file)
index 0000000..160fed5
--- /dev/null
+++ b/index.php
@@ -0,0 +1,166 @@
+<?php
+
+error_reporting(E_ALL &~ E_DEPRECATED);
+
+define("OUTPUT", fopen("php://memory", "w+"));
+
+function cut(array $lines, array $specs) {
+       $delim = "[[:space:]]+";
+       $bytes = [];
+       $fields= [];
+       
+       foreach ($specs as $spec => $value) {
+               switch ($spec) {
+               case "d":
+                       $delim = $value;
+                       break;
+               case "b":
+                       $bytes = $value;
+                       break;
+               case "f":
+                       $fields = $value;
+                       break;
+               }
+       }
+       
+       $result = [];
+       if ($bytes) {
+               $func = "substr";
+       } else {
+               $func = function($a, $o = 0, $l = 0) {
+                       return join(" ", array_slice($a, $o, $l ? $l+1 : count($a)-$o));
+               };
+       }
+       foreach ($lines as $line) {
+               if ($bytes) {
+                       $spec = $bytes;
+               } else {
+                       $line = split($delim, $line);
+                       $spec = $fields;
+               }
+               
+               if ($spec[0] == "-") {
+                       $result[] = $func($line, 0, $spec[1]);
+               } elseif ($spec[1] == "-") {
+                       if (empty($spec[2])) {
+                               $result[] = $func($line, $spec[0]);
+                       } else {
+                               $result[] = $func($line, $spec[0], $spec[2]-$spec[0]);
+                       }
+               } else {
+                       $result[] = $line{$spec[0]};
+               }
+       }
+       return $result;
+}
+
+function head($file, $lines = 1) {
+       $ld = [];
+       if (($fd = fopen($file, "r"))) {
+               while ($lines--) {
+                       $ld[] = fgets($fd);
+               }
+       }
+       return $ld;
+}
+
+function ns($file) {
+       return str_replace("/", "\\", str_replace("//", "/", trim($file, "/.")));
+}
+
+function urlpath($dir, $file) {
+       return (strlen($dir) ? $dir . "/" : "") . urlencode($file);
+}
+
+function ls($dir, $invert = false) {
+       fprintf(OUTPUT, "<ul>\n");
+       foreach (scandir($dir) as $file) {
+               $dir = trim($dir, "./");
+               $html = "";
+               if ($file === ".") {
+                       continue;
+               } elseif ($file === "..") {
+                       if ($dir === "" || $invert) {
+                               continue;
+                       }
+                       $name = sprintf("namespace %s", ns(dirname($dir)));
+               } elseif (!$invert && is_dir("./$dir/$file")) {
+                       $name = sprintf("namespace %s", ns("./$dir/$file"));
+               } elseif (!$invert && ctype_upper($file{0})) {
+                       $name = join(" ", cut(head("./$dir/$file"), ["f"=>"1-2"]));
+               } elseif (!$invert || ctype_upper($file{0})) {
+                       continue;
+               } else {
+                       $name = ns($dir)."::".basename($file, ".md");
+                       $html = "<p>".join(" ", cut(head("./$dir/$file"), ["f"=>"1-"]))."</p>";
+               }
+
+               fprintf(OUTPUT, "<li><a href=\"/%s\">%s</a>%s</li>\n",
+                       urlpath($dir, $file),
+                       htmlspecialchars($name),
+                       $html);
+       }
+       fprintf(OUTPUT, "</ul>\n");
+}
+
+function ml($file) {
+       $pi = pathinfo($file);
+       if (ctype_upper($pi["filename"][0])) {
+               fprintf(OUTPUT, "<h2>Methods:</h2>\n");
+               $el = $pi["dirname"] . "/" . $pi["filename"];
+               ls($el, true);
+       }
+}
+
+function md($file) {
+       $r = fopen($file, "r");
+       $md = MarkdownDocument::createFromStream($r);
+       $md->compile();
+       $md->writeHtml(OUTPUT);
+       unset($md);
+       fclose($r);
+
+       // BS Markdown seeks around...
+       fseek(OUTPUT, 0, SEEK_END);
+       
+       ml($file);
+}
+
+$r = new http\Env\Request;
+$u = new http\Url($r->getRequestUrl());
+$t = ["css"=>"text/css", "js"=>"application/javascript"];
+
+switch($u->path) {
+case "/index.js":
+case "/index.css":
+       $s = new http\Env\Response;
+       $s->setHeader("Content-type", $t[pathinfo($u->path, PATHINFO_EXTENSION)]);
+       $s->setBody(new http\Message\Body(fopen(basename($u->path), "r")));
+       $s->send();
+       exit;
+}
+
+if (is_dir(".".$u->path)) {
+       ls(".".$u->path);
+} else {
+       md(".".$u->path);
+}
+
+?>
+<!doctype html>
+<html>
+<head>
+<meta charset="utf-8">
+<title><?=$u->path?></title>
+<link rel="stylesheet" href="/index.css">
+</head>
+<body>
+<?php
+rewind(OUTPUT);
+fpassthru(OUTPUT);
+fclose(OUTPUT);
+?>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> 
+<script src="/index.js"></script>
+</body>
+</html>