'default'); private $keyfiles = array(); public $structs = array(); private $EXT=array( 'txt'=>array( 'txt', 'text', 'md' ), 'pic'=>array( 'jpg', 'jpeg', 'png', 'svg' ), 'tpl'=>array( 'html', 'htm', 'tpl' ), 'audio'=>array('mp3','wav','ogg'), 'csv'=>array( 'csv' ) ); public $config = array(); private $state=array(); function __construct($folder,$conf=array()) { debug("about to construct FIF: $folder"); $f3 = \Base::instance(); if(is_dir($folder)) { // are we given a valid path? $this->folder = $folder; } else { // and if not? $this->folder = $f3->get('CONTENT')."./"; } if(is_array($conf)) { foreach($conf as $key=>$value) { switch($key) { case 'content': if(is_array($value)) { foreach($value as $k=>$v) { $this->domains[$k] = $v; } } break; case 'keyfiles': if(is_array($value)) { foreach($value as $k=>$v) { $this->keyfiles[$k] = $v; } } break; } } } foreach($this->domains as $domain) { $this->content[$domain] = array(); } foreach($this->keyfiles as $keys=>$d) { $this->extras[$keys] = ""; } debug("constructed files in folder: $folder"); } ///////////////////////////// // read folder into struct // ///////////////////////////// function prepare_files() { foreach ($this->domains as $k=>$v) { foreach($this->EXT as $cat=>$endings) { $this->structs[$k][$cat]=array(); } } $ls = scandir($this->folder); foreach ($ls as $k=>$f) { if (!strncmp($f,'.',1)) continue; // ignore hidden files $ex=explode(".", $f); $ext=strtolower(end($ex)); if (array_key_exists($ex[0],$this->domains)) { $domain_key=$ex[0]; $sort_key=1; } elseif (array_key_exists($ex[0], $this->keyfiles)) { if(in_array($ext,$this->EXT[$this->keyfiles[$ex[0]]['type']])) { $this->extras[$ex[0]]=$this->folder.$f; continue; } $domain_key='default'; $sort_key=0; } else { $domain_key='default'; $sort_key=0; } foreach ($this->EXT as $cat=>$endings) { if (in_array($ext, $endings)) { $this->structs[$domain_key][$cat][$ex[$sort_key]] = $this->folder.$f; break; } } } foreach($this->keyfiles as $key=>$param) { if(!$this->extras[$key]) { $this->extras[$key] = self::search_up( $key, array($this->folder,$param['until']), $this->EXT[$param['type']] ); } if($this->extras[$key]) { if ($param['type'] == 'txt') { $this->read_textfile($this->extras[$key]); } } } } /////////////////////////////////////// // prepare content as per the struct // /////////////////////////////////////// function fill_content() { $f3 = \Base::instance(); $md = new \freaParsedown(); $md->deactivate_ol(); //var_dump($md->get_BlockTypes()); foreach($this->domains as $domain_key=>$domain) { // don't act on hidden files if ($domain == 'hidden') { continue; } $this->state['current_domain'] = $domain_key; foreach($this->structs[$domain_key]['txt'] as $key=>$file) { $str = $this->read_textfile($file); $str = self::content_element_dispatcher($str); $str = $md->text($str); //$str = sprintf("%s", $str); $this->content[$domain][$key."30text"] = sprintf( "
%s
", $page, $key, $str ); } $includeTemplates = array_key_exists('includeTemplates', $this->config) ? $this->config['includeTemplates'] : $f3->get('includeTemplates') ? : FALSE ; if ($includeTemplates) { foreach($this->structs[$domain_key]['tpl'] as $key=>$file) { $str = \Template::instance()->render(substr($file,7)); $str = self::linkify($str); $this->content[$domain][$key."00tpl"] = sprintf( "
%s
", $page, $key, $str ); } } $bulkIncludePic = array_key_exists('bulkIncludePic',$this->config) ? $this->config['bulkIncludePic'] : $f3->get('bulkIncludePic') ? : FALSE ; if ($bulkIncludePic) { foreach($this->structs[$domain_key]['pic'] as $key=>$file) { $this->content[$domain][$key."10image"] = sprintf( "" ); } } $bulkIncludeAudio = array_key_exists('bulkIncludeAudio',$this->config) ? $this->config['bulkIncludeAudio'] : $f3->get('bulkIncludeAudio') ? : FALSE ; if ($bulkIncludeAudio) { foreach ($this->structs[$domain_key]['audio'] as $key=>$file) { $this->content[$domain][$key."20audio"] = sprintf( '%s
', $file, $key ); } } foreach($this->structs[$domain_key]['csv'] as $key=>$file) { $csv = new \Modules\Ography($file,TRUE); $str=""; foreach($csv->entries as $entry) { $tmp=""; foreach($entry as $key=>$value) { $tmp .= sprintf("", $key, $value); } $str .= sprintf("%s",$tmp); } $str.="
%s
"; $this->content[$domain][$key."30csv"] = $str; } } } ////////////////////// // read config data // ////////////////////// function read_config($domain=false) { foreach ($this->domains as $source=>$destination) { if (is_string($domain)) { if ($source != $domain) { continue; } } elseif (is_array($domain)) { if (!in_array($source,$domain)) { continue; } } foreach ($this->structs[$source]['txt'] as $key=>$file) { $this->read_textfile($file); } } return $this->config; } //////////////// // recursions // //////////////// function search_up($key,$paths,$ext) { $return = ""; if(count($paths) == 2) { $current = $paths[0]; $last_try = $paths[1]; $ls=scandir($current); foreach($ls as $f) { if(!strncmp($f,'.',1)) continue; // ignore hidden files $ex=explode(".", $f); if(in_array(strtolower(end($ex)),$ext)) { if($ex[0]==$key) { $return = $current.$f; break; } } } } if ($return) { return $return; } elseif($current == $last_try) { return false; } else { $p = explode('/',$current); array_pop($p); array_pop($p); return self::search_up($key,array(implode("/",$p)."/",$last_try),$ext); } } /////////////////////// // Utility functions // /////////////////////// function read_textfile($file) { debug("about to read file: $file"); $str = file_get_contents($file); debug("read file: $file"); $str = self::linkify($str); $str = self::strip_comments($str); $str = self::get_config_from_content($str); debug("processed file: $file"); return $str; } function strip_comments($str) { $single_line_comments = "/(^;.*\R)/m"; $str = preg_replace($single_line_comments,"",$str); $multi_line_comments = "/\/\*.*?\*\//s"; $str = preg_replace($multi_line_comments,"",$str); return $str; } function linkify($string) { $pattern = "/\s@(\w+)[=]([\w,]+)\s/"; $count = 0; $new = preg_replace_callback ($pattern, function($m){ $f3 = \Base::instance(); return $f3->get('SITE_URL') .$f3->alias($m[1],self::$keyword."=".$m[2]) ;}, $string); return $new; } function get_config_from_content($string) { $f3 = \Base::instance(); $f = 0; $pattern = "/#\+(\w+):\s?(.*)/"; $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER); for ($i=0;$i<$f;$i++) { $string = str_replace($matches[0][$i],"",$string); $key = $matches[1][$i]; $value = trim($matches[2][$i]); if(strtolower($value) == "false") { $value = FALSE; } if(!strncmp(trim($value),'@',1)) { //var_dump($f3->get('DATA')); if (array_key_exists($key,$f3->get('DATA'))) { $DATA = $f3->get('DATA.'.$key); $conf = array($DATA['type'],$DATA['dir']); $relation = new \Modules\TOC($conf,$f3->get('CONTENT'),substr($value,1)); $relation->dispatch(); $this->config[$key]=array_shift($relation->entries); } else { $this->config[$key]=$value; } } else { $this->config[$key]=$value; } } $pattern = "/§>\s*(\w+):(.*?)\R[\011\040]*\R/s"; $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER); for ($i=0;$i<$f;$i++) { $string = str_replace($matches[0][$i],"",$string); $key = $matches[1][$i]; $value = trim($matches[2][$i]); if(strtolower($value) == "false") { $value = FALSE; } if (!strncmp($value,'@',1)) { # var_dump(); if (array_key_exists($key,$f3->get('DATA'))) { $entries = explode("@",$value); array_shift($entries); // first entry is always empty $DATA = $f3->get('DATA.'.$key); $conf = array($DATA['type'],$DATA['dir']); $relation = new \Modules\TOC($conf,$f3->get('CONTENT'),$entries); $relation->dispatch(); if(/*count($entries) >*/ 1) { $this->config[$key]= new CMultiple($relation->entries); } else { $this->config[$key]=array_shift($relation->entries); } } else { $this->config[$key]=$value; } } else { $this->config[$key]=$value; } } return $string; } function content_element_dispatcher($string) { $f3 = \Base::instance(); $md = new \freaParsedown(); $md->deactivate_ol(); $f0 = 0; // find occorances of {| keyword |} $pattern = "/\{\|(.+?)\|\}/s"; $f = preg_match_all($pattern, $string,$matches,PREG_PATTERN_ORDER); for ($i=0;$i<$f;$i++) { $body = preg_split("/\R/",trim($matches[1][$i])); $request = explode(":", trim(array_shift($body))); $new=""; switch($request[0]) { case 'test': $new="seems to work"; break; case ';': $new=""; break; case 'path': $new="/".$this->folder; break; case 'space': $new=sprintf("
", $request[1] ); break; case 'span': $new=sprintf("%s", $request[1], $request[2] ? : implode("\n",$body) ); break; case 'small-text': if(count($body)) { $new=sprintf("
%s
", implode("\n",$body) ); } else { $new=sprintf("%s", $request[1] ); } break; case 'TOC': // throw away TOC part of request, we don't need it array_shift($request); $toc = new \Modules\TOC($request,$this->folder,$body); $toc->dispatch(); $new=sprintf("
%s
", array_shift($request), $toc); break; case 'form': $token_db = $f3->get('TEMP') . "CEform/"; $form_config_file = sprintf("%s%s.cfg", ROOT.$this->folder, $request[1]); $db = new \DB\Jig($token_db,\DB\Jig::FORMAT_JSON); $formcall = new \DB\Jig\Mapper($db,'form_calls'); $timestamp = time(); $token = md5($timestamp . $form_config_file . rand(100,999)); $f3->config($form_config_file); $fields = $f3->get('fields'); foreach ($fields as $k => $v) { if ($v['type'] == 'custom') { $fields[$k]['template'] = sprintf( "%s%s", substr($this->folder,8), //assumens content folder is content $v['template'] ); } } $f3->set('fields', array_merge( $fields, ['xss-token'=>[ 'type'=>'hidden', 'value'=>$token, 'length'=>strlen($token) ]] )); $formcall->token = $token; $formcall->timestamp = $timestamp; $formcall->form = $form_config_file; $formcall->save(); $form_view = new \Template; $new=$form_view->render('form.htm'); break; case 'box': array_shift($request); //get rid of identifier $type = array_shift($request); $pics = explode(":",array_shift($body)); $pic = $pics[0]; $pic_hover = count($pics) > 1 ? $pics[1] : $pic; if (count($body) >= 3) { $caption = ['normal'=>['cap1' => array_shift($body), 'cap2' => array_shift($body)], 'hover'=> ['cap1' => array_shift($body), 'cap2' => array_shift($body)]]; $caption_html=[]; foreach ($caption as $state => $set) { if(!$set['cap2']) { $caption_html[$state] = [ sprintf(' '), sprintf('%s',$set['cap1']) ]; } else if (!$set['cap1'] && $set['cap2']) { $caption_html[$state] = [ sprintf('%s',$set['cap2']) ]; } else { $caption_html[$state] = [ sprintf('%s',$set['cap1']?:" "), sprintf('%s',$set['cap2']) ]; } } $has_caption = TRUE; } else { $has_caption = FALSE; } if (file_exists($this->folder.$pic)) { $pic = $this->folder.$pic; } else { $pic = $f3->get('RESOURCES')."img/default_img.png"; } if (file_exists($this->folder.$pic_hover)) { $pic_hover = $this->folder.$pic_hover; } else { $pic_hover = $pic; } if(0) { $PIC = new \Image($pic); $orientation = $PIC->width() > $PIC->height() ? 'landscape' : 'portrait' ; unset($PIC); } else { list($wwidth, $hheight) = getimagesize($pic); $orientation = $wwidth > $hheight ? 'landscape' : 'portrait'; } $pic = new CachedImage($pic); $pic_hover = new CachedImage($pic_hover); $class=""; $add=""; switch($type) { case 'plain': $link=false; break; case 'download': $file = "/".$this->folder.implode(":",$request); $link='href="'.$file.'" download '; break; case 'lightbox': $body = implode("\n",$body); if (count($request) % 2) { $class = array_pop($request); } if (count($request) >= 2) { $body=str_replace([$request[0],$request[1]],["{|","|}"],$body); $body=$this->content_element_dispatcher($body); } $hash=md5($body); $add=sprintf("
\n%s\n
", $hash, $md->text($body)); $link='href="#" data-featherlight="#'.$hash.'" '; break; case 'internal': $dest=implode(":",$request); $data = []; $base = substr($dest,0,strpos($dest,'?') ? : strlen($dest)); parse_str(parse_url($dest,PHP_URL_QUERY),$data); $fragment = parse_url($dest,PHP_URL_FRAGMENT); if ($f3->get('LANG') != $f3->get('default_lang')) { if (!array_key_exists('lang',$data)) { $data['lang'] = $f3->get('LANG'); } } $new_dest = $base; if (count($data) > 0) { $new_dest .= "?" . http_build_query($data); } if ($fragment) { $new_dest .= "#" . $fragment; } //if ($f3->get('LANG') != $f3->get('default_lang')) { // $dest .= "?lang=".$f3->get('LANG'); //} $link=sprintf('href="%s" ',$f3->get('SITE_URL')."/".$new_dest); break; case 'external': $dest=implode(":",$request); $target = $f3->get('external_links_open_in_new_window') ? 'target="_blank"' : '' ; $link=sprintf('href="%s" %s',$dest, $target); break; default: $link='href="#"'; break; } $new=sprintf("
\n\n
%s %s \n
\n
\n%s\n
", implode(" ",[$orientation,$class,$type]), $link, $pic->get_src(1600), $pic_hover->get_src(1600), ($has_caption ? "
".implode("
",$caption_html['normal'])."
": " "), ($has_caption ? "
".implode("
",$caption_html['hover'])."
" : " " ), $add ); break; case 'brick': array_shift($request); $class = array_shift($request); $new = sprintf("
\n%s\n
", $class, $md->text(implode("\n",$body)) ); break; case 'calendar': array_shift($request); $conf = array('path', $this->folder); $v = $this->read_config(); $cal = new \Modules\CCalendar($v,$conf); $new=sprintf("
\n%s\n
", $cal); break; case 'header': array_shift($request); $conf = array('path', $this->folder); $v = $this->read_config(); switch (array_shift($request)) { case 'event': $el = new CEvent($v,$conf); $el->set_layout('archive'); $new = $el; break; case 'concert': $el = new CConcert($v,$conf); $el->set_layout('header'); $new = $el; break; } break; case 'image': $key=$request[1]; $image=""; // if(!$key) { // $new=self::warn("Content Module \"Image\" needs name of a file (without extension)"); // break; //} foreach($this->structs as $domain=>$destination) { if(array_key_exists($key, $this->structs[$domain]['pic'])) { $image = $this->structs[$domain]['pic'][$key]; unset($this->structs[$domain]['pic'][$key]); unset($this->content[$this->domains[$domain]][$key]); break; } } if ($image) { if( in_array($request[2],array('left','right','full'))) { $class = $request[2]; } else { $class = 'full'; } $img = new \Image($image); $ratio = ($img->width() >= $img->height()) ? "landscape" : "portrait" ; $cached = new CachedImage($image); foreach ($body as $k=>$line) { if (strpos($line,"©") !== FALSE || strpos($line,"©") !== FALSE) { $body[$k] = sprintf("%s",$line); } } $new=sprintf("
" ."
\"user
" ."\"user" ."
%s
" ."
", $class, $ratio, $cached->get_src(1600), $cached->get_src(1600), $cached->get_src(1600), $md->text(implode("\n",$body)) ); } else { $new=sprintf("
\n" ."
\n" ."
\n%s\n
\n" ."
\n", $class, $ratio, $md->text(implode("\n",$body)) ); } break; case 'devide': $contents = explode($request[1],implode("\n",$body)); $c=count($contents); $str=""; for ($iiii=0;$iiii<$c;$iiii++) { $str .= sprintf(" %f%%",100/$c); } $template = sprintf('grid-template-columns:%s;', $str); $counter=0; $new = sprintf('
',$template); foreach($contents as $part) { $counter++; if (count($request) >= 4) { $part=str_replace([$request[2],$request[3]],["{|","|}"],$part); $part=$this->content_element_dispatcher($part); } $new .= sprintf("
\n%s\n
", $md->text($part) ); } $new.="
"; break; case 'page': array_shift($request); $target = array_shift($request); $class = array_shift($request); $folder = $this->folder.$target."/"; $anchor_name=array_pop(explode("/",$target)); $fff = new \Modules\FilesInFolders( $folder, array( 'content'=>array( 'secondary'=>'secondary', 'zzz'=>'hidden', 'unpublish'=>'hidden' )) ); $fff->prepare_files(); $fff->fill_content(); $new = sprintf("
\n%s\n
", $class, $anchor_name, implode("\n",$fff->content['default'])); break; case 'youtube': $vid=array_shift($request); $pos= array_shift($request); if( in_array($pos,array('left','right','full'))) { $class = $pos; } else { $class = 'left'; } $video=sprintf("", $vid); $thumbnail = sprintf("
" ."\"video-preview\"/" ."\"play-button\"" ."
%s
", "https://www.youtube.com/watch?v=".$vid, $vid, $vid, "/rsc/img/play-button.png", $vid, $video ); foreach ($body as $k=>$line) { if (strpos($line,"©") !== FALSE || strpos($line,"©") !== FALSE) { $body[$k] = sprintf("%s",$line); } } $new=sprintf("
" ."
%s
" ."
%s
" ."
", $class, $thumbnail, $md->text(implode("\n",$body))); break; default: $new=self::warn("Content Module \"".$request[0]."\" unknown"); break; } $string = str_replace($matches[0][$i],$new,$string); } return $string; } function warn($message) { return sprintf("
%s
",$message); } }