Created
June 20, 2013 14:30
-
-
Save charleyramm/5823217 to your computer and use it in GitHub Desktop.
Source:
http://toys.lerdorf.com/archives/38-The-no-framework-PHP-MVC-framework.html Clean and simple design
#HTML should look like HTML
#Keep the PHP code in the views extremely simple: function calls, simple loops and variable substitutions should be all you need
Secure
#Input validation using pecl/filter as a data firewall
#When possible, avoi…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
include './ui.inc'; // Common View Helper functions | |
include './add_c.inc'; // Controller | |
head(); | |
?> | |
<div id="tItems" class="ta"> | |
<table cellspacing="0" cellpadding="3" width="100%"> | |
<?php foreach($items as $i=>$elem) { | |
$s = $i%2; | |
echo <<<EOB | |
<tr id="{$elem['id']}" class="it$s"> | |
<td>{$elem['id']}</td> | |
<td>{$elem['sdesc']}</td> | |
<td>{$elem['cat']}</td> | |
<td align="right">\${$elem['fprice']}</td> | |
</tr> | |
EOB; | |
} | |
?> | |
</table> | |
</div><br /> | |
<form name="fItem" action="javascript:postForm('add.php','fItem')"> | |
<input type="hidden" name="formName" value="fItem" /> | |
<input type="hidden" name="id" id="f_id" value="" /> | |
<input type="text" class="f" id="f_sdesc" name="sdesc" size="39" | |
maxlength="128" value="Short Description" dir="LTR" /> | |
<select class="f" name="cat" id="f_cat" size="1"> | |
<option selected>Category</option> | |
<?php foreach($categories as $cat) echo <<<EOB | |
<option value="{$cat}">{$cat}</option> | |
EOB; | |
?> | |
</select> | |
<input type="text" class="f" id="f_price" name="price" size="8" | |
maxlength="128" value="Price" dir="RTL" /><br /> | |
<textarea style="width: 100%" name="ldesc" class="f" | |
id="f_ldesc" rows="5" wrap="soft">Details</textarea><br /> | |
<input name="f_submit" type="submit" value="Add Item" /> | |
<input type="reset" value="Clear" /> | |
</form> | |
<?php | |
foot(); | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
include './model/db.inc'; | |
include './model/items.inc'; | |
$db = new items(); | |
if($_SERVER['REQUEST_METHOD']=='POST') { | |
header("Content-type: application/json"); | |
// Load an item entry from backend and send JSON request to populate form | |
if(isset($_POST['load_item'])) { | |
$entry = $db->load($_POST['load_item']); | |
$entry[0]['submit'] = 'Modify Item'; | |
if($entry) echo json_encode(array('formName'=>$_POST['formName'], | |
'load_item'=>$entry)); | |
exit; | |
} | |
// Validate form fields | |
foreach($_POST as $k=>$v) { | |
if(substr($k,0,5)=="desc_") { | |
if(isset($_POST[substr($k,5)]) && $_POST[substr($k,5)]==$v) { | |
echo json_encode(array('validate_error'=>'f_'.substr($k,5))); | |
exit; | |
} | |
} | |
} | |
// Save changes and display status message | |
$status = "Failure"; | |
if($_POST['f_submit']=='Modify Item') { | |
$ret = $db->modify($_POST); | |
if($ret) $status = "Modified"; | |
} else { | |
$ret = $db->insert($_POST); | |
if($ret) $status = "Added"; | |
} | |
echo json_encode(array('status'=>$status, | |
'elem'=>'tItems', | |
'reset'=>$ret, | |
'formName'=>$_POST['formName'])); | |
exit; | |
} | |
// Initialize view data | |
if(!isset($categories)) load_list('categories'); | |
if(!isset($item)) $item = array('cat'=>''); | |
$items = $db->load(); | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Catch JSON replies | |
var fN = function callBack(o) { | |
myDebug(o.responseText); | |
var resp = eval('(' + o.responseText + ')'); | |
if(resp['debug']) { | |
myDebug(resp["debug"]); | |
} | |
// Put up a Status message and fade it out | |
if(resp['status']) { | |
div = document.createElement("div"); | |
div.className='status'; | |
div.innerHTML = resp['status']; | |
pos = YAHOO.util.Dom.getXY(resp['elem']); | |
div.style.visibility = 'hidden' | |
document.body.appendChild(div); | |
YAHOO.util.Dom.setXY(div,[pos[0],pos[1]+40]); | |
div.style.visibility = 'visible' | |
fnc = function() { | |
if(resp['reset']) { | |
document.forms[resp['formName']].reset(); | |
} | |
window.location.reload(false); | |
} | |
fade(div,2,fnc); | |
} | |
// Flash the field that had the error | |
if(resp['validate_error']) { | |
var el = document.getElementById(resp['validate_error']); | |
var over = el.cloneNode(true); | |
over.style.position = 'absolute'; | |
over.style.zIndex=9999; | |
addClass(over,'error'); | |
over.style.visibility = 'hidden' | |
document.body.appendChild(over); | |
YAHOO.util.Dom.setXY(over, YAHOO.util.Dom.getXY(el)); | |
over.style.visibility = 'visible' | |
// Whoa - nested onCompletes can look a bit confusing ;) | |
fade(over,0.5, function() { | |
unfade(over,0.5, function() { | |
fade(over,2, function() { | |
over.parentNode.removeChild(over); | |
} ); | |
} ); | |
} ); | |
} | |
// Fill in formName | |
if(resp['load_item']) { | |
var oForm = document.forms[resp['formName']]; | |
for(var k in resp.load_item[0]) { | |
if(oForm['f_'+k]) { | |
if(resp.load_item[0][k].length) | |
oForm['f_'+k].value = resp.load_item[0][k]; | |
else oForm['f_'+k].value = oForm['desc_'+k].value; | |
} | |
} | |
} | |
} | |
var callback = { success:fN } | |
// Post form fields from formName to target | |
function postForm(target,formName) { | |
YAHOO.util.Connect.setForm(formName); | |
YAHOO.util.Connect.asyncRequest('POST',target,callback); | |
} | |
function postData(target,data) { | |
YAHOO.util.Connect.asyncRequest('POST',target,callback,data); | |
} | |
function addClass(o,cls) { | |
o.className+=" "+cls; | |
} | |
function delClass(o,cls) { | |
o.className=o.className.replace(new RegExp(" "+cls+"\\b"), ""); | |
} | |
function fade(o, dur, fnc) { | |
var oAnim = new YAHOO.util.Anim(o, {opacity: {from: 1, to: 0}}, dur); | |
if(fnc) oAnim.onComplete.subscribe(fnc); | |
oAnim.animate(); | |
} | |
function unfade(o, dur, fnc) { | |
var oAnim = new YAHOO.util.Anim(o, {opacity: {from: 0, to: 1}}, dur); | |
if(fnc) oAnim.onComplete.subscribe(fnc); | |
oAnim.animate(); | |
} | |
// Javascript for the item table | |
function clickItemPost(event) { | |
var target = YAHOO.util.Event.getTarget(event, true); | |
if(target.nodeName=='TD') target = target.parentNode; | |
postData('add.php','formName=fItem&load_item=' + target.id); | |
} | |
function mouseoverItem() { | |
this.className = 'its'; | |
} | |
function mouseoutItemEven() { | |
this.className = 'it0'; | |
} | |
function mouseoutItemOdd() { | |
this.className = 'it1'; | |
} | |
function fancyItems() { | |
var oT = document.getElementById('tItems'); | |
var oTr = oT.getElementsByTagName('TR'); | |
for(var i=0; i<oTr.length; i++){ | |
YAHOO.util.Event.addListener(oTr[i], "mouseover", mouseoverItem); | |
YAHOO.util.Event.addListener(oTr[i], "mouseout", i%2 ? mouseoutItemOdd:mouseoutItemEven); | |
YAHOO.util.Event.addListener(oTr[i], "click", clickItemPost); | |
} | |
} | |
// Javascript for the form entry section | |
function onfocusFormElem(event) { | |
var target = YAHOO.util.Event.getTarget(event, true); | |
var descElem = document.getElementById('desc_'+target.name); | |
if(document.all) { addClass(this,'iefocus') } | |
if(this.value == descElem.value) { this.value = ''; } | |
} | |
function onblurFormElem(event) { | |
var target = YAHOO.util.Event.getTarget(event, true); | |
var descElem = document.getElementById('desc_'+target.name); | |
if(document.all) { delClass(this,'iefocus') } | |
if(this.value == '') { this.value = descElem.value; } | |
} | |
function addHidden(oElm) { | |
var newE = document.createElement("INPUT") | |
newE.type = "hidden"; newE.value = oElm.value; | |
newE.name = "desc_"+oElm.name; newE.id = newE.name; | |
oElm.parentNode.insertBefore(newE, oElm); | |
} | |
function fancyForm() { | |
var oF = document.forms['fItem']; | |
var oElm = oF.getElementsByTagName('INPUT'); | |
var els = oElm.length; | |
for(var i=0; i<els; i++) { | |
if(oElm[i].type != 'hidden' && oElm[i].type != 'submit' && oElm[i].type != 'reset') { | |
YAHOO.util.Event.addListener(oElm[i], "focus", onfocusFormElem); | |
YAHOO.util.Event.addListener(oElm[i], "blur", onblurFormElem); | |
addHidden(oElm[i]); i++; els++; | |
} | |
} | |
oElm = oF.getElementsByTagName('TEXTAREA'); | |
els = oElm.length; | |
for(var i=0; i<els; i++) { | |
if(oElm[i].type != 'hidden') { | |
YAHOO.util.Event.addListener(oElm[i], "focus", onfocusFormElem); | |
YAHOO.util.Event.addListener(oElm[i], "blur", onblurFormElem); | |
addHidden(oElm[i]); i++; els++; | |
} | |
} | |
oElm = oF.getElementsByTagName('SELECT'); | |
els = oElm.length; | |
for(var i=0; i<els; i++) { | |
if(oElm[i].type != 'hidden') { | |
addHidden(oElm[i]); i++; els++; | |
} | |
} | |
} | |
function myDebug(msg) { | |
var oDebug = document.getElementById('debug'); | |
if(typeof(msg)=='object') { | |
tmp = ''; | |
for(var i in msg) { | |
tmp += i + " = " + msg[i] + "<br />"; | |
} | |
} else tmp = msg; | |
oDebug.innerHTML = [oDebug.innerHTML,tmp,'<br />'].join(''); | |
oDebug.scrollTop = oDebug.scrollHeight * 2; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class db { | |
protected static $dbh = false; | |
function connect() { | |
self::$dbh = new PDO('sqlite:./model/example.db'); | |
self::$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | |
} | |
protected function fatal_error($msg) { | |
echo "<pre>Error!: $msg\n"; | |
$bt = debug_backtrace(); | |
foreach($bt as $line) { | |
$args = var_export($line['args'], true); | |
echo "{$line['function']}($args) at {$line['file']}:{$line['line']}\n"; | |
} | |
echo "</pre>"; | |
die(); | |
} | |
} | |
// load_list takes a text file and turns it into a global array cached by APC | |
function load_list($name) { | |
global $$name; | |
if(!$$name = apc_fetch($name)) { | |
$$name = explode("\n",trim(file_get_contents($name.'.txt'))); | |
apc_store($name,$$name); | |
} | |
} | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
id INTEGER PRIMARY KEY, | |
cat TEXT NOT NULL, | |
sdesc TEXT NOT NULL, | |
ldesc TEXT NOT NULL, | |
price REAL DEFAULT 0 | |
*/ | |
class items extends db { | |
function insert($item) { | |
$t = $_SERVER["REQUEST_TIME"]; | |
try { | |
if(!self::$dbh) $this->connect(); | |
$stmt = self::$dbh->prepare("INSERT INTO items | |
(id,cat,sdesc,ldesc,price,ctime) | |
VALUES | |
(NULL,:cat,:sdesc,:ldesc,:price,$t)"); | |
$params = array(':cat' =>$item['cat'], | |
':sdesc'=>$item['sdesc'], | |
':ldesc'=>$item['ldesc'], | |
':price'=>$item['price']); | |
$ret = $stmt->execute($params); | |
} catch (PDOException $e) { | |
$this->fatal_error($e->getMessage()); | |
} | |
return $ret; | |
} | |
function modify($item) { | |
try { | |
if(!self::$dbh) $this->connect(); | |
$stmt = self::$dbh->prepare("UPDATE items SET | |
cat=:cat, sdesc=:sdesc, | |
ldesc=:ldesc, price=:price | |
WHERE id=:id"); | |
$params = array(':cat' =>$item['cat'], | |
':sdesc'=>$item['sdesc'], | |
':ldesc'=>$item['ldesc'], | |
':price'=>$item['price'], | |
':id'=>$item['id']); | |
$ret = $stmt->execute($params); | |
} catch (PDOException $e) { | |
$this->fatal_error($e->getMessage()); | |
} | |
return $ret; | |
} | |
function load($id=-1) { | |
$where = ''; | |
if($id!=-1) $where = "where id=".(int)$id; | |
try { | |
if(!self::$dbh) $this->connect(); | |
$result = self::$dbh->query("SELECT * FROM items | |
$where order by ctime desc"); | |
$rows = $result->fetchAll(PDO::FETCH_ASSOC); | |
} catch (PDOException $e) { | |
$this->fatal_error($e->getMessage()); | |
} | |
// Some databases can do this right in the SELECT | |
// SQLite can't, so we add a formatted column ourselves | |
foreach($rows as $i=>$row) { | |
$rows[$i]['fprice'] = number_format($row['price'],2); | |
} | |
return $rows; | |
} | |
} | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
function head($title="Default") { ?> | |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" | |
"http://www.w3.org/TR/html4/loose.dtd"> | |
<html lang="en"> | |
<head> | |
<title><?php echo $title?></title> | |
<style type="text/css" media="screen">@import "styles.css";</style> | |
<script type="text/javascript" src="/yui/YAHOO.js"></script> | |
<script type="text/javascript" src="/yui/dom.js"></script> | |
<script type="text/javascript" src="/yui/event.js"></script> | |
<script type="text/javascript" src="/yui/connection.js"></script> | |
<script type="text/javascript" src="/yui/animation.js"></script> | |
<script type="text/javascript" src="common.js"></script> | |
</head> | |
<body> | |
<br /> | |
<div class="main"> | |
<?php | |
} | |
function foot() { ?> | |
</div><br clear="left"/> | |
<font size="-1">Server -> Client JSON Messages</font><br /> | |
<div id="debug" class="debug"> | |
</div> | |
<script>fancyItems(); fancyForm();</script> | |
</body> | |
</html> | |
<?php | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment