Simple PHP Template Parsing - php

I want to create a simple PHP Class for parsing basic HTML email templates in PHP. Very basic... Pass a PHP array into a function which has a variable containing the Email template HTML with placeholders {{var_name}}. The PHP Array's Key will be the variable name in the template and it;s Value will be the desired output when the email HTML is sent as an email.
I thought it might be useful for me to create a simple PHP Class that could do this same thing and speed things up by being flexible.
So here is some basic example HTML for the Email body.... Variables that will need to be replaced in the template with values from PHP variables are wrapped with {{var_name}}
<html>
<body>
<h1>Account Details</h1>
<p>Thank you for registering on our site, your account details are as follows:<br>
Username: {{username}}<br>
Password: {{password}} </p>
</body>
</html>
In the above example there are 2 variables that need to be populated. {{username}} and {{password}}
I would like to be able to simply pass my Class function a PHP Array where the Array key is the variable name and the value is the value that would be populated in my email template.
So something like this would be passed into my method/function that parses the email template....
$emailValues = array(
'username' => 'My username value here',
'password' => 'My password value here'
);
$emailHtml = new EmailParser($emailValues);
echo $emailHtml;
Would look like this...
<html>
<body>
<h1>Account Details</h1>
<p>Thank you for registering on our site, your account details are as follows:<br>
Username: My username value here<br>
Password: My password value here </p>
</body>
</html>
I am curious how I could best achieve this? My main question would be how to pass in the PHP Array and have it map out to a variable name to do the replacements. The PHP Array Key would be the Variable name in the template.

It should just be a case of looping through the values and using str_replace on them.
Here's an example:
<?php
$emailValues = array(
'username' => 'My username value here',
'password' => 'My password value here'
);
$emailHtml = new EmailParser($emailValues);
echo $emailHtml->output();
class EmailParser {
protected $_openingTag = '{{';
protected $_closingTag = '}}';
protected $_emailValues;
protected $_emailHtml = <<<HTML
<html>
<body>
<h1>Account Details</h1>
<p>Thank you for registering on our site, your account details are as follows:<br>
Username: {{username}}<br>
Password: {{password}} </p>
</body>
</html>
HTML;
public function __construct($emailValues) {
$this->_emailValues = $emailValues;
}
public function output() {
$html = $this->_emailHtml;
foreach ($this->_emailValues as $key => $value) {
$html = str_replace($this->_openingTag . $key . $this->_closingTag, $value, $html);
}
return $html;
}
}

these two functions should help :
function template($string,$hash) {
foreach ( $hash as $ind=>$val ) {
$string = str_replace('{{'.$ind.'}}',$val,$string);
}
$string = preg_replace('/\{\{(.*?)\}\}/is','',$string);
return $string;
}
function template_file($file,$hash) {
$string = file_get_contents($file);
if ($string) {
$string = template($string,$hash);
}
return $string;
}

Non-recursive solution:
<?php
Class ParseTemplate
{
public function Email( $sTemplateName, $aPlaceholders, $aData )
{
$sReplacedHtml = '';
try
{
if( !empty( $sTemplateName ) && !empty( $aPlaceholders ) && !empty( $aData ) )
{
$iCountPlaceholders = count( $aPlaceholders );
$iCountData = count( $aData );
if( $iCountData !== $iCountPlaceholders )
{
throw new Exception( 'Placeholders and data don\'t match' );
}
if( file_exists( $sTemplateName ) )
{
$sHtml = file_get_contents( $sTemplateName );
for( $i = 0; $i < $iCountData; ++$i )
{
$sHtml = str_ireplace( $aPlaceholders[ $i ], $aData[ $i ], $sHtml );
}
$sReplacedHtml = $sHtml;
}
}
}
catch( Exception $oException )
{
// Log if desired.
}
return $sReplacedHtml;
}
}
$aPlaceholders = array( '{{username}}', '{{password}}' );
$aData = array( 'Why so pro', 'dontchangeme' );
$oParser = new ParseTemplate;
$sReplacedHtml = $oParser->Email( 'intemplate.html', $aPlaceholders, $aData );
file_put_contents( 'outtemplate.html', $sReplacedHtml );
?>

I already use a function for this kind of purpose.
// file class.bo3.php, more about this class here: https://github.com/One-Shift/BO3-BOzon/blob/master/backoffice/class/class.bo3.php
class bo3 {
public static function c2r ($args = [], $target) {
foreach ($args as $index => $value) { $target = str_replace("{c2r-$index}", $value, $target); }
return $target;
}
}
and to run it
$emailValues = ['
username' => 'My username value here', // in the template the code need to be "{c2r-username}"
'password' => 'My password value here' // in the template the code need to be "{c2r-password}"
];
$template = file_get_contents("path/to/html/file")
$finishedTemplate = bo3::c2r($emailValues, $template);
If you want to change the code format from {c2r-$index} to {{ $index }}, just change it in the class function c2r().

Related

Send all of a dropdown in Contact Form 7

I need to send a full array of custom field to a mail (dynamicaly populate) with contact Form 7 to work it here before sending :
// define the wpcf7_posted_data callback
function action_wpcf7_posted_data($array)
{
$a = get_field('date')
//WORK HERE
$array['Nom & Prénom'] = $array['name'];
unset($array['name']);
$array['E-mail'] = $array['email'];
unset($array['email']);
$array['Téléphone'] = $array['tel'];
unset($array['tel']);
$array['Profession'] = $array['job'];
unset($array['job']);
$array['Session'] = $array['upcoming-gigs'];
unset($array['upcoming-gigs']);
unset($array['privacy']);
return $array;
}
add_filter('wpcf7_posted_data', 'action_wpcf7_posted_data', 10, 1);
Because it's before sending a mail I can't call anything to compare before sending.
So I want to send all the data in a hidden input next to compare it.
This the two input in contact Form 7 :
[select upcoming-gigs data:gigs id:date] [hidden select upcoming-gigs2 data:gigs2]
My goal here is to send all the data of the hidden select.
I don't find a way to send all input in the mail.
Is it possible ? There is a better way ?
Thx
EDIT :
My question mark2 :
The goal is to send a mail with the date of the session and the id of it.
I use ACF and I have :
And after a dynamic dropdown, it's look like this for the user :
The problem is I don't have the id of the session, only the date.
To know the id I need to compar to the array of all the custom field, I can't import it during wpcf7_posted_data.
I think if I send all the data of the array in a hidden field, I could remake the array and find the id of the session my user choose.
I hope I'm clearer.
(I can't make a request in php during wpcf7_posted_data. Can I make an ajax request ?)
EDIT2 :
This my hidden select with session and text
This is the html of contact form 7 the rest is div for CSS
[select upcoming-date data:date id:date] [hidden select upcoming-date2 data:date2]
EDIT3 :
Okay get it.
The custom fields I use to make the dropdown are in two part id and text. I have the text part I need the id.
If I send every text and id in the mail I can compare to the answer of the user et add to the mail the right id.
Here the generated html : http://www.sharemycode.fr/5ax
EDIT 4 :
That where I write the id and text of the dropdown :
That where I create the select :
add_filter('wpcf7_form_tag_data_option', function ($n, $options, $args) {
$ses = (array)get_field('date_new');
$sesCount = count($ses);
$gigs = [];
$gigs2 = [];
if (in_array('gigs', $options)) {
for ($i = 0; $i < $sesCount; $i++) {
if ($ses[$i]['date_start'] > date('d-m-Y', time())) {
$a = "A réaliser entre le " . $ses[$i]['date_start'] . " et le " . $ses[$i]['date_end'] ." | bla";
array_push($gigs, $a);
}
}
return $gigs;
}
}
It looks like this is supported by Contact Form 7 natively, it's just not very obvious on how to make it happen.
Here's a documentation page explaining the functionality: http://contactform7.com/selectable-recipient-with-pipes/
Basically all you have to do is put the values like so:
Visible Value|actual-form-value
What comes before the pipe "|" character will be shown in the form, and what comes after will be the actual value filled in for the form.
EDIT kanarpp :
I add my code here to separate the answer of HowardE.
This is how I dynamicaly create my select :
add_filter('wpcf7_form_tag_data_option', function ($n, $options, $args) {
$ses = (array)get_field('date');
$sesCount = count($ses);
$date= [];
if (in_array('date', $options)) {
for ($i = 0; $i < $sesCount; $i++) {
if ($ses[$i]['date_start'] > date('d-m-Y', time())) {
$a = "A réaliser entre le " . $ses[$i]['date_start'] . " et le " . $ses[$i]['date_end'] ." | bla";
array_push($date, $a);
}
}
return $date;
}
It's not working, I use Smart Grid-Layout Design for Contact Form 7 to create dynmicaly my select
I would create a custom form tag for the select. The following code will create a custom form tag called [gigs] which would be used like this:
[gigs upcoming-gigs]
I've also included ability to add the * and make it required.
My assumptions are how you're actually getting the ACF fields, which I can't actually do, since I don't have them, and you haven't completely shared how it's stored. You would add this to your functions.php.
add_action('wpcf7_init', function (){
wpcf7_add_form_tag( array('gigs', 'gigs*'), 'dd_cf7_upcoming_gigs' , array('name-attr' => true) );
});
function dd_cf7_upcoming_gigs($tag) {
if ( empty( $tag->name ) ) {
return '';
}
$validation_error = wpcf7_get_validation_error( $tag->name );
$class = wpcf7_form_controls_class( $tag->type );
if ( $validation_error ) {
$class .= ' wpcf7-not-valid';
}
$atts = array();
$atts['class'] = $tag->get_class_option( $class );
$atts['id'] = $tag->get_id_option();
$atts['tabindex'] = $tag->get_option( 'tabindex', 'signed_int', true );
if ( $tag->is_required() ) {
$atts['aria-required'] = 'true';
}
if ( $validation_error ) {
$atts['aria-invalid'] = 'true';
$atts['aria-describedby'] = wpcf7_get_validation_error_reference(
$tag->name
);
} else {
$atts['aria-invalid'] = 'false';
}
// Make first option unselected and please choose
$html = '<option value="">- - '. __('Please Choose', 'text-domain'). ' - -</option>';
// This part you may have to update with your custom fields
$ses = (array)get_field('date_new');
$sesCount = count($ses);
for ($i = 0; $i < $sesCount; $i++) {
if ($ses[$i]['date_start'] > date('d-m-Y', time())) {
$a = "A réaliser entre le " . $ses[$i]['date_start'] . " et le " . $ses[$i]['date_end'];
// if session ID is in fact $ses[$i]['session']
$html .= sprintf( '<option %1$s>%2$s</option>',
$ses[$i]['session'], $a );
}
}
foreach ($gigs as $key => $value){
$html .= sprintf( '<option %1$s>%2$s</option>',
$key, $value );
}
$atts['name'] = $tag->name;
$atts = wpcf7_format_atts( $atts );
$html = sprintf(
'<span class="wpcf7-form-control-wrap %1$s"><select %2$s>%3$s</select>%4$s</span>',
sanitize_html_class( $tag->name ), $atts, $html, $validation_error
);
return $html;
}
add_filter( 'wpcf7_validate_gigs', 'dd_validate_gigs_filter', 10, 2 );
add_filter( 'wpcf7_validate_gigs*', 'dd_validate_gigs_filter', 10, 2 );
function dd_validate_gigs_filter( $result, $tag ) {
$name = $tag->name;
$has_value = isset( $_POST[$name] ) && '' !== $_POST[$name];
if ( $has_value and $tag->has_option( 'multiple' ) ) {
$vals = array_filter( (array) $_POST[$name], function( $val ) {
return '' !== $val;
} );
$has_value = ! empty( $vals );
}
if ( $tag->is_required() and ! $has_value ) {
$result->invalidate( $tag, wpcf7_get_message( 'invalid_required' ) );
}
return $result;
}

showing my models value on view in codeigniter

im new in codeigniter and get some trouble with my function
here is my model
public function kode_unik(){
$q = $this->db->query("select MAX(RIGHT(id_obat,5)) as code_max from obat");
$code = "";
if($q->num_rows()>0){
foreach($q->result() as $cd){
$tmp = ((int)$cd->code_max)+1;
$hitung = strlen($tmp);
if ($hitung == 1 ){
$a = "0000".$tmp;
} elseif ($hitung == 2) {
$a = "000".$tmp;
}elseif ($hitung == 3) {
$a = "00".$tmp;
}elseif ($hitung == 4) {
$a = "0".$tmp;
}else{
$a = $tmp;
}
$code = sprintf("%s", $a);
}
}else{
$code = "0001";
}
$kodenyami = "E".$code;
return $kodenyami;
}
and then i wanna get the result of my models to show in my view.
here is my controller
public function add_data()
{
$this->load->helper( array('fungsidate', 'rupiah', 'url') );
$this->load->model('obat');
$this->load->database();
$data['a'] = $this->obat->tampil_data();
$data['b'] = $this->obat->kode_unik();
$componen = array(
"header" => $this->load->view("admin/header", array(), true),
"sidebar" => $this->load->view("admin/sidebar", array(), true),
"content" => $this->load->view("admin/add_obat", array("data" => $data), true)
);
$this->load->view('admin/index', $componen);
}
and my view goes here.
<i class="fa fa-medkit fa-5x"></i></div>
<div class="col-xs-9 text-right">
line20-> <div class="huge"><?php echo $b; ?></div>
<div>ID Obat</div>
the code give me an errors Message: Undefined variable: b
just don't know how to put the value of my models $kode_unik into my view ..
thanks
$data is already an array. Maybe like this :
"content" => $this->load->view("admin/add_obat", $data, TRUE)
CodeIgniter will extract the keys in $data so you will be able to use them in your view as $b
BTW instead of passing array() as a parameter of the load->view you can use NULL
P.S If you set the last parameter to TRUE, you will return the populated content of that view as a String (HTML in that case)
Here is something to start with :
public function __construct() {
parent::construct();
$this->load->helper(‘array(‘fungsidate’, ‘rupiah’, ‘url’);
$this->load->model(‘obat’);
$this->load->database(); // Should be already loaded depending on your config
}
public function add_data() {
// Set the data
$data[‘a’] = $this->obat->tampil_data();
$data[‘b’] = $this->obat->kodeunik();
// Load the views
$componen = array(
‘header’ => $this->load->view(‘admin/header’, NULL, TRUE);
‘sidebar’ => $this->load->view(‘admin/sidebar’, NULL, TRUE);
‘content’ => $this->load->view(‘admin/add_obat', $data, TRUE);
);
$this->load->view(‘admin/index’ ,$componen);
}
From what I understand about your code, in your templates you will need to echo the array keys
in admin/header you will echo $header;
in admin/sidebar you will echo $sidebar;
in admin/add_obat you will need to echo $content
and then you admin/index should be populated. I won’t do that if I were you to be honest I would probably load each template as is instead of outputting them as HTML string inside the final index. I don’t know exactly how you did your structure so it’s kinda hard for me to guess well. But in my case I would have use something like this instead of the componen array
public function add_data() {
// Set the data
$data[‘a’] = $this->obat->tampil_data();
$data[‘b’] = $this->obat->kodeunik();
// Load the views
$this->load->view(‘admin/header’);
$this->load->view(‘admin/sidebar’);
$this->load->view(‘admin/add_obat, $data); // This should be the body template of your page
$this->load->view(‘admin/footer’); // I guess you have a footer template
}
I hope this will help you!

Template Library

I'm trying to use a template library created by Phil Sturgeon. He has some great documentation for his template library but I've ran into a little bit of a problem with how I have my file structure done.
-views
-layouts
-default.php
-partials
-header_view.php
-footer_view.php
-metadata_view.php
login_view.php
Inside of my login controller index function I have the following code to establish which layout to use and which view to load as the body of the template. I also have included what I have inside of the header_view.php file which I believe is what I'm not getting to work right. I was hoping to be able to target the metadata partial inside of the header_view. According to the documentation I'm doing it correctly, however, I'm getting an error undefined index metadata coming from the header_view.php file. Any light on this issue.
Documention from the github repostitory: https://github.com/philsturgeon/codeigniter-template
$this->template
->title('Login Form')
->set_partial('header', 'partials/header_view')
->set_partial('metadata', 'partials/metadata_view')
->set_partial('footer', 'partials/footer_view')
->set_layout('default')
->build('login_form_view');
default.php
<?php echo $template['partials']['header']; ?>
<?php echo $template['body']; ?>
<?php echo $template['partials']['footer']; ?>
header_view.php
<!DOCTYPE html>
<html>
<head>
<title><?php echo $template['title']; ?></title>
<?php echo $template['partials']['metadata']; ?>
</head>
<body
well im a codeigniter fan; and i honestly think that the real power of CI that it doesnt come loaded with fancy "TEMPLATING lib" or auth lib; yet it give you all tools to build your own swiftly and very rappidly;
so my answer my not be what you really asking for but its a simple example of how you can build your own so called templaling lib in ci in less than 10mins and works flowlessly;
create MY_Controller inside applicaiton/core folder;
class MY_Controller extends CI_Controller {
protected $noEcho=true,$body = 'base/layout', $title = 'YOUR CONTROLLER TITLE',
$js = array(), //filename
$inline_js = '', //script
$css = array(),
$inline_css = '', //style
$content = array(); //html
inside it will be 3 basic functions
that set you page parts;
that manage your assets
that print out your end result page;
1
function output($data,$section='content'){
//checking type of data to be pushed its either array or string(html)
//this is a view it should be formated like this array( viewname,$data )
if( is_array($data) ){
$this->content[ $section ][] = $this->load->view( $data[0], $data[1], TRUE );
return $this;//to allow chaing
}elseif( is_string($data) ){//this is html
$this->content[ $section ][] = $data;
return $this;//to allow chaing
}
}
2nd is a function that let you add js,css and and inline js&css to this page;
function _asset( $link, $txt = FALSE ) {
if ( $txt !== FALSE ) {
if ( $txt == 'js' )
$this->inline_js[] = $txt;
elseif ( $txt == 'css' )
$this->inline_css[] = $txt;
}else{
if ( pathinfo( $link, PATHINFO_EXTENSION ) == 'css' ){
$this->css[] = link_tag( base_url( 'assets/css/' . trim( $link, "/\\" ) ) );
}else{
$this->js[] = '<script src="' . base_url( 'assets/js/' . trim( $link, "/\\" ) ) . '"></script>';
}
}
return $this;
}
and at last a function that put all your parts together;
protected function print_page(){
if ( $this->noEcho ) ob_clean();
$data=array();
$data[ 'title' ] = $this->title;
$data[ 'css' ] = is_array( $this->css ) ? implode( "\n", $this->css ) : '';
$data[ 'js' ] = is_array( $this->js ) ? implode( "\n", $this->js ) : '';
$data[ 'inline_css' ] = ( $this->inline_css ) ? '<style>' . implode( "\n", $this->inline_css ) . '</style>' : '';
$data[ 'inline_js' ] = ( $this->inline_js ) ? implode( "\n", $this->inline_js ) : '';
foreach ( $this->content as $section => $content ) {
$data[ $section ] = is_array( $content ) ? implode( "\n\n\n ", $content ) : $content;
} //$this->content as $section => $content
return $this->load->view( $this->body, $data );
}
now put all three together and extend your controller to this base controller;
now for the example page your are trying to build i would do:
Controller :
public function __construct() {
parent::__construct();
$this->title = 'Controller title';
$this->body = 'base/default';
//load all your assets.. if its across all pages then load them in MY_controller construct
$this->assets('jquery.min.js')
->assets('bootstrap.css')
->assets('alert("itworks");','js');//will be added to $inline_js
}
function index(){
$var = $This->some_model->get_data();
$this->output( array('some_View',$var) )
->output('<hr/>')
->output('THIS WILL BE IN $FOOTER','footer')
->print_page();
}
Now how clean is that :) ?;
now your controller will load view set on this->body and all pass all your sections to it.
so for above example your view will recieve 2 variables.
$content : ill contail some_view view +
$footer : will contain html we passed it to it;
$css,$js,$inline_js,$inline_css variables contain all you assets
$title contain your page title;
at end
i hope that i hope this small demo help you understand the unlimited possibilities that these 3 small functions can do thanks to CI native view loader.

Eval'ing Plugins System

What would be the best way to do this?
I'm given a template with some things in it like {:HELLO-WORLD:} tags in it.
I'm also given an array like:
Array
(
[0] => Array
(
[Name] => {:HELLO-WORLD:}
[Plugin] => "<?php return 'Hello World'; ?>"
[Settings] =>
)
)
What can I do to make sure {:HELLO-WORLD:} gets replaced with the output of Hello World?
I am currently attempting:
private function PluginReplacer($arr, $str){
$gsCt = count($arr);
$kv = array();
for ($i=0;$i<$gsCt;++$i){
$kv[$arr[$i]['Name']] = $arr[$i]['Plugin'];
}
return str_replace(array_keys($kv), $this->EvalCode(array_values($kv)), $str);
}
// Eval Some Code
private function EvalCode($var){
require_once('plugins.php');
$pr = new CloudCMSPluginRunner();
$pr->Code = $var;
$pr->SitePath = GetSiteAssetsPath($this->SiteID);
$pr->RunIt();
echo $pr->Error;
}
<?php
class CloudCMSPluginRunner {
public $Code = '';
public $Error = '';
public $SitePath = '';
private $DoNotAllow = array('echo', 'eval', 'phpinfo', '/`/', 'chmod', 'chown', 'umask', 'shell_exec',
'exec', 'escapeshellcmd', 'proc_open', 'proc_terminate', 'proc_get_status',
'passthru', 'proc_nice', 'system', 'escapeshellarg', 'ob_start', 'ob_end_clean',
'ob_get_clean', 'session_start', 'putenv', 'header', 'sleep', 'uwait', 'ini_set',
'error_reporting', 'chgrp', 'basename', 'clearstatcache', 'copy', 'delete',
'dirname', 'disk_free_space', 'disk_total_space', 'diskfreespace', 'fclose',
'feof', 'fflush', 'fgetc', 'fgetcsv', 'fgets', 'fgetss', 'file_exists', 'file_get_contents',
'file_put_contents', 'file', 'fileatime', 'filectime', 'filegroup', 'fileinode', 'filemtime',
'fileowner', 'fileperms', 'filesize', 'filetype', 'flock', 'fnmatch', 'fopen', 'fpassthru',
'fputcsv', 'fputs', 'fread', 'fscanf', 'fseek', 'fstat', 'ftell', 'ftruncate', 'fwrite', 'glob',
'is_dir', 'is_executable', 'is_file', 'is_link', 'is_readable', 'is_uploaded_file', 'is_writeable',
'is_writable', 'lchgrp', 'lchown', 'link', 'linkinfo', 'lstat', 'mkdir', 'move_uploaded_file',
'parse_ini_file', 'parse_ini_string', 'pathinfo', 'pclose', 'popen', 'readfile', 'readlink',
'realpath_cache_get', 'realpath_cache_size', 'realpath', 'rename', 'rewind', 'rmdir', 'set_file_buffer',
'stat', 'symlink', 'tempnam', 'tmpfile', 'touch', 'unlink', 'chdir', 'chroot', 'closedir', 'dir',
'getcwd', 'opendir', 'readdir', 'rewinddir', 'scandir', 'dio_close', 'dio_fcntl', 'dio_open', 'dio_read',
'dio_seek', 'dio_stat', 'dio_tcsetattr', 'dio_truncate', 'dio_write', 'finfo_buffer', 'finfo_close',
'finfo_file', 'finfo_open', 'finfo_set_flags', 'mime_content_type', 'inotify_add_watch', 'inotify_init',
'inotify_queue_len', 'inotify_read', 'inotify_rm_watch', 'setproctitle', 'setthreadtitle', 'xattr_get',
'xattr_list', 'xattr_remove', 'xattr_set', 'xattr_supported');
public function RunIt(){
$valid = $this->CheckIt();
if($valid){
eval($this->Code);
}else{
// code is invalid
$this->Error = 'The code in this plugin is invalid.';
return null;
}
}
private function CheckIt(){
$ret = false;
ob_start(); // Catch potential parse error messages
$code = eval('if(0){' . "\n" . $this->Code . "\n" . '}');
ob_end_clean();
$ret = ($code !== false);
// run a check against the dissallowed
$ret = (stripos($this->Code , $this->DoNotAllow) !== false);
// make sure any path is there's and there's alone
$ret = (stripos($this->Code , $this->SitePath) !== false);
return $ret;
}
}
?>
But nothing is happenning... in fact the page I am attempting to run this on blanks out (meaning there is an error happenning)
You're generating code formatted as:
eval("function GetPageWeAreOn(){$p=explode('/',$_SERVER['REQUEST_URI']);return $p[1];}");
What's happening is that PHP is interpreting the variables wrongly - instead of passing them in to the eval'ed function, it's interpolating them first.
I've avoided the error by escaping them:
eval("function GetPageWeAreOn(){\$p=explode('/',\$_SERVER['REQUEST_URI']);return \$p[1];}");
You can avoid the need for escaping by putting your string to be eval'ed into single quotes, too - that doesn't try to interpolate variables:
eval('function GetPageWeAreOn(){$p=explode("/",$_SERVER["REQUEST_URI"]);return $p[1];}');

Looping class, for template engine kind of thing

I am updating my class Nesty so it's infinite but I'm having a little trouble.... Here is the class:
<?php
Class Nesty
{
// Class Variables
private $text;
private $data = array();
private $loops = 0;
private $maxLoops = 0;
public function __construct($text,$data = array(),$maxLoops = 5)
{
// Set the class vars
$this->text = $text;
$this->data = $data;
$this->maxLoops = $maxLoops;
}
// Loop function
private function loopThrough($data)
{
if( ($this->loops +1) > $this->maxLoops )
{
die("ERROR: Too many loops!");
}
else
{
$keys = array_keys($data);
for($x = 0; $x < count($keys); $x++)
{
if(is_array($data[$keys[$x]]))
{
$this->loopThrough($data[$keys[$x]]);
}
else
{
return $data[$keys[$x]];
}
}
}
}
// Templater method
public function template()
{
echo $this->loopThrough($this->data);
}
}
?>
Here is the code you would use to create an instance of the class:
<?php
// The nested array
$data = array(
"person" => array(
"name" => "Tom Arnfeld",
"age" => 15
),
"product" => array (
"name" => "Cakes",
"price" => array (
"single" => 59,
"double" => 99
)
),
"other" => "string"
);
// Retreive the template text
$file = "TestData.tpl";
$fp = fopen($file,"r");
$text = fread($fp,filesize($file));
// Create the Nesty object
require_once('Nesty.php');
$nesty = new Nesty($text,$data);
// Save the newly templated text to a variable $message
$message = $nesty->template();
// Print out $message on the page
echo("<pre>".$message."</pre>");
?>
Here is a sample template file:
Dear <!--[person][name]-->,
Thanks for contacting us regarding our <!--[product][name]-->. We will try and get back to you within the next 24 hours.
Please could you reply to this email to certify you will be charged $<!--[product][price][single]--> for the product.
Thanks,
Company.
The problem is that I only seem to get "string" out on the page... :(
Any ideas?
if(is_array($data[$keys[$x]]))
{
$this->loopThrough($data[$keys[$x]]);
}
else
{
return $data[$keys[$x]];
}
You need to return from the first if statement.
if(is_array($data[$keys[$x]]))
{
return $this->loopThrough($data[$keys[$x]]);
}
else
{
return $data[$keys[$x]];
}
This will get you a result back when you recurse. You're only getting "string" back right now because that key is only 1 level deep in your array structure.

Categories