pupupu

simple static CMS for crappy servers
git clone https://git.ce9e.org/pupupu.git

commit
4c609f7d24b2e7f885425fd3805b4728605fa45a
parent
493d83035e248c43dff3d65982d3dc8a3fd2c468
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2018-10-14 12:50
foo

Diffstat

M index.php 142 ++++++++++++++++++++++++++++++++++++-------------------------
M templates/page.html 22 ++++++++++++----------

2 files changed, 95 insertions, 69 deletions


diff --git a/index.php b/index.php

@@ -2,21 +2,25 @@
    2     2 
    3     3 require __DIR__ . '/vendor/autoload.php';
    4     4 use Symfony\Component\Yaml\Yaml;
    5    -1 use Michelf\Markdown;
   -1     5 use Michelf\MarkdownExtra;
    6     6 
    7    -1 function rrmdir($path)
   -1     7 function rmdirs($path)
    8     8 {
    9    -1     foreach (scandir($path) as $object) {
   10    -1         if ($object !== '.' && $object !== '..') {
   11    -1             $p = "$path/$object";
   12    -1             if (is_dir($p)) {
   13    -1                 rrmdir($p);
   14    -1             } else {
   15    -1                 unlink($p);
   16    -1             }
   -1     9     if ($path !== '.' && file_exists($path)) {
   -1    10         try {
   -1    11             rmdir($path);
   -1    12             rmdirs(dirname($path));
   -1    13         } finally {
   17    14         }
   18    15     }
   19    -1     rmdir($path);
   -1    16 }
   -1    17 
   -1    18 function rmfile($path)
   -1    19 {
   -1    20     if (file_exists($path)) {
   -1    21         unlink($path);
   -1    22     }
   -1    23     rmdirs(dirname($path));
   20    24 }
   21    25 
   22    26 function mkdirp($path)
@@ -34,12 +38,17 @@ function shiftHeadings($html, $offset)
   34    38     }, $html);
   35    39 }
   36    40 
   -1    41 function pathIsFile($path)
   -1    42 {
   -1    43     return $path === '/_site' || strpos($path, '.') !== false;
   -1    44 }
   -1    45 
   37    46 function validatePath($path)
   38    47 {
   39    48     if (
   40    49         (strlen($path) > 1 && $path[0] !== '/') ||
   41    50         substr($path, -1) === '/' ||
   42    -1         strpos($path, '.') !== false
   -1    51         strpos($path, '..') !== false
   43    52     ) {
   44    53         http_response_code(400);
   45    54         die();
@@ -73,9 +82,27 @@ class Pupupu
   73    82         $this->cache = array();
   74    83     }
   75    84 
   76    -1     public function get($path, $name)
   -1    85     protected function getSrc($path, $ext)
   77    86     {
   78    -1         $p = $this->srcDir . '/_content' . $path . '/' . $name;
   -1    87         if (pathIsFile($path)) {
   -1    88             return $this->srcDir . '/_content' . $path . '.' . $ext;
   -1    89         } else {
   -1    90             return $this->srcDir . '/_content' . $path . '/index' . '.' . $ext;
   -1    91         }
   -1    92     }
   -1    93 
   -1    94     protected function getTarget($path)
   -1    95     {
   -1    96         if (pathIsFile($path)) {
   -1    97             return $this->targetDir . $path;
   -1    98         } else {
   -1    99             return $this->targetDir . $path . '/index.html';
   -1   100         }
   -1   101     }
   -1   102 
   -1   103     public function get($path, $ext)
   -1   104     {
   -1   105         $p = $this->getSrc($path, $ext);
   79   106         if (file_exists($p)) {
   80   107             return file_get_contents($p);
   81   108         } else {
@@ -83,56 +110,52 @@ class Pupupu
   83   110         }
   84   111     }
   85   112 
   86    -1     public function put($path, $name, $content)
   -1   113     public function put($path, $ext, $content)
   87   114     {
   88    -1         $p = $this->srcDir . '/_content' . $path . '/' . $name;
   -1   115         $p = $this->getSrc($path, $ext);
   89   116         mkdirp(dirname($p));
   90   117         file_put_contents($p, $content);
   91   118     }
   92   119 
   93   120     public function rm($path)
   94   121     {
   95    -1         rrmdir($this->srcDir . '/_content' . $path);
   96    -1         rrmdir($this->targetDir . $path);
   -1   122         rmfile($this->getSrc($path, 'yml'));
   -1   123         rmfile($this->getSrc($path, 'md'));
   -1   124         rmfile($this->getTarget($path));
   97   125     }
   98   126 
   99    -1     protected function getYml($path, $name)
   -1   127     public function getMarkdown($path)
  100   128     {
  101    -1         $key = "yml:$path:$name";
   -1   129         $key = "md:$path";
  102   130         if (!in_array($key, $this->cache)) {
  103    -1             $v = Yaml::parse($this->get($path, $name));
   -1   131             $v = MarkdownExtra::defaultTransform($this->get($path, 'md'));
  104   132             $this->cache[$key] = $v;
  105   133         }
  106   134         return $this->cache[$key];
  107   135     }
  108   136 
  109    -1     public function getBody($path)
   -1   137     public function getYaml($path)
  110   138     {
  111    -1         $key = "body:$path";
   -1   139         $key = "yml:$path";
  112   140         if (!in_array($key, $this->cache)) {
  113    -1             $v = Markdown::defaultTransform($this->get($path, 'index.md'));
   -1   141             $v = Yaml::parse($this->get($path, 'yml'));
  114   142             $this->cache[$key] = $v;
  115   143         }
  116   144         return $this->cache[$key];
  117   145     }
  118   146 
  119    -1     public function getPage($path)
  120    -1     {
  121    -1         return $this->getYml($path, 'index.yml');
  122    -1     }
  123    -1 
  124    -1     public function getSite()
  125    -1     {
  126    -1         return $this->getYml('', 'site.yml');
  127    -1     }
  128    -1 
  129   147     public function getSubpages($path)
  130   148     {
  131   149         $subpages = array();
  132    -1         $p = $this->srcDir . '/_content' . $path;
   -1   150         $p = dirname($this->getSrc($path, 'yml'));
  133   151         foreach (scandir($p) as $name) {
  134    -1             if ($name !== '.' && $name !== '..' && is_dir("$p/$name")) {
  135    -1                 $subpages[$name] = "$path/$name";
   -1   152             if ($name !== '.' && $name !== '..' && $name[0] !== '_') {
   -1   153                 if (substr($name, -4) === '.yml') {
   -1   154                     $name = substr($name, 0, -4);
   -1   155                 }
   -1   156                 if (file_exists($this->getSrc("$path/$name", 'yml'))) {
   -1   157                     $subpages[$name] = "$path/$name";
   -1   158                 }
  136   159             }
  137   160         }
  138   161         return $subpages;
@@ -140,9 +163,9 @@ class Pupupu
  140   163 
  141   164     public function upload($file)
  142   165     {
  143    -1         $p = $this->targetDir . '/uploads';
  144    -1         mkdirp($p);
  145    -1         move_uploaded_file($file['tmp_name'], $p . '/' . $file['name']);
   -1   166         $p = $this->targetDir . '/uploads/' . $file['name'];
   -1   167         mkdirp(dirname($p));
   -1   168         move_uploaded_file($file['tmp_name'], $p);
  146   169     }
  147   170 
  148   171     public function getUploads()
@@ -168,24 +191,22 @@ class Pupupu
  168   191             echo "rendering $path\n";
  169   192         }
  170   193 
  171    -1         $page = $this->getPage($path);
  172    -1         $site = $this->getSite();
  173    -1         $body = $this->getBody($path);
  174    -1         $body = shiftHeadings($body, $site['shiftHeadings'] ?? 0);
   -1   194         $page = $this->getYaml($path);
   -1   195         $site = $this->getYaml('/_site');
   -1   196         $body = $this->getMarkdown($path);
   -1   197         $body = shiftHeadings($body, $site['_shiftHeadings'] ?? 0);
  175   198 
  176    -1         $template = $page['template'] ?? 'base.html';
   -1   199         $template = $page['_template'] ?? 'base.html';
  177   200         $html = $this->twig->render($template, array(
  178   201             'page' => $page,
  179   202             'site' => $site,
  180   203             'body' => $body,
  181    -1             'date' => time(),
  182   204             'pupupu' => $this,
  183   205         ));
  184   206 
  185    -1         $filename = $page['filename'] ?? 'index.html';
  186    -1         $p = $this->targetDir . $path . '/' . $filename;
  187    -1         mkdirp(dirname($p));
  188    -1         file_put_contents($p, $html);
   -1   207         $target = $this->getTarget($path);
   -1   208         mkdirp(dirname($target));
   -1   209         file_put_contents($target, $html);
  189   210     }
  190   211 
  191   212     public function renderAll($verbose=false, $path='')
@@ -198,8 +219,8 @@ class Pupupu
  198   219 
  199   220     public function renderDynamic($verbose=false)
  200   221     {
  201    -1         $site = $this->getSite();
  202    -1         $dynamic = $site['dynamic'] ?? array();
   -1   222         $site = $this->getYaml('/_site');
   -1   223         $dynamic = $site['_dynamic'] ?? array();
  203   224         foreach ($dynamic as $path) {
  204   225             $this->render($path, $verbose);
  205   226         }
@@ -225,10 +246,10 @@ function siteView($pupupu, $twig)
  225   246 {
  226   247     if ($_SERVER['REQUEST_METHOD'] == 'GET') {
  227   248         echo $twig->render('site.html', array(
  228    -1             'yml' => $pupupu->get('', 'site.yml'),
   -1   249             'yml' => $pupupu->get('/_site', 'yml'),
  229   250         ));
  230   251     } else {
  231    -1         $pupupu->put('', 'site.yml', $_POST['yml']);
   -1   252         $pupupu->put('/_site', 'yml', $_POST['yml']);
  232   253         $pupupu->renderAll();
  233   254         header("Location: ", true, 302);
  234   255     }
@@ -238,18 +259,21 @@ function pageView($pupupu, $twig)
  238   259 {
  239   260     if (isset($_GET['add'])) {
  240   261         header("Location: ?path=${_GET['path']}/${_GET['add']}", true, 302);
   -1   262     } elseif ($_GET['path'] === '/_site') {
   -1   263         header('Location: ?path=_site', true, 302);
  241   264     } else {
  242   265         $path = validatePath($_GET['path']);
  243   266 
  244   267         if ($_SERVER['REQUEST_METHOD'] == 'GET') {
  245   268             echo $twig->render('page.html', array(
  246    -1                 'yml' => $pupupu->get($path, 'index.yml'),
  247    -1                 'md' => $pupupu->get($path, 'index.md'),
   -1   269                 'yml' => $pupupu->get($path, 'yml'),
   -1   270                 'md' => $pupupu->get($path, 'md'),
  248   271                 'subpages' => $pupupu->getSubpages($path),
  249   272                 'path' => $path,
   -1   273                 'pathIsFile' => pathIsFile($path),
  250   274                 'breadcrumbs' => getBreadcrumbs($path),
  251   275             ));
  252    -1         } elseif ($_POST['delete']) {
   -1   276         } elseif (isset($_POST['delete'])) {
  253   277             if ($path === '') {
  254   278                 http_response_code(400);
  255   279                 die();
@@ -258,8 +282,8 @@ function pageView($pupupu, $twig)
  258   282             $target = dirname($path);
  259   283             header("Location: ?path=$target", true, 302);
  260   284         } else {
  261    -1             $pupupu->put($path, 'index.yml', $_POST['yml']);
  262    -1             $pupupu->put($path, 'index.md', $_POST['md']);
   -1   285             $pupupu->put($path, 'yml', $_POST['yml']);
   -1   286             $pupupu->put($path, 'md', $_POST['md']);
  263   287             $pupupu->render($path);
  264   288             $pupupu->renderDynamic();
  265   289             header('Location: ', true, 302);

diff --git a/templates/page.html b/templates/page.html

@@ -2,18 +2,20 @@
    2     2 
    3     3 {% block breadcrumbs %}
    4     4     {% for name, path in breadcrumbs %}
    5    -1         <a href="?path={{ path }}">{{ name }}</a> /
   -1     5         / <a href="?path={{ path }}">{{ name }}</a>
    6     6     {% endfor %}
    7     7 
    8    -1     <form>
    9    -1         <input type="hidden" name="path" value="{{ path }}">
   10    -1         <input type="text" name="add" list="subpages" autocomplete="off">
   11    -1         <datalist id="subpages">
   12    -1             {% for name, path in subpages %}
   13    -1                 <option value="{{ name }}">
   14    -1             {% endfor %}
   15    -1         </datalist>
   16    -1     </form>
   -1     8     {% if not pathIsFile %}
   -1     9         / <form>
   -1    10             <input type="hidden" name="path" value="{{ path }}">
   -1    11             <input type="text" name="add" list="subpages" autocomplete="off">
   -1    12             <datalist id="subpages">
   -1    13                 {% for name, path in subpages %}
   -1    14                     <option value="{{ name }}">
   -1    15                 {% endfor %}
   -1    16             </datalist>
   -1    17         </form>
   -1    18     {% endif %}
   17    19 {% endblock %}
   18    20 
   19    21 {% block main %}