LiaCat.php
<?php
class LiaCat extends \Lia\Compo {
protected $projects = [];
protected $useKittenLogo = false;
protected $appName = "Liaison WiKitten implementation";
protected $pathParts = [];
public $projectsDir;
public $baseUrl;
public $reqUrl;
public function __construct($package){
parent::__construct($package);
$options = (object)$package->setup['options'];
$this->projectsDir = $options->projectsDir;
$this->baseUrl = $options->baseUrl;
if (!is_dir($this->projectsDir)){
throw new \Exception("You must pass a valid directory path as 'projectsDir' to the wiki package setup.");
}
}
protected $defaultPageData = array(
'title' => false, // will use APP_NAME by default
'description' => 'Wikitten is a small, fast, PHP wiki.',
'tags' => array('wikitten', 'wiki'),
'page' => ''
);
//need to make the base url function with the static files & project files
public function onRequest_Setup($event, $url){
// echo 'oh good';exit;
//add each project's directory to the router
//probably do it as a callable, since will not use the regular file-routing mechanisms
//or add a new feature to liaison to fine-tune route handling
//or implement an existing event that lets me filter content handlers
}
public function onEvents_Sort($event, $name, $args, $events){
if ($name!='Request_Deliver')return $events;
$others = [];
foreach ($events as $callable){
if (!is_array($callable))continue;
if ($callable[0]!==$this)$others[] = $callable;
}
$baseUrl = $this->baseUrl;
$url = $args[0];
if (substr($url,0,strlen($baseUrl))!=$baseUrl)return $others;
$staticUrl = $baseUrl.'static/';
if (substr($url,0,strlen($staticUrl))==$staticUrl)return $others;
foreach ($events as $callable){
if (!is_array($callable))continue;
if ($callable[0]===$this)return [$callable];
}
}
public function onRequest_Deliver($event,$url){
if (($_GET['view_source']??false)=='true'){
$source = $this->getFileContent($url);
if (($_GET['raw']??false)=='true'){
header(('Content-type: text/plain'));
echo $source;
exit;
}
header(('Content-type: text/html'));
$extension = pathinfo($url,PATHINFO_EXTENSION);
$source = htmlentities($source);
$html =
<<<HTML
<!DOCTYPE html>
<html>
<head>
<style>
html,body, body > pre {
padding:0;
margin:0;
}
body > pre > code.hljs{
margin:0;
padding:16px;
}
</style>
<link rel="stylesheet"
href="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.1.2/build/styles/default.min.css">
<script src="//cdn.jsdelivr.net/gh/highlightjs/cdn-release@10.1.2/build/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body>
<pre><code class="language-{$extension}">{$source}</code></pre>
</body>
</html>
HTML;
echo $html;
exit;
}
$url = str_replace(['%20'],' ', $url);
$this->reqUrl = $url;
$content = $this->getWikiContent($url);
ob_start();
$lia = $this->lia;
// require($this->dir('theme').'/init.php');
require($this->dir('theme').'/template.php');
$pageOutput = ob_get_clean();
// exit;
// $this->lia->send('Theme_Display',$pageOutput,$url,[]);\
$themeView = $this->lia->view('Site/Theme',['content'=>$pageOutput,'without_content_area'=>true]);
if ($themeView==null)echo $pageOutput;
else echo $themeView;
}
protected function config($name){
return null;
}
protected function getFileContent($url){
$url = str_replace(['%20'],' ', $url);
if (substr($url,0,strlen($this->baseUrl))!==$this->baseUrl)return;
$relUrl = substr($url,strlen($this->baseUrl));
$file = str_replace(['///','//'],'/',$this->projectsDir.'/'.$relUrl);
if (!file_exists($file))return "File not found...";
$content = file_get_contents($file);
return $content;
// $ext = pathinfo($file,PATHINFO_EXTENSION);
// $mdContent = "```{$ext}\n{$content}\n```";
// // $converter = new League\CommonMark\CommonMarkConverter([
// // // 'html_input' => 'strip',
// // // 'allow_unsafe_links' => false,
// // ]);
// // $coolOutput = $converter->convertToHtml($mdContent);
// return $coolOutput;
}
protected function getWikiContent($url){
$url = str_replace(['%20'],' ', $url);
if (substr($url,0,strlen($this->baseUrl))!==$this->baseUrl)return;
$relUrl = substr($url,strlen($this->baseUrl));
$file = str_replace(['///','//'],'/',$this->projectsDir.'/'.$relUrl);
return $this->render($file);
}
public function addProject($projectDir){
$this->projects[] = $projectDir;
}
public function cleanHtml($dirty){
return htmlspecialchars($dirty, ENT_QUOTES, 'UTF-8');
}
public function tree($array, $parent, $parts = array(), $step = 0) {
// return 'this is where tree items print';
// return;
if (!count($array)) {
return '';
}
$tid = ($step == 0) ? 'id="tree"' : '';
$t = '<ul class="unstyled" '.$tid.'>';
// var_dump('parent',$parent);
// exit;
$reqUrl = $this->reqUrl;
// var_dump($parent,$reqUrl);
foreach ($array as $key => $item) {
if (is_array($item)) {
$open = false;
// var_dump($key);
$itemUrl = $parent.'/'.$key;
if (substr($reqUrl,0,strlen($itemUrl))===$itemUrl){
// var_dump($reqUrl);
// var_dump($itemUrl);
$open = true;
}
$ourlpen = $step !== false && (isset($parts[$step]) && $key == $parts[$step]);
$t .= '<li class="directory'. ($open ? ' open' : '') .'">';
$t .= '<a href="#" data-role="directory"><i class="far fa-folder'. ($open ? '-open' : '') .'"></i> ' . $key . '</a>';
$t .= $this->tree($item, "$parent/$key", $parts, $open ? $step + 1 : false);
$t .= '</li>';
} else {
$selected = (isset($parts[$step]) && $item == $parts[$step]);
$t .= '<li class="file'. ($selected ? ' active' : '') .'"><a href="'. $parent .'/'. $item . '">'.$item.'</a></li>';
}
}
$t .= '</ul>';
return $t;
}
public function getTree($dir =null)
{
$dir = $dir ?? $this->projectsDir;
// echo 'tree';exit;
// return 'tree items';exit;
$return = array('directories' => array(), 'files' => array());
$items = scandir($dir);
foreach ($items as $item) {
if ($item=='.'||$item=='..')continue;
// if (preg_match($this->_ignore, $item)) {
// if ($this->_force_unignore === false || !preg_match($this->_force_unignore, $item)) {
// continue;
// }
// }
$path = $dir.'/'.$item;
if (is_dir($path)) {
$return['directories'][$item] = $this->getTree($path);
continue;
}
$return['files'][$item] = $item;
}
uksort($return['directories'], "strnatcasecmp");
uksort($return['files'], "strnatcasecmp");
return $return['directories'] + $return['files'];
}
protected function pathIsSafe($fullPath){
if (substr($fullPath,0,strlen($this->projectsDir))==$this->projectsDir){
return true;
}
return false;
}
protected function render($absPath)
{
// var_dump($absPath);
// exit;
$relPath = substr($absPath,strlen($this->projectsDir));
if (substr($relPath,0,1)=='/')$relPath = substr($relPath,1);
$breadcrumbs = explode('/', $relPath);
// array_shift($breadcrumbs);
$this->pathParts = $breadcrumbs;
if (!$this->pathIsSafe($absPath)) {
$this->notFound();
}
// var_dump($absPath);
// Handle directories by showing a neat listing of its
// contents
if (is_dir($absPath)) {
if (file_exists($indexFile=$absPath.'/index.md')
||file_exists($indexFile=$absPath.'/index.html')) {
return $this->render($indexFile);
}
// Get a printable version of the actual folder name:
$dir_name = htmlspecialchars(end($breadcrumbs), ENT_QUOTES, 'UTF-8');
// Pass this to the render view, cleverly disguised as just
// another page, so we can make use of the tree, breadcrumb,
// etc.
$page_data = $this->defaultPageData;
$page_data['title'] = 'Listing: ' . $dir_name;
// var_dump($absPath);exit;
$files = scandir($absPath);
$list = "<h2>I'm an empty folder... Very hungry!</h2>\n";
if (2 < count($files)) {
$list = '';
$dirs = [];
$nondirs = [];
foreach ($files as $file){
if ($file=='.'||$file=='..')continue;
$targetUrl = str_replace(['///','//'],'/',$this->reqUrl.'/'.$file);
$relUrl = substr($targetUrl,strlen($this->baseUrl));
$targetPath = $this->projectsDir.'/'.$relUrl;
if (is_dir($targetPath))$dirs[$file] = $targetUrl;
else $nondirs[$file] = $targetUrl;
}
if (count($dirs)>0){
$list .= "<h2>Lovely subfolders</h2>\n";
$list .="<ul>\n";
foreach ($dirs as $name=>$targetUrl) {
$list .= "<li><a href=\"{$targetUrl}\">${name}</a></li>\n";
}
$list .= "</ul>\n";
}
if (count($nondirs)>0){
$list .= "<h2>Beautiful files!</h2>\n";
$list .="<ul>\n";
foreach ($nondirs as $name=>$targetUrl) {
$list .= "<li><a href=\"{$targetUrl}\">${name}</a></li>\n";
}
$list .= "</ul>\n";
}
}
// echo $list;
// exit;
return $this->lia->view('Wiki/render', array(
'breadcrumbs' => $breadcrumbs,
'page' => $page_data,
'html' => $list,
'is_dir' => true,
'compo'=>$this
));
}
// $finfo = finfo_open(FILEINFO_MIME);
// $mime_type = trim(finfo_file($finfo, $path));
// if (substr($mime_type, 0, strlen('text/plain')) != 'text/plain'
// && substr($mime_type, 0, strlen('inode/x-empty')) != 'inode/x-empty'
// ) {
// echo 'zabeebebee';exit;
// // not an ASCII file, send it directly to the browser
// $file = fopen($path, 'rb');
// header("Content-Type: $mime_type");
// header("Content-Length: " . filesize($path));
// fpassthru($file);
// exit();
// }
$source = file_get_contents($absPath);
$extension = pathinfo($absPath, PATHINFO_EXTENSION);
$renderer = true;
$page_data = $this->defaultPageData;
// Extract the JSON header, if the feature is enabled:
if ($this->usePageMetaData??false) {
list($source, $meta_data) = $this->_extractJsonFrontMatter($source);
$page_data = array_merge($page_data, $meta_data);
}
// We need to know the source file in case editing is enabled:
// $page_data['file'] = $page;
$html = false;
if ($renderer===true){
// $rawcontent = $liaison->package('liaison_base')->compo('RawContent')
$mimetype = \Lia\Content\RawContent::extensionMimeType($extension);
$mimeparts = explode('/',$mimetype);
if ($mimeparts[0]=='image'){
$blob = 'data:'.$mimetype.';base64,'.base64_encode($source);
$html = '<img src="'.$blob.'" />';
// var_dump($path);
// var_dump($page);
// exit;
} else if ($extension=='md'){
$cm = new \League\CommonMark\CommonMarkConverter([
'html_input' => 'strip',
'allow_unsafe_links' => false,
]);
$source = $source;
$html = $cm->convertToHtml($source);
} else {
$source = htmlentities($source);
$basename = basename($absPath);
$html =
<<<HTML
<h2>{$basename}</h2>
<pre><code class="language-{$extension}">{$source}</code></pre>
HTML;
}
// echo $html;exit;
// $source = '';
$renderer = true;
// $html = \Wikitten\MarkdownExtra::defaultTransform('```json'."\n".$source."\n```");
}
// if ($extension=='html') {
// $html = $source;
// }
// if ($renderer && $renderer == 'Markdown') {
// $html = \Wikitten\MarkdownExtra::defaultTransform($source);
// }
if (empty(trim($html))) {
$html = "<h1>This page is empty</h1>\n";
$source = $breadcrumbs[0];
}
return $this->lia->view('Wiki/render', array(
'html' => $html,
'source' => $source,
'extension' => $extension,
'breadcrumbs' => $breadcrumbs,
'page' => $page_data,
'is_dir' => false,
'use_pastebin' => false,
'compo'=>$this,
'reqUrl'=>$this->reqUrl
));
}
static public function packageDir(){
return dirname(__DIR__);
}
}