tintin is the PiROS HTTP server. When it's asked for a .psh file it runs
the script and returns its output as the page. That turns Pequod into a template language for a real,
if tiny, web stack.
A request for /page.psh makes tintin run psh on that file and stream the
result back to the browser:
browser ──GET /page.psh──▸ tintin ──exec──▸ psh page.psh ──▸ HTML ──▸ browser
tintin runs the script as its own service user and hands it the request context (method, query,
body), which Pequod exposes as the $_GET, $_POST, $_SERVER and
$_REQUEST superglobals.
Any file containing a <? tag is a template: text outside the tags is sent
verbatim, code inside runs. Use <?= expr ?> to echo a value inline.
<!doctype html>
<html><body>
<h1><?= "Welcome to PiROS" ?></h1>
<? $now = "today"; ?>
<p>Served <?= $now ?> by tintin.</p>
</body></html>
<? foreach (…) { ?><li>…</li><? } ?>.The everyday pattern: loop an array, emit a row per item.
default/www/status.psh<!doctype html>
<html><body><h1>Services</h1>
<? $svc = ["sshd" => "running", "tintin" => "running", "nemo" => "stopped"];
$up = 0; ?>
<ul>
<? foreach ($svc as $name => $state) {
if ($state == "running") { $up++; } ?>
<li><?= htmlspecialchars($name) ?> — <?= $state ?></li>
<? } ?>
</ul>
<p><?= $up ?> of <?= count($svc) ?> up.</p>
</body></html>
$_GET and $_POSTtintin populates the superglobals from the request. They're associative arrays; index by field name. When there's no request context (running from the shell) they're simply empty, so you can index them safely without guards.
| Superglobal | Holds |
|---|---|
$_GET["field"] | Query-string parameters (?field=value). |
$_POST["field"] | Submitted form fields (POST body). |
$_REQUEST["field"] | GET overlaid with POST (POST wins). |
$_SERVER["REQUEST_METHOD"] | "GET" or "POST". |
Show the form on GET; process the submission on POST. Always run user
values through htmlspecialchars() before echoing them into the page.
<!doctype html>
<html><body>
<? if ($_SERVER["REQUEST_METHOD"] == "POST") { ?>
<p>Hello, <?= htmlspecialchars($_POST["name"]) ?>!</p>
<? } else { ?>
<form method="post">
<input name="name" placeholder="your name">
<button>Say hi</button>
</form>
<? } ?>
</body></html>
$_GET/$_POST
value into HTML is an XSS hole. htmlspecialchars() turns <script> into
harmless text. Make it a habit for every user-supplied value.Keep settings and secrets out of the served directory. Put them in a file elsewhere and
include it — its define()d constants become available, but the file itself is
never served.
define("SITE_NAME", "PiROS demo");
define("DB", "shop");
default/www/home.psh
<? include "config/app.psh"; ?>
<h1><?= SITE_NAME ?></h1>
Drop the .psh file under tintin's web root and start the service (root):
root@pros> admin service start tintin
root@pros> ps # tintin shows as a ring-3 process
Then request it from a browser or curl. A page that reads a database is one small step
further — that's the SQL chapter.
included fragments, and keep generated output within the capture limit.