mix html template with php code : php html template - php

I create a dynamic website using php/mysql. my template for print data using pure php code + html . now , better, optimized, faster way for Structure of mix php + html ? ( without template engine )
for each page i have : ex.1 ( php code before wrapper )
<?PHP include ( DEFINE_SITE . '/templates/header.php' );
// isset : post : get : SELECT : INSERT ... Or ANY CODE OF PHP
?>
<div id="wrapper">
<div id="leftsidebar"><?PHP // Left DATA ?></div>
<div id="centercontent">
<?PHP // while {} Print result of php ANY LOOPS ..... ?>
</div>
<div id="rightsidebar"><?PHP // Right DATA ?></div>
</div>
<?PHP include ( DEFINE_SITE . '/templates/footer.php' ); ?>
for each page i have : ex.2 ( after side bar and before center content )
<?PHP include ( DEFINE_SITE . '/templates/header.php' );
<div id="wrapper">
<div id="leftsidebar"><?PHP // Left DATA ?></div>
<?PHP // isset : post : get : SELECT : INSERT ... Or ANY CODE OF PHP ?>
<div id="centercontent">
<?PHP // while {} Print result of php ANY LOOPS ..... ?>
</div>
<div id="rightsidebar"><?PHP // Right DATA ?></div>
</div>
<?PHP include ( DEFINE_SITE . '/templates/footer.php' );?>
Which is better? e.x 1 or e.x 2 ? your opinion ?

why the aversion to a template engine? In reality, PHP is a template engine, but perhaps if you checked a few out (like Twig) it might help you in designing something more flexible, fast and responsive without the template engine.... or you might start to love it, like me ;-)

I suggest that you keep your HTML and PHP separated. If you don't want to use a template system why don't you do it like this?
Make a HTML template:
<div id="wrapper">
<div id="leftsidebar">{LEFT}</div>
<div id="centercontent">{CONTENT}</div>
<div id="rightsidebar">{RIGHT}</div>
</div>
In a different php file:
$content = file_get_contents('template.html');
$templateVars = array();
startVar('CONTENT');
echo '<p>This is the content.</p>'; // New template vars are also allowed
endVar('CONTENT');
echo replaceTemplateVars($content);
/**
* Replace template variables recursively with the key-value pairs that are in the $templateVars queue
* #param string $content (default NULL) is code to convert.
* #return the string that is replaced
*/
function replaceTemplateVars($content = NULL)
{
global $templateVars;
$matches = array();
preg_match_all("/{[A-Z0-9_:]*}/", $content, $matches); // $matches = All vars found in your template
foreach($matches[0] as $key)
{
if(isset($templateVars[substr($key, 1, -1)]))
{
$content = str_replace($key, $templateVars[substr($key, 1, -1)], $content); // Substitute template var with contents
}
else
{
$content = str_replace($key, "", $content); // Remove empty template var from template
}
}
// Check if the replacement has entered any new template variables, if so go recursive and replace these too
if(preg_match_all("/{[A-Z0-9_:]*}/", $content, $matches))
{
$content = replaceTemplateVars($content);
}
return $content;
}
/**
* Start output buffer for a template key
* #param string $key is not used. Only for overview purposes
*/
function startVar($key)
{
ob_start();
}
/**
* End output buffer for a template key and store the contents of the output buffer in the template key
* #param string $key
*/
function endVar($key)
{
setVar($key, ob_get_contents());
ob_end_clean();
}
/**
* #param string $key to store value in
* #param mixed $value to be stored
*/
function setVar($key, $value)
{
global $templateVars;
$templateVars[$key] = $value;
}
And this is what you get on your screen:
<div id="wrapper">
<div id="leftsidebar"></div>
<div id="centercontent"><p>This is the content.</p></div>
<div id="rightsidebar"></div>
</div>
So preprocessing is done first and at the end all html code is outputted.
Of course you could add functions like startPrependVar() and startAppendVar() and wrap everything into a Template class to get rid of the global scope.

Related

PHP template not rendering to PHP page

I'm trying to make a PHP template without any libraries or frameworks, in order to understand templating. The template is of a <select> that displays a list of all the countries. It was fully working before I templated it, so the issue is not with the <select> element logic.
However, the select template is not rendering to the page.
Here is my code:
country_select.php:
<?php
class CountrySelect {
static $template = 'country_select_template.php';
public static function display() {
if ( class_exists( 'View' ) ) {
// Get the full path to the template file.
$templatePath = dirname( __FILE__ ) . static::$template;
// Return the rendered HTML
return View::render( $templatePath );
}
else {
return "You are trying to render a template, but we can't find the View Class";
}
}
}
?>
country_select_template.php:
<div class="form-group col-sm-6">
<div class="select">
<span class="arr"></span>
<select data-bind="options: _countries,
optionsText: 'name',
optionsValue: 'geonameId',
value: selectedCountry,
optionsCaption: 'Country'">
</select>
</div>
</div>
view.php:
<?php
/** View.php **/
class View {
/**
* -------------------------------------
* Render a Template.
* -------------------------------------
*
* #param $filePath - include path to the template.
* #param null $viewData - any data to be used within the template.
* #return string -
*
*/
public static function render( $filePath, $viewData = null ) {
// Was any data sent through?
( $viewData ) ? extract( $viewData ) : null;
ob_start();
include ( $filePath );
$template = ob_get_contents();
ob_end_clean();
return $template;
}
}
?>
view_renderer.php:
<?php
require('view.php');
?>
Here is the relevant code from the php page where I try to render the template. Notice that the "region_select" is not yet templated, that is how my "country_select used to look.
<div class="row">
<?php
require 'scripts/back_end/views/country_select.php';
require 'scripts/back_end/views/view.php';
View::render('country_select_template.php');
?>
<div class="form-group col-sm-6">
<div class="select">
<span class="arr"></span>
<select data-bind="options: _regions,
optionsText: 'name',
optionsValue: 'name',
value: selectedCity,
optionsCaption: 'Region'">
</select>
</div>
</div>
How do I get the html in country_select_template to render to the page? The calling code that is supposed to initiate the template to render to the page is
<?php
require 'scripts/back_end/views/country_select.php';
require 'scripts/back_end/views/view.php';
View::render('country_select_template.php');
?>
I have changed the calling code to:
<?php
require 'scripts/back_end/views/country_select.php';
require 'scripts/back_end/views/view.php';
echo View::render('country_select_template.php');
?>
I see I have this error in the php error logs:
[15-Feb-2016 09:33:35 Europe/Berlin] PHP Warning:
require(scripts/back_end/views/country_select.php): failed to open
stream: No such file or directory in
/Applications/MAMP/htdocs/its_vegan/index.php on line 92 [15-Feb-2016
09:33:35 Europe/Berlin] PHP Fatal error: require(): Failed opening
required 'scripts/back_end/views/country_select.php'
(include_path='.:/Applications/MAMP/bin/php/php7.0.0/lib/php') in
/Applications/MAMP/htdocs/its_vegan/index.php on line 92
View::render returns the code. It does not print it.
So I think this should do it:
<?php
require 'scripts/back_end/views/country_select.php';
require 'scripts/back_end/views/view.php';
echo View::render('country_select_template.php');
?>

PHP or Regex for unique matching ID's

Here's some stuff stored in a database table:
<section id="earth">
<h2>Earth</h2>
<div class="MainDiv">
(article)
</div>
</section>
<section id="mars">
<h2>Mars</h2>
<div class="MainDiv">
(article)
</div>
</section>
All I want to do is modify the display so each section has a unique data-target and each div has a matching ID. (I gave the div's a class - MainDiv - to distinguish them from any nested divs they might contain.)
<section id="earth" data-target="a">
<h2>Earth</h2>
<div class="MainDiv" id="a">
<section id="mars" data-target="b">
<h2>Mars</h2>
<div class="MainDiv" id="b">
Ideally, I'd like to keep the data-targets and matching ID's simple - single, lower case letters would be perfect. Is there a PHP function that can do that? If not, do you know a regex script that would work?
No, as much as possible, don't work on regex for this task. This is what HTML parsers are for. There is already a class for PHP that does this, its DOMDocument.
First, just load up the class (this is built-in already), then you load the HTML markup, get all the elements you need (in this case, the section tags). After you got all the section tags, iterate on those found and add those data attributes you want for each of those (including the div tags), then you put it back together as string again. Here's some to get you started. Rough Example:
$i = 1; // initialize counter
// initialize DOMDocument
$dom = new DOMDocument;
#$dom->loadHTML($html); // load the markup
$sections = $dom->getElementsByTagName('section'); // get all section tags
if($sections->length > 0) { // if there are indeed section tags inside
// work on each section
foreach($sections as $section) { // for each section tag
$section->setAttribute('data-target', 'section' . $i); // set id for section tag
// get div inside each section
foreach($section->getElementsByTagName('div') as $div) {
if($div->getAttribute('class') == 'MainDiv') { // if this div has class maindiv
$div->setAttribute('id', 'div' . $i); // set id for div tag
}
}
$i++; // increment counter
}
}
// back to string again, get all contents inside body
$html = '';
foreach($dom->getElementsByTagName('body')->item(0)->childNodes as $child) {
$html .= $dom->saveHTML($child); // convert to string and append to the container
}
// output
echo $html;
Sample Output
I would do as #Barmar suggested. Doing a0,a1,a2, ..., This way we can have as many as we want and echo each <section> in PHP via loop. If we went from a,b,c,...,z what would be next? aa? And you will have to program that in. For each element I would use a simple for loop and use the index for each element. For example this:
class Planet
{
public $title;
public $name;
public $article;
function __construct($title, $name, $article) {
$this->name = $name;
$this->title = $title;
$this->article = $article;
}
}
$planets = array(
new Planet("earth", "Earth", "Hello World!"),
new Planet("mars", "Mars", "Hello World Again!")
);
for( $i = 0; $i < count($planets); $i++ ) {
$id = strtolower($planets[$i]->name);
$name = $planets[$i]->name;
$article = $planets[$i]->article;
echo <<<HERE
<section id="$id" data-target="a$i">
<h2>$name</h2>
<div class="MainDiv" id="a$i">
$article
</div>
</section>
HERE;
}
Would give the output:
<section id="earth" data-target="a0">
<h2>Earth</h2>
<div class="MainDiv" id="a0">
Hello World!
</div>
</section>
<section id="mars" data-target="a1">
<h2>Mars</h2>
<div class="MainDiv" id="a1">
Hello World Again!
</div>
</section>

How to use AJAX in an MVC - php Blog? - adding comments dynamically

I wrote a posts.php page which shows a certain post and its comments, giving the user the ability to add a new comment to this post dynamically.
I want to implement the *"submit_comment"* using Ajax, but I don't really know how to do it in MVC.
This is my Posts.php:
<script type="application/javascript" src="Ajax/addComment.js"> </script>
src="../views/Ajax/addComment.js"> </script> <title> Posts
(View)</title> </head>
<body> <div id="main"> <div class="container"> <?=$data['header'];?>
<div id="content">
<!-- Main Post -->
<div class="content-background">
<h2> <?=$data['title'];?></h2>
<h4> <?=$data['date'];?> </h4>
<p> <?=$data['content'];?></p>
</div>
<div id="form-content">
<form name="commentForm" method="post">
Enter your name: <input type="text" name="username" id="username"> <br />
Enter your comment: </br> <textarea name="comment" id="comment" cols="10" rows="10"> </textarea> <br />
<input value='Submit' type='button' onclick='JavaScript:commentRequest2("<?=$data['id']?>")'
name='submit'>
</form>
</div>
<div id="commentArea">
<?=include_once("comments_area.php");?>
</div><!-- end commentArea -->
</div> </div> </div>
</body> </html>
This is My Posts_Controller.php:
<?php
/**
* This file handles the retrieval and serving of posts posts
*/
class Posts_Controller
{
/**
* This template variable will hold the 'view' portion of our MVC for this
* controller
*/
public $template = 'posts';
/**
* This is the default function that will be called by router.php
*
* #param array $getVars the GET variables posted to index.php
*/
public function main(array $getVars)
{
$postsModel = new Posts_Model;
}
else{
//get the post
$post = $postsModel->get_main_post("`id`='", $getVars['id'], "LIMIT", "1");
//get the comments
$comments = $postsModel->get_comments("`postID`='", $getVars['id']);
//create a new view and pass it our template
$header = new View_Model('header_template');
$view = new View_Model($this->template);
//assign post data to view
$view->assign('header', $header->render(FALSE));
$view->assign('title' , $post['title']);
$view->assign('content' , $post['content']);
$view->assign('date' , $post['date']);
$view->assign('by' , $post['added_by']);
$view->assign('id' , $post['id']);
$view->assign('commentsArr' , $comments);
$view->render();
}
}
}
And This is My Posts_Model.php:
<?php
/**
* The Posts Model does the back-end heavy lifting for the Posts Controller
*/
class Posts_Model
{
/**
* Holds instance of database connection
*/
private $db;
public function __construct()
{
$this->db = new MysqlImproved_Driver;
}
/**
* Fetches article based on supplied name
*
* #param string $author
*
* #return array $article
*/
public function get_main_post($cond1, $var1, $cond2 ="", $var2 = "")
{
//connect to database
$this->db->connect();
//sanitize data
$var1 = $this->db->escape($var1);
$var2 = $this->db->escape($var2);
$cond = $cond1.$var1."'";
$cond.= " ".$cond2." ".$var2;
//prepare query
$this->db->prepare
(
"
SELECT * FROM `posts`
WHERE $cond
;
"
);
//execute query
$this->db->query();
$article = $this->db->fetch('array');
return $article;
}
public function get_comments($cond1, $var1, $cond2 ="", $var2 = "")
{
//connect to database
$this->db->connect();
//sanitize data
$var1 = $this->db->escape($var1);
$var2 = $this->db->escape($var2);
$cond = $cond1.$var1."'";
$cond.= " ".$cond2." ".$var2;
//prepare query
$this->db->prepare
(
"
SELECT * FROM `comments`
WHERE $cond
;
"
);
//execute query
$this->db->query();
$resultArr[0] = 0;
$i = 1;
while( $result = $this->db->fetch('array')){
$resultArr[$i] = $result;
$i++;
}
$resultArr[0] = $i;
return $resultArr;
}
}
?>
Where Should I add the addComment.js? (V, M or C?)
And what should the addComment do? what URL/ function to call?
Any suggestions? Examples?
In your controller create a function that will allow you to add javascript files to your views. Then call it in your controller. It will add the file path to an array, and just before the view is displayed, assign it to the template.
$view->addJavascript('/Ajax/addComment.js');
Or you can just use
$js_files[] = '/Ajax/addComment.js';
$view->assign('js_files', $js_files);
then in your view you can use
<?
foreach($data['js_files'] as $file)
{
echo '<script type="application/javascript" src="'.$file.'"> </script>'
}
?>
Not sure how your routing is structured in your application, but you would create a method similar to
main for the ajax functionality. if you mention more about how URLs route to Controller then I might bbe able to make a more educated suggestion.
Before you even try to learn how to use MVC, you should learn how to write semantic HTML and unobtrusive JavaScript! Judging by posts.php files, you really have no clue what you are doing.
I would recommend reading everything from this page. It will contains a lot of very good materials about HTML. Then watch this lecture and then watch everything on http://yuiblog.com/crockford/. Also i would advise you read Eloquent Javascript book.
Are you using a home-made framework or is it some 3rd part product?
Anyway. You should start by making a non-AJAX method for adding comments. In your current setup it would most likely happen by adding post_comment() method in Posts_Model. And then creating a separate method in Posts_Controller, for dealing with POST requests.
When that is done, you can start working on using AJAX to post new comments for the article. Your '/views/Ajax/addComment.js' file should be added in posts.php files (what you call "view", but it isn't). You should use absolute path for including that JS file.
The AJAX request should be executed through event handlers which is attached to onsubmit event for the <form name="commentForm">. You gather data from form's elements and create XHR request. To learn how to do it, read this article.
That said, your code is vulnerable to SQL injections. Just because you use PDO/MySQLi it will not magically protect you. You actually need to know how to use it too. I would recommend reading this article (yes, it is for PDO, but the theory does not change). Especially this section. It should explain you how to properly use prepared statements and why it is important. For MySQLi equivalents you will have to read the MySQLi::bind_param() manual entry.

Simple template var replacement, but with a twist

So I'm setting up a system that has a lot of emails, and variable replacement within it, so I'm writing a class to manage some variable replacement for templates stored in the database.
Here's a brief example:
// template is stored in db, so that's how this would get loaded in
$template = "Hello, %customer_name%, thank you for contacting %website_name%";
// The array of replacements is built manually and passed to the class
// with actual values being called from db
$replacements = array('%customer_name%'=>'Bob', '%website_name%'=>'Acme');
$rendered = str_replace(array_keys($replacements), $replacements, $template);
Now, that works well and good for single var replacements, basic stuff. However, there are some places where there should be a for loop, and I'm lost how to implement it.
The idea is there'd be a template like this:
"hello, %customer_name%, thank you for
requesting information on {products}"
Where, {products} would be an array passed to the template, which the is looped over for products requested, with a format like:
Our product %product_name% has a cost
of %product_price%. Learn more at
%product_url%.
So an example rendered version of this would be:
"hello, bob, thank you for requesting
information on:
Our product WidgetA has a cost of $1.
Learn more at example/A
Our product WidgetB has a cost of $2.
Learn more at example/B
Our product WidgetC has a cost of $3.
Learn more at example/C.
What's the best way to accomplish this?
Well, I really dont see the point in a template engine that uses repalcements/regex
PHP Is already a template engine, when you write <?php echo $var?> its just like doing <{$var}> or {$var}
Think of it this way, PHP Already translates <?php echo '<b>hello</b>'?> into <b>hello</b> by its engine, so why make it do everything 2 times over.
The way i would implement a template engine is like so
Firstly create a template class
class Template
{
var $vars = array();
function __set($key,$val)
{
$this->vars[$key] = $val;
}
function __get($key)
{
return isset($this->vars[$key]) ? $this->vars[$key] : false;
}
function output($tpl = false)
{
if($tpl === false)
{
die('No template file selected in Template::output(...)');
}
if(!file_exists(($dir = 'templates/' . $tpl . '.php')))
{
die(sprintf('Tpl file does not exists (%s)',$dir));
}
new TemplateLoader($dir,$this->vars);
return true;
}
}
This is what you use in your login such as index.php, you will set data just like an stdClass just google it if your unsure. and when you run the output command it sends the data and tpl to the next class below.
And then create a standalone class to compile the tpl file within.
class TemplateLoader
{
private $vars = array();
private $_vars = array(); //hold vars set within the tpl file
function __construct($file,$variables)
{
$this->vars = $variables;
//Start the capture;
ob_start();
include $file;
$contents = ob_get_contents();
ob_end_clean(); //Clean it
//Return here if you wish
echo $contents;
}
function __get($key)
{
return isset($this->vars[$key]) ? $this->vars[$key] : (isset($this->_vars[$key]) ? $this->_vars[$key] : false) : false;
}
function __set($key,$val)
{
$this->_vars[$key] = $val;
return true;
}
function bold($key)
{
return '<strong>' . $this->$key . '</string>';
}
}
The reason we keep this seperate is so it has its own space to run in, you just load your tpl file as an include in your constructor so it only can be loaded once, then when the file is included it has access to all the data and methods within TemplateLoader.
Index.php
<?php
require_once 'includes/Template.php';
require_once 'includes/TemplateLoader.php';
$Template = new Template();
$Template->foo = 'somestring';
$Template->bar = array('some' => 'array');
$Template->zed = new stdClass(); // Showing Objects
$Template->output('index'); // loads templates/index.php
?>
Now here we dont really want to mix html with this page because by seperating the php and the view / templates you making sure all your php has completed because when you send html or use html it stops certain aspects of your script from running.
templates/index.php
header
<h1><?php $this->foo;?></h1>
<ul>
<?php foreach($this->bar as $this->_foo):?>
<li><?php echo $this->_foo; ?></li>
<?php endforeach; ?>
</ul>
<p>Testing Objects</p>
<?php $this->sidebar = $this->foo->show_sidebar ? $this->foo->show_sidebar : false;?>
<?php if($this->sidebar):?>
Showing my sidebar.
<?php endif;?>
footer
Now here we can see that were mixing html with php but this is ok because in ehre you should only use basic stuff such as Foreach,For etc. and Variables.
NOTE: IN the TemplateLoader Class you can add a function like..
function bold($key)
{
return '<strong>' . $this->$key . '</string>';
}
This will allow you to increase your actions in your templates so bold,italic,atuoloop,css_secure,stripslashs..
You still have all the normal tools such as stripslashes/htmlentites etc.
Heres a small example of the bold.
$this->bold('foo'); //Returns <strong>somestring</string>
You can add lots of tools into the TempalteLoader class such as inc() to load other tpl files, you can develop a helper system so you can go $this->helpers->jquery->googleSource
If you have any more questions feel free to ask me.
----------
An example of storing in your database.
<?php
if(false != ($data = mysql_query('SELECT * FROM tpl_catch where item_name = \'index\' AND item_save_time > '.time() - 3600 .' LIMIT 1 ORDER BY item_save_time DESC')))
{
if(myslq_num_rows($data) > 0)
{
$row = mysql_fetch_assc($data);
die($row[0]['item_content']);
}else
{
//Compile it with the sample code in first section (index.php)
//Followed by inserting it into the database
then print out the content.
}
}
?>
If you wish to store your tpl files including PHP then that's not a problem, within Template where you passing in the tpl file name just search db instead of the filesystem
$products = array('...');
function parse_products($matches)
{
global $products;
$str = '';
foreach($products as $product) {
$str .= str_replace('%product_name%', $product, $matches[1]); // $matches[1] is whatever is between {products} and {/products}
}
return $str;
}
$str = preg_replace_callback('#\{products}(.*)\{/products}#s', 'parse_products', $str);
The idea is to find string between {products} and {products}, pass it to some function, do whatever you need to do with it, iterating over $products array.
Whatever the function returns replaces whole "{products}[anything here]{/products}".
The input string would look like that:
Requested products: {products}%product_name%{/products}

What is the best way to include a php file as a template?

I have simple template that's html mostly and then pulls some stuff out of SQL via PHP and I want to include this template in three different spots of another php file. What is the best way to do this? Can I include it and then print the contents?
Example of template:
Price: <?php echo $price ?>
and, for example, I have another php file that will show the template file only if the date is more than two days after a date in SQL.
The best way is to pass everything in an associative array.
class Template {
public function render($_page, $_data) {
extract($_data);
include($_page);
}
}
To build the template:
$data = array('title' => 'My Page', 'text' => 'My Paragraph');
$Template = new Template();
$Template->render('/path/to/file.php', $data);
Your template page could be something like this:
<h1><?php echo $title; ?></h1>
<p><?php echo $text; ?></p>
Extract is a really nifty function that can unpack an associative array into the local namespace so that you can just do stuff like echo $title;.
Edit: Added underscores to prevent name conflicts just in case you extract something containing a variable '$page' or '$data'.
Put your data in an array/object and pass it to the following function as a second argument:
function template_contents($file, $model) {
if (!is_file($file)) {
throw new Exception("Template not found");
}
ob_start();
include $file;
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}
Then:
Price: <?php echo template_contents("/path/to/file.php", $model); ?>

Categories