From 5de31e894436d2de83af3c5eeb3f33eeaa54e84f Mon Sep 17 00:00:00 2001 From: Gargaj Date: Sun, 5 May 2019 14:30:19 +0200 Subject: [PATCH] fix a few sqllib bugs, add field to reorder menu (#2, not fully done yet) --- contentifier.min.php | 2 +- contentifier.php | 12 ++++++++---- contentifier/contentifier-admin.inc.php | 6 +++++- contentifier/sqllib.inc.php | 6 +++--- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/contentifier.min.php b/contentifier.min.php index b72f46e..027fe98 100644 --- a/contentifier.min.php +++ b/contentifier.min.php @@ -1 +1 @@ -query=$query;}public function __toString(){$e.=date("Y-m-d H:i:s");$e.="\nError: ".$this->getMessage()."\n";$e.="\nQuery: ".$this->query."\n";$e.="\nTrace: ".$this->getTraceAsString();return$e;}}class SQLLib{public static$link;public static$debugMode=false;public static$charset="";public$queries=array();public function Connect($dsn,$username=null,$password=null,$options=null){try{$this->link=new PDO($dsn,$username,$password,$options);}catch(PDOException$e){die("Unable to connect SQLite with PDO: ".$e->getMessage());}$this->link->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);$this->link->setAttribute(PDO::ATTR_STRINGIFY_FETCHES,false);}public function Disconnect(){$this->link=null;}public function Query($cmd){global$SQLLIB_QUERIES;if($this->debugMode){$start=microtime(true);$r=@$this->link->query($cmd);if(!$r)throw new SQLLibException(implode("\n",$this->link->errorInfo()),0,$cmd);$end=microtime(true);$SQLLIB_QUERIES[$cmd]=$end-$start;}else{$r=@$this->link->query($cmd);if(!$r)throw new SQLLibException(implode("\n",$this->link->errorInfo()),0,$cmd);$SQLLIB_QUERIES[]="*";}return$r;}public function Fetch($r){return$r->fetchObject();}public function SelectRows($cmd){$r=$this->Query($cmd);$a=Array();while($o=$this->Fetch($r))$a[]=$o;return$a;}public function SelectRow($cmd){if(stristr($cmd,"select ")!==false&&stristr($cmd," limit ")===false)$cmd.=" LIMIT 1";$r=$this->Query($cmd);$a=$this->Fetch($r);return$a;}public function InsertRow($table,$o){global$SQLLIB_ARRAYS_CLEANED;if(!$SQLLIB_ARRAYS_CLEANED)trigger_error("Arrays not cleaned before InsertRow!",E_USER_ERROR);if(is_object($o))$a=get_object_vars($o);else if(is_array($o))$a=$o;$keys=Array();$values=Array();foreach($a as$k=>$v){$keys[]=$this->Quote($k);if($v!==NULL)$values[]="'".$this->Quote($v)."'";else$values[]="null";}$cmd=sprintf("insert into %s (%s) values (%s)",$table,implode(", ",$keys),implode(", ",$values));$r=$this->Query($cmd);return$this->link->lastInsertId();}public function UpdateRow($table,$o,$where){global$SQLLIB_ARRAYS_CLEANED;if(!$SQLLIB_ARRAYS_CLEANED)trigger_error("Arrays not cleaned before UpdateRow!",E_USER_ERROR);if(is_object($o))$a=get_object_vars($o);else if(is_array($o))$a=$o;$set=Array();foreach($a as$k=>$v){if($v===NULL){$set[]=sprintf("%s=null",$this->Quote($k));}else{$set[]=sprintf("%s='%s'",$this->Quote($k),$this->Quote($v));}}$cmd=sprintf("update %s set %s where %s",$table,implode(", ",$set),$where);$this->Query($cmd);}public function UpdateRowMulti($table,$key,$tuples){if(!count($tuples))return;if(!is_array($tuples[0]))throw new Exception("Has to be array!");$fields=array_keys($tuples[0]);$sql="UPDATE ".$table;$keys=array();foreach($fields as$field){if($field==$key)continue;foreach($tuples as$tuple)$cond.=sprintf_esc(" WHEN %d THEN '%s' ",$tuple[$key],$tuple[$field]);$sql.=" SET `".$field."` = (CASE `".$key."` ".$cond." END)";}foreach($tuples as$tuple)$keys[]=$tuple[$key];$sql.=" WHERE `".$key."` IN (".implode(",",$keys).")";$this->Query($sql);}public function UpdateOrInsertRow($table,$o,$where){if($this->SelectRow(sprintf("SELECT * FROM %s WHERE %s",$table,$where)))return$this->UpdateRow($table,$o,$where);else return$this->InsertRow($table,$o);}public function StartTransaction(){}public function FinishTransaction(){}public function CancelTransaction(){}public function Quote($string){return substr($this->link->quote($string),1,-1);}public function Escape($string){$args=func_get_args();for($key=1;$keyQuote($args[$key]);}return call_user_func_array("sprintf",$args);}}class SQLTrans{var$rollback;function __construct(){$this->StartTransaction();$rollback=false;}function Rollback(){$this->rollback=true;}function __destruct(){if(!$rollback)$this->FinishTransaction();else$this->CancelTransaction();}}class SQLSelect{var$fields;var$tables;var$conditions;var$joins;var$orders;var$groups;var$limit;var$offset;function __construct(){$this->fields=array();$this->tables=array();$this->conditions=array();$this->joins=array();$this->orders=array();$this->groups=array();$this->limit=NULL;$this->offset=NULL;}function AddTable($s){$this->tables[]=$s;}function AddField($s){$this->fields[]=$s;}function AddJoin($type,$table,$condition){$o=new stdClass();$o->type=$type;$o->table=$table;$o->condition=$condition;$this->joins[]=$o;}function AddWhere($s){$this->conditions[]="(".$s.")";}function AddOrder($s){$this->orders[]=$s;}function AddGroup($s){$this->groups[]=$s;}function SetLimit($limit,$offset=NULL){$this->limit=(int)$limit;if($offset!==NULL)$this->offset=(int)$offset;}function GetQuery(){if(!count($this->tables))throw new Exception("[sqlselect] No tables specified!");$sql="SELECT ";if($this->fields){$sql.=implode(", ",$this->fields);}else{$sql.=" * ";}$sql.=" FROM ".implode(", ",$this->tables);if($this->joins){foreach($this->joins as$v){$sql.=" ".$v->type." JOIN ".$v->table." ON ".$v->condition;}}if($this->conditions)$sql.=" WHERE ".implode(" AND ",$this->conditions);if($this->groups)$sql.=" GROUP BY ".implode(", ",$this->groups);if($this->orders)$sql.=" ORDER BY ".implode(", ",$this->orders);if($this->offset!==NULL){$sql.=" LIMIT ".$this->offset.", ".$this->limit;}else if($this->limit!==NULL){$sql.=" LIMIT ".$this->limit;}return$sql;}}function sprintf_esc(){$args=func_get_args();reset($args);next($args);while(list($key,$value)=each($args))$args[$key]=$this->Quote($args[$key]);return call_user_func_array("sprintf",$args);}function nop($s){return$s;}function clearArray($a){$ar=array();$qcb=get_magic_quotes_gpc()?"stripslashes":"nop";foreach($a as$k=>$v)if(is_array($v))$ar[$k]=clearArray($v);else$ar[$k]=$qcb($v);return$ar;}$_POST=clearArray($_POST);$_GET=clearArray($_GET);$_REQUEST=clearArray($_REQUEST);$SQLLIB_ARRAYS_CLEANED=true;trait ContentifierAdmin{function isloggedinasadmin(){@session_start();if($_POST["login"]&&$_SESSION["contentifier_token"]==$_POST["token"]){$user=$this->sql->selectRow($this->sql->escape("select * from users where username='%s'",$_POST["username"]));if(password_verify($_POST["password"],$user->password)){$_SESSION["contentifier_userID"]=$user->id;return true;}}return$this->sql->selectRow($this->sql->escape("select * from users where id='%d'",$_SESSION["contentifier_userID"]));}function renderadmin_loginform(){$token=rand(1,999999);$_SESSION["contentifier_token"]=$token;$output.="
";$output.="";$output.="";$output.="";$output.="";$output.="";$output.="";$output.="
";return$output;}function renderadmin(){$output="\nContentifier Admin

Contentifier Admin

";if(!$this->isloggedinasadmin()){$output.="
";$output.=$this->renderadmin_loginform();}else{$output.="
";switch($_GET["section"]){case"logout":{unset($_SESSION["contentifier_userID"]);$this->redirect($this->buildurl("/"));}break;case"menu":{if($_POST["deleteMenu"]){$this->sql->query($this->sql->escape("delete from menu where id=%d",$_POST["menuID"]));$this->redirect($this->buildurl("admin",array("section"=>"menu")));}else if($_POST["submitMenu"]){$a=array("label"=>$_POST["label"],"url"=>$_POST["url"],);if($_POST["menuID"]){$this->sql->updateRow("menu",$a,$this->sql->escape("id=%d",$_POST["menuID"]));$this->redirect($this->buildurl("admin",array("section"=>"menu","menuID"=>$_POST["userID"])));}else{$id=$this->sql->insertRow("menu",$a);$this->redirect($this->buildurl("admin",array("section"=>"menu","menuID"=>$id)));}}if($_GET["menuID"]||$_GET["add"]=="new"){$menu=$this->sql->selectRow($this->sql->escape("select * from menu where id='%d'",$_GET["menuID"]));$output.="

Menu item: ".$this->escape($menu->label)."

";$output.="
";$output.="";$output.="";$output.="";$output.="";if($_GET["menuID"]){$output.="";}$output.="";$output.="";$output.="
";}else{$menus=$this->sql->selectRows($this->sql->escape("select * from menu order by `order`"));$output.="

Menu

";$output.="";foreach($menus as$menu){$output.="";$output.="";$output.="";$output.="";$output.="";}$output.="";$output.="";$output.="";$output.="
".$this->escape($menu->id)."".$this->escape($menu->label)."".$this->escape($menu->url)."
Add new menu item
";}}break;case"users":{if($_POST["deleteUser"]){$this->sql->query($this->sql->escape("delete from users where id=%d",$_POST["userID"]));$this->redirect($this->buildurl("admin",array("section"=>"users")));}else if($_POST["submitUser"]){$a=array("username"=>$_POST["username"],);if($_POST["userID"]){if($_POST["password"]){$a["password"]=password_hash($_POST["password"],PASSWORD_DEFAULT);}$this->sql->updateRow("users",$a,$this->sql->escape("id=%d",$_POST["userID"]));$this->redirect($this->buildurl("admin",array("section"=>"users","userID"=>$_POST["userID"])));}else{$a["password"]=password_hash($_POST["password"],PASSWORD_DEFAULT);$id=$this->sql->insertRow("users",$a);$this->redirect($this->buildurl("admin",array("section"=>"users","userID"=>$id)));}}if($_GET["userID"]||$_GET["add"]=="new"){$user=$this->sql->selectRow($this->sql->escape("select * from users where id='%d'",$_GET["userID"]));$output.="

User: ".$this->escape($user->username)."

";$output.="
";$output.="";$output.="";$output.="";if($_GET["userID"]){$output.="";$output.="";}else{$output.="";}$output.="";$output.="";$output.="
";}else{$users=$this->sql->selectRows($this->sql->escape("select * from users"));$output.="

Users

";$output.="";foreach($users as$user){$output.="";$output.="";$output.="";$output.="";}$output.="";$output.="";$output.="";$output.="
".$this->escape($user->id)."".$this->escape($user->username)."
Add new user
";}}break;default:{$found=false;foreach($this->plugins as$plugin){if($_GET["section"]==$plugin->id()){$output.=$plugin->admin();$found=true;}}if(!$found){if($_POST["deletePage"]){$this->sql->query($this->sql->escape("delete from pages where id=%d",$_POST["pageID"]));$this->redirect($this->buildurl("admin",array("section"=>"pages")));}else if($_POST["submitPage"]){$a=array("title"=>$_POST["title"],"slug"=>$_POST["slug"],"content"=>$_POST["content"],"format"=>$_POST["format"],);if($_POST["pageID"]){$this->sql->updateRow("pages",$a,$this->sql->escape("id=%d",$_POST["pageID"]));$this->redirect($this->buildurl("admin",array("section"=>"pages","pageID"=>$_POST["pageID"])));}else{$id=$this->sql->insertRow("pages",$a);$this->redirect($this->buildurl("admin",array("section"=>"pages","pageID"=>$id)));}}if($_GET["pageID"]||$_GET["add"]=="new"){$page=$this->sql->selectRow($this->sql->escape("select * from pages where id='%d'",$_GET["pageID"]));$output.="
";$output.="

Page: ".$this->escape($page->title)."

";$output.="";$output.="";$output.="";$output.="";$output.="";$output.="";$output.="";$output.="
";$output.="";$output.="";$output.="
";if($_GET["pageID"]){$output.="";}$output.="";$output.="";$output.="
";}else{$pages=$this->sql->selectRows($this->sql->escape("select * from pages"));$output.="

Pages

";$output.="";foreach($pages as$page){$output.="";$output.="";$output.="";$output.="";$output.="";}$output.="";$output.="";$output.="";$output.="
".$this->escape($page->id)."".$this->escape($page->slug)."".$this->escape($page->title)."
Add new page
";}}}break;}}$output.="
";echo$output;}};abstract class ContentifierPlugin{abstract public function id();abstract public function adminmenuitem();public function admin(){return null;}}abstract class ContentifierPagePlugin extends ContentifierPlugin{abstract public function slugregex();abstract public function content($match);}abstract class ContentifierShortCodePlugin extends ContentifierPlugin{abstract public function shortcode();abstract public function content($params);}abstract class Contentifier{public function sqldsn(){return"mysql:host=localhost;dbname=contentifier";}public function sqluser(){return"contentifier";}abstract public function sqlpass();public function sqloptions(){return array();}public function templatefile(){return"template.html";}public function rewriteenabled(){return false;}public function rooturl(){return$this->rootURL;}public function slug(){return$this->slug;}private$plugins=array();use ContentifierAdmin;function escape($s){return htmlspecialchars($s,ENT_QUOTES);}function buildurl($slug,$params=array()){if($slug=="/")$slug="";if($this->rewriteenabled()){return$this->rooturl().($slug?$slug."/":"").($params?"?".http_build_query($params):"");}else{$params["page"]=$slug;return$this->rooturl()."?".http_build_query($params);}}function redirect($url){header("Location: ".$url);exit();}function initurls(){$this->url=($_SERVER["HTTPS"]=="on"?"https":"http")."://".$_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"];$dir=dirname($_SERVER["PHP_SELF"]);$this->rootRelativeURL=$_SERVER['REQUEST_URI'];if(strlen($dir)>1){$this->rootRelativeURL=substr($this->rootRelativeURL,strlen($dir));}list($this->rootRelativePath,)=explode("?",$this->rootRelativeURL);$this->rootURL=substr($this->url,0,-strlen($this->rootRelativeURL))."/";}function extractslug(){$this->slug="";if($this->rewriteenabled()){$this->slug=trim($this->rootRelativePath,'/');}else{$this->slug=$_GET["page"];}if(!$this->slug){$this->slug="index";}}function menu(){$rows=$this->sql->selectRows($this->sql->escape("select * from menu order by `order`"));if($rows){$out="
    ";foreach($rows as$row){$url=$row->url;if(strstr($url,"://")===false){$url=$this->buildurl(trim($url,"/"));}$out.="
  • ";$out.="".$this->escape($row->label)."";$out.="
  • ";}$out.="
";}return$out;}function addplugin($instance){if(is_a($instance,"ContentifierPlugin")){$this->plugins[]=$instance;}}function content($slug=null){$slug=$slug?:$this->slug;foreach($this->plugins as$plugin){if(is_a($plugin,"ContentifierPagePlugin")&&preg_match("/".$plugin->slugregex()."/",$slug,$match)){return$plugin->content($match);}}$row=$this->getpagebyslug($slug);if($row){$content=$row->content;foreach($this->plugins as$plugin){if(is_a($plugin,"ContentifierShortCodePlugin")){$content=preg_replace_callback("/\{\{".$plugin->shortcode()."\|?(.*)\}\}/",function($matches)use($plugin){return$plugin->content(explode("|",$matches[1]));},$content);}}switch($row->format){case"text":$content=nl2br($this->escape($content));break;}return$content;}return false;}function contenttokens(){$content=$this->content();if($content===false||$content===null){header("HTTP/1.1 404 Not Found");$content="

404

Page '".$this->escape($this->slug)."' not found

";}return array("{%MENU%}"=>$this->menu(),"{%CONTENT%}"=>$content,"{%ROOTURL%}"=>$this->rooturl(),"{%SLUG%}"=>$this->slug(),);}function template(){return file_exists($this->templatefile())?file_get_contents($this->templatefile()):"\n{%CONTENT%}";}function render(){$tokens=$this->contenttokens();$template=$this->template();$template=str_replace(array_keys($tokens),array_values($tokens),$template);echo$template;}public function getpagebyslug($slug){return$this->sql->selectRow($this->sql->escape("select * from pages where slug='%s'",$slug));}public function bootstrap(){if(!class_exists("PDO"))die("Contentifier runs on PDO - please install it");$this->sql=new SQLLib();$this->sql->Connect($this->sqldsn(),$this->sqluser(),$this->sqlpass(),$this->sqloptions());}public function install(){$this->bootstrap();$output="\nContentifier Install

Contentifier Installation

";if($_POST["username"]&&$_POST["password"]){$isMysql=strstr($this->sqldsn(),"mysql")!==false;$primary=$isMysql?"int(11) PRIMARY KEY NOT NULL AUTO_INCREMENT":"INTEGER PRIMARY KEY AUTOINCREMENT";$enum=$isMysql?"enum('text','html','wiki') NOT NULL DEFAULT 'text'":"text";$init=array("CREATE TABLE `menu` ( `id` ".$primary.", `order` int(11) NOT NULL DEFAULT '0', `label` varchar(128) NOT NULL, `url` varchar(256) NOT NULL);","CREATE TABLE `pages` ( `id` ".$primary.", `slug` varchar(128) NOT NULL UNIQUE, `title` text NOT NULL, `content` text NOT NULL, `format` ".$enum.");","CREATE TABLE `users` ( `id` ".$primary.", `username` varchar(64) NOT NULL UNIQUE, `password` varchar(128) NOT NULL);");foreach($init as$v)$this->sql->Query($v);$this->sql->insertRow("users",array("username"=>$_POST["username"],"password"=>password_hash($_POST["password"],PASSWORD_DEFAULT)));$output.="

Installation successful; now replace the \$...->install() in your main entry point file with \$...->run() and load the admin to add some content.

";}else{$output.="

Create your first user

";}$output.="";echo$output;}public function run(){$this->bootstrap();$this->initurls();$this->extractslug();if($this->slug=="admin"){$this->renderadmin();}else{$this->render();}}}?> \ No newline at end of file +query=$query;}public function __toString(){$e.=date("Y-m-d H:i:s");$e.="\nError: ".$this->getMessage()."\n";$e.="\nQuery: ".$this->query."\n";$e.="\nTrace: ".$this->getTraceAsString();return$e;}}class SQLLib{public static$link;public static$debugMode=false;public static$charset="";public$queries=array();public function Connect($dsn,$username=null,$password=null,$options=null){try{$this->link=new PDO($dsn,$username,$password,$options);}catch(PDOException$e){die("Unable to connect SQLite with PDO: ".$e->getMessage());}$this->link->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);$this->link->setAttribute(PDO::ATTR_STRINGIFY_FETCHES,false);}public function Disconnect(){$this->link=null;}public function Query($cmd){global$SQLLIB_QUERIES;if($this->debugMode){$start=microtime(true);$r=@$this->link->query($cmd);if(!$r)throw new SQLLibException(implode("\n",$this->link->errorInfo()),0,$cmd);$end=microtime(true);$SQLLIB_QUERIES[$cmd]=$end-$start;}else{$r=@$this->link->query($cmd);if(!$r)throw new SQLLibException(implode("\n",$this->link->errorInfo()),0,$cmd);$SQLLIB_QUERIES[]="*";}return$r;}public function Fetch($r){return$r->fetchObject();}public function SelectRows($cmd){$r=$this->Query($cmd);$a=Array();while($o=$this->Fetch($r))$a[]=$o;return$a;}public function SelectRow($cmd){if(stristr($cmd,"select ")!==false&&stristr($cmd," limit ")===false)$cmd.=" LIMIT 1";$r=$this->Query($cmd);$a=$this->Fetch($r);return$a;}public function InsertRow($table,$o){global$SQLLIB_ARRAYS_CLEANED;if(!$SQLLIB_ARRAYS_CLEANED)trigger_error("Arrays not cleaned before InsertRow!",E_USER_ERROR);if(is_object($o))$a=get_object_vars($o);else if(is_array($o))$a=$o;$keys=Array();$values=Array();foreach($a as$k=>$v){$keys[]="`".$this->Quote($k)."`";if($v!==NULL)$values[]="'".$this->Quote($v)."'";else$values[]="null";}$cmd=sprintf("insert into %s (%s) values (%s)",$table,implode(", ",$keys),implode(", ",$values));$r=$this->Query($cmd);return$this->link->lastInsertId();}public function UpdateRow($table,$o,$where){global$SQLLIB_ARRAYS_CLEANED;if(!$SQLLIB_ARRAYS_CLEANED)trigger_error("Arrays not cleaned before UpdateRow!",E_USER_ERROR);if(is_object($o))$a=get_object_vars($o);else if(is_array($o))$a=$o;$set=Array();foreach($a as$k=>$v){if($v===NULL){$set[]=sprintf("`%s`=null",$this->Quote($k));}else{$set[]=sprintf("`%s`='%s'",$this->Quote($k),$this->Quote($v));}}$cmd=sprintf("update %s set %s where %s",$table,implode(", ",$set),$where);$this->Query($cmd);}public function UpdateRowMulti($table,$key,$tuples){if(!count($tuples))return;if(!is_array($tuples[0]))throw new Exception("Has to be array!");$fields=array_keys($tuples[0]);$sql="UPDATE ".$table;$keys=array();foreach($fields as$field){if($field==$key)continue;foreach($tuples as$tuple)$cond.=sprintf_esc(" WHEN %d THEN '%s' ",$tuple[$key],$tuple[$field]);$sql.=" SET `".$field."` = (CASE `".$key."` ".$cond." END)";}foreach($tuples as$tuple)$keys[]=$tuple[$key];$sql.=" WHERE `".$key."` IN (".implode(",",$keys).")";$this->Query($sql);}public function UpdateOrInsertRow($table,$o,$where){if($this->SelectRow(sprintf("SELECT * FROM %s WHERE %s",$table,$where)))return$this->UpdateRow($table,$o,$where);else return$this->InsertRow($table,$o);}public function StartTransaction(){}public function FinishTransaction(){}public function CancelTransaction(){}public function Quote($string){return substr($this->link->quote($string),1,-1);}public function Escape($string){$args=func_get_args();for($key=1;$keyQuote($args[$key]);}return call_user_func_array("sprintf",$args);}}class SQLTrans{var$rollback;function __construct(){$this->StartTransaction();$rollback=false;}function Rollback(){$this->rollback=true;}function __destruct(){if(!$rollback)$this->FinishTransaction();else$this->CancelTransaction();}}class SQLSelect{var$fields;var$tables;var$conditions;var$joins;var$orders;var$groups;var$limit;var$offset;function __construct(){$this->fields=array();$this->tables=array();$this->conditions=array();$this->joins=array();$this->orders=array();$this->groups=array();$this->limit=NULL;$this->offset=NULL;}function AddTable($s){$this->tables[]=$s;}function AddField($s){$this->fields[]=$s;}function AddJoin($type,$table,$condition){$o=new stdClass();$o->type=$type;$o->table=$table;$o->condition=$condition;$this->joins[]=$o;}function AddWhere($s){$this->conditions[]="(".$s.")";}function AddOrder($s){$this->orders[]=$s;}function AddGroup($s){$this->groups[]=$s;}function SetLimit($limit,$offset=NULL){$this->limit=(int)$limit;if($offset!==NULL)$this->offset=(int)$offset;}function GetQuery(){if(!count($this->tables))throw new Exception("[sqlselect] No tables specified!");$sql="SELECT ";if($this->fields){$sql.=implode(", ",$this->fields);}else{$sql.=" * ";}$sql.=" FROM ".implode(", ",$this->tables);if($this->joins){foreach($this->joins as$v){$sql.=" ".$v->type." JOIN ".$v->table." ON ".$v->condition;}}if($this->conditions)$sql.=" WHERE ".implode(" AND ",$this->conditions);if($this->groups)$sql.=" GROUP BY ".implode(", ",$this->groups);if($this->orders)$sql.=" ORDER BY ".implode(", ",$this->orders);if($this->offset!==NULL){$sql.=" LIMIT ".$this->offset.", ".$this->limit;}else if($this->limit!==NULL){$sql.=" LIMIT ".$this->limit;}return$sql;}}function sprintf_esc(){$args=func_get_args();reset($args);next($args);while(list($key,$value)=each($args))$args[$key]=$this->Quote($args[$key]);return call_user_func_array("sprintf",$args);}function nop($s){return$s;}function clearArray($a){$ar=array();$qcb=get_magic_quotes_gpc()?"stripslashes":"nop";foreach($a as$k=>$v)if(is_array($v))$ar[$k]=clearArray($v);else$ar[$k]=$qcb($v);return$ar;}$_POST=clearArray($_POST);$_GET=clearArray($_GET);$_REQUEST=clearArray($_REQUEST);$SQLLIB_ARRAYS_CLEANED=true;trait ContentifierAdmin{function isloggedinasadmin(){@session_start();if($_POST["login"]&&$_SESSION["contentifier_token"]==$_POST["token"]){$user=$this->sql->selectRow($this->sql->escape("select * from users where username='%s'",$_POST["username"]));if(password_verify($_POST["password"],$user->password)){$_SESSION["contentifier_userID"]=$user->id;return true;}}return$this->sql->selectRow($this->sql->escape("select * from users where id='%d'",$_SESSION["contentifier_userID"]));}function renderadmin_loginform(){$token=rand(1,999999);$_SESSION["contentifier_token"]=$token;$output.="
";$output.="";$output.="";$output.="";$output.="";$output.="";$output.="";$output.="
";return$output;}function renderadmin(){$output="\nContentifier Admin

Contentifier Admin

";if(!$this->isloggedinasadmin()){$output.="
";$output.=$this->renderadmin_loginform();}else{$output.="
";switch($_GET["section"]){case"logout":{unset($_SESSION["contentifier_userID"]);$this->redirect($this->buildurl("/"));}break;case"menu":{if($_POST["deleteMenu"]){$this->sql->query($this->sql->escape("delete from menu where id=%d",$_POST["menuID"]));$this->redirect($this->buildurl("admin",array("section"=>"menu")));}else if($_POST["submitMenu"]){$a=array("label"=>$_POST["label"],"url"=>$_POST["url"],"order"=>(int)$_POST["order"],);if($_POST["menuID"]){$this->sql->updateRow("menu",$a,$this->sql->escape("id=%d",$_POST["menuID"]));$this->redirect($this->buildurl("admin",array("section"=>"menu","menuID"=>$_POST["userID"])));}else{$id=$this->sql->insertRow("menu",$a);$this->redirect($this->buildurl("admin",array("section"=>"menu","menuID"=>$id)));}}if($_GET["menuID"]||$_GET["add"]=="new"){$menu=$this->sql->selectRow($this->sql->escape("select * from menu where id='%d'",$_GET["menuID"]));$output.="

Menu item: ".$this->escape($menu->label)."

";$output.="
";$output.="";$output.="";$output.="";$output.="";$output.="";$output.="";if($_GET["menuID"]){$output.="";}$output.="";$output.="";$output.="
";}else{$menus=$this->sql->selectRows($this->sql->escape("select * from menu order by `order`"));$output.="

Menu

";$output.="";foreach($menus as$menu){$output.="";$output.="";$output.="";$output.="";$output.="";$output.="";}$output.="";$output.="";$output.="";$output.="
".$this->escape($menu->id)."".$this->escape($menu->label)."".$this->escape($menu->url)."".$this->escape($menu->order)."
Add new menu item
";}}break;case"users":{if($_POST["deleteUser"]){$this->sql->query($this->sql->escape("delete from users where id=%d",$_POST["userID"]));$this->redirect($this->buildurl("admin",array("section"=>"users")));}else if($_POST["submitUser"]){$a=array("username"=>$_POST["username"],);if($_POST["userID"]){if($_POST["password"]){$a["password"]=password_hash($_POST["password"],PASSWORD_DEFAULT);}$this->sql->updateRow("users",$a,$this->sql->escape("id=%d",$_POST["userID"]));$this->redirect($this->buildurl("admin",array("section"=>"users","userID"=>$_POST["userID"])));}else{$a["password"]=password_hash($_POST["password"],PASSWORD_DEFAULT);$id=$this->sql->insertRow("users",$a);$this->redirect($this->buildurl("admin",array("section"=>"users","userID"=>$id)));}}if($_GET["userID"]||$_GET["add"]=="new"){$user=$this->sql->selectRow($this->sql->escape("select * from users where id='%d'",$_GET["userID"]));$output.="

User: ".$this->escape($user->username)."

";$output.="
";$output.="";$output.="";$output.="";if($_GET["userID"]){$output.="";$output.="";}else{$output.="";}$output.="";$output.="";$output.="
";}else{$users=$this->sql->selectRows($this->sql->escape("select * from users"));$output.="

Users

";$output.="";foreach($users as$user){$output.="";$output.="";$output.="";$output.="";}$output.="";$output.="";$output.="";$output.="
".$this->escape($user->id)."".$this->escape($user->username)."
Add new user
";}}break;default:{$found=false;foreach($this->plugins as$plugin){if($_GET["section"]==$plugin->id()){$output.=$plugin->admin();$found=true;}}if(!$found){if($_POST["deletePage"]){$this->sql->query($this->sql->escape("delete from pages where id=%d",$_POST["pageID"]));$this->redirect($this->buildurl("admin",array("section"=>"pages")));}else if($_POST["submitPage"]){$a=array("title"=>$_POST["title"],"slug"=>$_POST["slug"],"content"=>$_POST["content"],"format"=>$_POST["format"],);if($_POST["pageID"]){$this->sql->updateRow("pages",$a,$this->sql->escape("id=%d",$_POST["pageID"]));$this->redirect($this->buildurl("admin",array("section"=>"pages","pageID"=>$_POST["pageID"])));}else{$id=$this->sql->insertRow("pages",$a);$this->redirect($this->buildurl("admin",array("section"=>"pages","pageID"=>$id)));}}if($_GET["pageID"]||$_GET["add"]=="new"){$page=$this->sql->selectRow($this->sql->escape("select * from pages where id='%d'",$_GET["pageID"]));$output.="
";$output.="

Page: ".$this->escape($page->title)."

";$output.="";$output.="";$output.="";$output.="";$output.="";$output.="";$output.="";$output.="
";$output.="";$output.="";$output.="
";if($_GET["pageID"]){$output.="";}$output.="";$output.="";$output.="
";}else{$pages=$this->sql->selectRows($this->sql->escape("select * from pages"));$output.="

Pages

";$output.="";foreach($pages as$page){$output.="";$output.="";$output.="";$output.="";$output.="";}$output.="";$output.="";$output.="";$output.="
".$this->escape($page->id)."".$this->escape($page->slug)."".$this->escape($page->title)."
Add new page
";}}}break;}}$output.="
";echo$output;}};abstract class ContentifierPlugin{abstract public function id();abstract public function adminmenuitem();public function admin(){return null;}}abstract class ContentifierPagePlugin extends ContentifierPlugin{abstract public function slugregex();abstract public function content($match);}abstract class ContentifierShortCodePlugin extends ContentifierPlugin{abstract public function shortcode();abstract public function content($params);}abstract class Contentifier{public function sqldsn(){return"mysql:host=localhost;dbname=contentifier";}public function sqluser(){return"contentifier";}abstract public function sqlpass();public function sqloptions(){return array();}public function templatefile(){return"template.html";}public function rewriteenabled(){return false;}public function rooturl(){return$this->rootURL;}public function slug(){return$this->slug;}private$plugins=array();use ContentifierAdmin;function escape($s){return htmlspecialchars($s,ENT_QUOTES);}function buildurl($slug,$params=array()){if($slug=="/")$slug="";if($this->rewriteenabled()){return$this->rooturl().($slug?$slug."/":"").($params?"?".http_build_query($params):"");}else{$params["page"]=$slug;return$this->rooturl()."?".http_build_query($params);}}function redirect($url){header("Location: ".$url);exit();}function initurls(){$this->url=($_SERVER["HTTPS"]=="on"?"https":"http")."://".$_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"];$dir=dirname($_SERVER["PHP_SELF"]);$this->rootRelativeURL=$_SERVER['REQUEST_URI'];if(strlen($dir)>1){$this->rootRelativeURL=substr($this->rootRelativeURL,strlen($dir));}list($this->rootRelativePath,)=explode("?",$this->rootRelativeURL);$this->rootURL=substr($this->url,0,-strlen($this->rootRelativeURL))."/";}function extractslug(){$this->slug="";if($this->rewriteenabled()){$this->slug=trim($this->rootRelativePath,'/');}else{$this->slug=$_GET["page"];}if(!$this->slug){$this->slug="index";}}function menu(){$rows=$this->sql->selectRows($this->sql->escape("select * from menu order by `order`"));if($rows){$out="
    ";foreach($rows as$row){$url=$row->url;if(strstr($url,"://")===false){$url=$this->buildurl(trim($url,"/"));}$out.="
  • ";$out.="".$this->escape($row->label)."";$out.="
  • ";}$out.="
";}return$out;}function addplugin($instance){if(is_a($instance,"ContentifierPlugin")){$this->plugins[]=$instance;}}function content($slug=null){$slug=$slug?:$this->slug;foreach($this->plugins as$plugin){if(is_a($plugin,"ContentifierPagePlugin")&&preg_match("/".$plugin->slugregex()."/",$slug,$match)){return$plugin->content($match);}}$row=$this->getpagebyslug($slug);if($row){$content=$row->content;foreach($this->plugins as$plugin){if(is_a($plugin,"ContentifierShortCodePlugin")){$content=preg_replace_callback("/\{\{".$plugin->shortcode()."\|?(.*)\}\}/",function($matches)use($plugin){return$plugin->content(explode("|",$matches[1]));},$content);}}switch($row->format){case"text":$content=nl2br($this->escape($content));break;}return$content;}return false;}function contenttokens(){$content=$this->content();if($content===false||$content===null){header("HTTP/1.1 404 Not Found");$content="

404

Page '".$this->escape($this->slug)."' not found

";}return array("{%MENU%}"=>$this->menu(),"{%CONTENT%}"=>$content,"{%ROOTURL%}"=>$this->rooturl(),"{%SLUG%}"=>$this->slug(),);}function template(){return file_exists($this->templatefile())?file_get_contents($this->templatefile()):"\n{%CONTENT%}";}function render(){$tokens=$this->contenttokens();$template=$this->template();$template=str_replace(array_keys($tokens),array_values($tokens),$template);echo$template;}public function getpagebyslug($slug){return$this->sql->selectRow($this->sql->escape("select * from pages where slug='%s'",$slug));}public function bootstrap(){if(!class_exists("PDO"))die("Contentifier runs on PDO - please install it");$this->sql=new SQLLib();$this->sql->Connect($this->sqldsn(),$this->sqluser(),$this->sqlpass(),$this->sqloptions());}public function install(){$this->bootstrap();$output="\nContentifier Install

Contentifier Installation

";if($_POST["username"]&&$_POST["password"]){$isMysql=strstr($this->sqldsn(),"mysql")!==false;$primary=$isMysql?"int(11) PRIMARY KEY NOT NULL AUTO_INCREMENT":"INTEGER PRIMARY KEY AUTOINCREMENT";$enum=$isMysql?"enum('text','html','wiki') NOT NULL DEFAULT 'text'":"text";$init=array("CREATE TABLE `menu` ( `id` ".$primary.", `order` int(11) NOT NULL DEFAULT '0', `label` varchar(128) NOT NULL, `url` varchar(256) NOT NULL);","CREATE TABLE `pages` ( `id` ".$primary.", `slug` varchar(128) NOT NULL UNIQUE, `title` text NOT NULL, `content` text NOT NULL, `format` ".$enum.");","CREATE TABLE `users` ( `id` ".$primary.", `username` varchar(64) NOT NULL UNIQUE, `password` varchar(128) NOT NULL);");foreach($init as$v)$this->sql->Query($v);$this->sql->insertRow("users",array("username"=>$_POST["username"],"password"=>password_hash($_POST["password"],PASSWORD_DEFAULT)));$output.="

Installation successful; now replace the \$...->install() in your main entry point file with \$...->run() and load the admin to add some content.

";}else{$output.="

Create your first user

";}$output.="";echo$output;}public function run(){$this->bootstrap();$this->initurls();$this->extractslug();if($this->slug=="admin"){$this->renderadmin();}else{$this->render();}}}?> \ No newline at end of file diff --git a/contentifier.php b/contentifier.php index 0c82f91..8caca40 100644 --- a/contentifier.php +++ b/contentifier.php @@ -87,7 +87,7 @@ public function InsertRow($table,$o) $keys = Array(); $values = Array(); foreach($a as $k=>$v) { - $keys[]=$this->Quote($k); + $keys[]="`".$this->Quote($k)."`"; if ($v!==NULL) $values[]="'".$this->Quote($v)."'"; else $values[]="null"; } @@ -107,11 +107,11 @@ public function UpdateRow($table,$o,$where) foreach($a as $k=>$v) { if ($v===NULL) { - $set[] = sprintf("%s=null",$this->Quote($k)); + $set[] = sprintf("`%s`=null",$this->Quote($k)); } else { - $set[] = sprintf("%s='%s'",$this->Quote($k),$this->Quote($v)); + $set[] = sprintf("`%s`='%s'",$this->Quote($k),$this->Quote($v)); } } $cmd = sprintf("update %s set %s where %s", @@ -402,6 +402,7 @@ function renderadmin() $a = array( "label"=>$_POST["label"], "url"=>$_POST["url"], + "order"=>(int)$_POST["order"], ); if ($_POST["menuID"]) { @@ -423,6 +424,8 @@ function renderadmin() $output .= ""; $output .= ""; $output .= ""; + $output .= ""; + $output .= ""; if ($_GET["menuID"]) { $output .= ""; @@ -442,10 +445,11 @@ function renderadmin() $output .= "".$this->escape($menu->id).""; $output .= "".$this->escape($menu->label).""; $output .= "".$this->escape($menu->url).""; + $output .= "".$this->escape($menu->order).""; $output .= ""; } $output .= ""; - $output .= "Add new menu item"; + $output .= "Add new menu item"; $output .= ""; $output .= ""; } diff --git a/contentifier/contentifier-admin.inc.php b/contentifier/contentifier-admin.inc.php index 7b14e29..42d2b06 100644 --- a/contentifier/contentifier-admin.inc.php +++ b/contentifier/contentifier-admin.inc.php @@ -101,6 +101,7 @@ function renderadmin() $a = array( "label"=>$_POST["label"], "url"=>$_POST["url"], + "order"=>(int)$_POST["order"], ); if ($_POST["menuID"]) { @@ -122,6 +123,8 @@ function renderadmin() $output .= ""; $output .= ""; $output .= ""; + $output .= ""; + $output .= ""; if ($_GET["menuID"]) { $output .= ""; @@ -141,10 +144,11 @@ function renderadmin() $output .= "".$this->escape($menu->id).""; $output .= "".$this->escape($menu->label).""; $output .= "".$this->escape($menu->url).""; + $output .= "".$this->escape($menu->order).""; $output .= ""; } $output .= ""; - $output .= "Add new menu item"; + $output .= "Add new menu item"; $output .= ""; $output .= ""; } diff --git a/contentifier/sqllib.inc.php b/contentifier/sqllib.inc.php index ceb3a70..39b35a7 100644 --- a/contentifier/sqllib.inc.php +++ b/contentifier/sqllib.inc.php @@ -99,7 +99,7 @@ public function InsertRow($table,$o) $keys = Array(); $values = Array(); foreach($a as $k=>$v) { - $keys[]=$this->Quote($k); + $keys[]="`".$this->Quote($k)."`"; if ($v!==NULL) $values[]="'".$this->Quote($v)."'"; else $values[]="null"; } @@ -124,11 +124,11 @@ public function UpdateRow($table,$o,$where) foreach($a as $k=>$v) { if ($v===NULL) { - $set[] = sprintf("%s=null",$this->Quote($k)); + $set[] = sprintf("`%s`=null",$this->Quote($k)); } else { - $set[] = sprintf("%s='%s'",$this->Quote($k),$this->Quote($v)); + $set[] = sprintf("`%s`='%s'",$this->Quote($k),$this->Quote($v)); } } $cmd = sprintf("update %s set %s where %s",