<?php
namespace ROF\View;
class Controller {
static public function addScript($scriptPath){
static::$stScripts = array_unique(
array_merge(static::$stScripts, [$scriptPath])
);
}
static public function addStyle($stylePath){
static::$stStyles = array_unique(
array_merge(static::$stStyles, [$stylePath])
);
}
static protected $stStyles = [];
static protected $stScripts = [];
private $content = "";
private $originalContent = [];
private $scripts = [];
private $stylesheets = [];
private $title;
private $keywords;
private $description;
private $image;
private $author;
private $documentRoot;
private $url;
private $type;
private $fb_app_id;
public function __construct($documentRoot){
include_once(__DIR__.'/../lib/simple_html_dom.php');
$this->documentRoot = $documentRoot;
}
public function load($content){
$this->content = $content;
$dom = new \simple_html_dom($this->content);
$c=0;
while ($c++<30&&count($dom->find('view'))>0){
$this->singlePass();
$dom = new \simple_html_dom($this->content);
}
}
private function insertHeadHtml(){
$dom = new \simple_html_dom($this->content);
$outputTags = $dom->find("view[type=output], view[name=Head]");
$staticStyles = static::$stStyles;
static::$stStyles = [];
$this->stylesheets = array_unique(array_merge($this->stylesheets,$staticStyles));
$staticScripts = static::$stScripts;
static::$stScripts = [];
$this->scripts = array_unique(array_merge($this->scripts,$staticScripts));
if (count($outputTags)==0){
$stylesList = '';
foreach ($this->stylesheets as $stylesheet){
if (!file_exists($stylesheet))$stylesheet = ($this->documentRoot.'/Style/'.$stylesheet);
if (!file_exists($stylesheet))throw new \Exception("Stylesheet __".$stylesheet."__ does not exist");
$stylesList .= $stylesheet.',';
}
$scriptList = '';
foreach ($this->scripts as $script){
if (!file_exists($script))$script = ($this->documentRoot.'/Script/'.$script);
if (!file_exists($script))throw new \Exception("Stylesheet __".$script."__ does not exist");
$scriptList .= $script.',';
}
$dataTag = '<view type="self" scripts="'.$scriptList.'" stylesheets="'.$stylesList.'"></view>';
$this->content = $dataTag.$this->content;
} else {
$this->insertHeadHtml2();
}
}
private function insertHeadHtml2(){
// Collects the stylesheets and compiles them into a single, minified file
// Collects the scripts and compiles them into a single, minified file.
// Returns SEO information
// Returns viewport meta tag
$outputHtml = "";
$stylesheet = "";
$stylesName = "css-";
$mostRecentEdit = 0;
foreach ($this->stylesheets as $fileName){
if (file_exists($fileName)){
$file = $fileName;
$fileName = basename($fileName);
} else {
$fileName = basename(parse_url($fileName,PHP_URL_PATH));
$file = $this->documentRoot.'/style/'.$fileName;
}
$stylesName .= $fileName;
if (file_exists($file)){
$editTime = filemtime($file);
if ($editTime>$mostRecentEdit)$mostRecentEdit = $editTime;
if (substr($file,-4)==='.php'){
ob_start();
include($file);
$contents = ob_get_clean();
} else {
$contents = file_get_contents($file);
}
$stylesheet .= $contents;
} else {
$stylesheet = "/* Stylesheet {$file} was not found */\n".$stylesheet;
}
}
$stylesName = str_replace(array('.css','.','?','#',' '),array('-','_','v','h',''),$stylesName);
$stylesName = strtolower(substr($stylesName,0,251).'.css');
$stylesDir = $this->documentRoot.'/view/compiled/';
if (!file_exists($stylesDir))mkdir($stylesDir,0755);
$stylesPath = strtolower($stylesDir.$stylesName);
if (!file_exists($stylesPath)||$mtime=filemtime($stylesPath)<$mostRecentEdit){
file_put_contents($stylesPath,$stylesheet);
}
$outputHtml .= '<link rel="stylesheet" mtype="test/css" href="/compiled/'.$stylesName.'?'.filemtime($stylesPath).'" />'."\n";
$scripts = "";
$scriptsName = "js-";
$mostRecentEdit = 0;
foreach ($this->scripts as $fileName){
if (file_exists($fileName)){
$file = $fileName;
$fileName = basename($fileName);
} else {
$fileName = basename(parse_url($fileName,PHP_URL_PATH));
$file = $this->documentRoot.'/script/'.$fileName;
}
$scriptsName .= $fileName;
if (file_exists($file)){
$editTime = filemtime($file);
if ($editTime>$mostRecentEdit)$mostRecentEdit = $editTime;
if (substr($file,-4)==='.php'){
ob_start();
include($file);
$contents = ob_get_clean();
} else {
$contents = file_get_contents($file);
}
$scripts .= $contents;
} else {
$scripts = "/* Script {$file} was not found */\n".$scripts;
}
}
$scriptsName = str_replace(array('.js','.','?','#',' '),array('-','_','v','h',''),$scriptsName);
$scriptsName = strtolower(substr($scriptsName,0,252).'.js');
$scriptsDir = $this->documentRoot.'/view/compiled/';
if (!file_exists($scriptsDir))mkdir($scriptsDir,0755);
$scriptsPath = strtolower($scriptsDir.$scriptsName);
if (!file_exists($scriptsPath)||filemtime($scriptsPath)<$mostRecentEdit){
file_put_contents($scriptsPath,$scripts);
}
$outputHtml .= '<script type="text/javascript" src="'.'/compiled/'.$scriptsName.'"></script>'."\n";
if ($this->title!=NULL){
$outputHtml .= '<title>'.$this->title.'</title>'."\n"
.'<meta property="og:title" content="'.$this->title.'" />'."\n";
}
if ($this->description!=NULL){
$outputHtml .= '<meta property="og:description" name="description" content="'.$this->description.'">'."\n";
}
if ($this->keywords!=NULL){
$outputHtml .= '<meta property="og:keywords" name="keywords" content="'.$this->keywords.'">'."\n";
}
if ($this->image!=NULL){
$outputHtml .= '<meta property="og:image" content="'.$this->image.'" />'."\n";
}
if ($this->url==NULL){
$this->url = $this->getFullUrl('');
}
if ($this->url!=NULL){
$outputHtml .= '<meta property="og:url" content="'.$this->url.'" />'."\n";
}
if ($this->type!=NULL){
$outputHtml .= '<meta property="og:type" content="'.$this->type.'" />'."\n";
}
if ($this->fb_app_id!=NULL){
$outputHtml .= '<meta property="fb:app_id" content="'.$this->fb_app_id.'" />'."\n";
}
$dom = new \simple_html_dom($this->content);
$outputTags = $dom->find("view[type=output], view[name=Head]");
$c =0;
foreach ($outputTags as $output){
if ($c++>0)throw new \Exception("Error preparing the page..... There were multiple head output views. Only one is allowed. Error reported on line "
.__LINE__." of file ".__FILE__);
$output->outertext = $outputHtml;
}
$this->content = $dom.'';
//output tags are for inserting the head data, so that PHP doesn't have to be written in the html <head> tag.
//Instead a <view type="output"> is put into the head tag, then it is filled in by this script
}
private function discoverInfo($dom){
$this->stylesheets = array_unique(
array_merge($this->stylesheets, $dom->stylesheets!=NULL ? explode(',',$dom->stylesheets) : array())
);
$this->scripts = array_unique(
array_merge($dom->scripts!=NULL ? explode(',',$dom->scripts) : array(),$this->scripts)
);
if ($this->title==NULL&&$dom->title!=NULL){
$this->title = $dom->title;
}
if ($this->image==NULL&&$dom->image!=NULL){
$this->image = $this->getFullUrl($dom->image);
}
if ($this->description==NULL&&$dom->description!=NULL){
$this->description = $dom->description;
}
if ($this->keywords==NULL&&$dom->keywords!=NULL){
$this->keywords = $dom->keywords;
}
if ($this->url==NULL&&$dom->url!=NULL){
$this->url = $this->getFullUrl($dom->url);
}
if ($this->type==NULL&&$dom->ogtype!=NULL){
$this->type = $dom->ogtype;
}
if ($this->fb_app_id==NULL&&$dom->fb_app_id!=NULL){
$this->fb_app_id = $dom->fb_app_id;
}
}
private function singlePass(){
$dom = new \simple_html_dom($this->content);
$headerData = count($_GET)>0 ? $_GET : $_POST;
if (isset($headerData['view_type'])&&strtolower($headerData['view_type'])=='none'){
$viewTags = $dom->find('view');
if (count($viewTags)==1&&trim($viewTags[0]->outertext)==trim($dom->outertext)){
$this->content = $viewTags[0]->innertext;
} else {
foreach ($viewTags as $tag){
$tag->outertext = '<span>'.$tag->innertext.'</span>';
}
$this->content = $dom->outertext;
}
return;
}
$parentTags = $dom->find('view[type=parent]');
$includeTags = $dom->find('view[type=include]');
$childTags = $dom->find('view[type=child]');
$selfTags = $dom->find('view[type=self]');
$dataTags = $dom->find('view[type=data]');
//self tags can contain information about stylesheets, scripts, and meta data.
//self tags provide no visual information. They are data only and the tag must be removed.
foreach ($selfTags as $self){
//echo $self;exit;
$this->discoverInfo($self);
$self->outertext = $self->innertext;
}
static $offset = 0;
foreach ($childTags as $count=>$child){
$this->discoverInfo($child);
$child->outertext = $this->originalContent[$count+$offset];
}
// $this->originalContent = array();
foreach ($parentTags as $parent){
$this->discoverInfo($parent);
$fileContent = $this->getViewFile($parent->name);
$this->originalContent[] = $parent->innertext;
$parent->outertext = $fileContent;
}
foreach ($includeTags as $included){
$this->discoverInfo($included);
$fileContent = $this->getViewFile($included->name);
$included->outertext = $fileContent;
}
$this->content = $dom->outertext;
}
private function getViewFile($viewName){
if ($viewName==FALSE){
throw new \Exception("View Name is empty, so the page can not be created. "
."Web Developer: Please see the script for this page and correct the view tag.");
}
$filePath = $this->documentRoot.'/template/'.$viewName.'.php';
if (!file_exists($filePath)){
throw new \Exception("There has been an error creating the page...... View '{$viewName}' could not be found on the server at path '{$filePath}'. "
."Error reported on line ".__LINE__." in file ".__FILE__);
}
ob_start();
include($filePath);
$fileContent = ob_get_clean();
return $fileContent;
}
public function display(){
$this->insertHeadHtml();
$dom = new \simple_html_dom($this->content);
$residualTags = $dom->find("view");
foreach ($residualTags as $tag){
$tag->outertext = $tag->innertext;
}
echo $dom->outertext;
}
/** $path may be relative or the full url. This function will determine and return an address with protocol://domain/relative_path
* if $path starts with '/' then it will be relative to the protocol://domain
* if $path does NOT start with '/' then it will be relative to the current directory
*/
public function getFullUrl($path){
$protocol = isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] === 'on' || $_SERVER['HTTPS'] === 1) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https' ? 'https' : 'http';
$domain = $_SERVER['HTTP_HOST'];
$start = $protocol.'://'.$domain;
if (strpos($path,'/')!==0){
$path = str_replace('//','/',substr($_SERVER['REQUEST_URI'],0,strrpos($_SERVER['REQUEST_URI'],'/')).'/'.$path);
}
if (strpos($path,$start)!==0){
$path = $start.$path;
}
return $path;
}
public function displayView($viewName){
$content = $this->getViewFile($viewName);
$this->load($content);
$this->display();
}
}
?>