Allowing users to make template- Scan code for functions - php

I am currently creating a web app and I would like to allow my users to create a template. I would only allow them to use HTML and some functions to get some values, so I have some functions like
getDescription(); but since its PHP I also have other function (e.g. phpinfo();) which I don't want them to use.
Is it possible to set a filter (like in_array) to check if functions other than declared are used?
Or is there an Template engine or something else which does that.
I am very new to templating and I couldn't find anything.

If they are only creating HTML templates, you could allow them to put for example;
<div>
[PHP]getDescriptions()[PHP]
</div>
<div>
[PHP]phpinfo()[/PHP]
</div>
Then in your parsing file when they save or whatever, you could have
$allowedFunctions = array('getDescriptions');
$input = '';//html from the template
foreach($allowedFunctions as $key => $value){
$myVal = $value();
$input = str_replace('[PHP]'.$value.'()[/PHP]',$myVal,$input);
}
This would replace [PHP]getDescriptions()[/PHP] with whatever is returned from getDescriptions()...
and phpinfo() wouldnt change.

you can check if a function exists with function_exists. If you want them to use the functions you defined for that purpose only you could prefix those function with something like 'tpl_*". like this:
function tpl_getDescription() {/*code here*/}
and then when you user tries to implement a function like getDescription you add "tpl_" to it and check if that function exists with function_exists().
if(function_exists('tpl_' . $userFuncName))
{
call_user_func('tpl_' . $userFuncName)
}
that way even if the user tries to evoke a native php function tpl_ will be prefixed and if will return false.

Yes, you could easily make a script that enumerates all user functions in an external file. Lets say you have this "template", template.php :
<?
function getDescription() {
}
function userFunc() {
}
function anotherFunction() {
}
?>
then you could get a list of all functions in template.php this way :
<?
include('template.php');
$functions = get_defined_functions();
echo '<pre>';
print_r($functions['user']);
echo '</pre>';
?>
would output :
Array
(
[0] => getdescription
[1] => userfunc
[2] => anotherfunction
)
I would call this script through AJAX, like getfunctions.php?file=template.php which returned a JSON with all user functions inside template.php.

Related

PHP Custom CMS - How to handle settings

I'm currently trying to find a way to handle settings on my custom CMS (just a playground to learn PHP). I have database table that stores all settings. My temporary solution is a function that returns one dimensional array with query results.
// Get settings from db.
function getPanelOptions( $pdo ) {
$options = [];
$getOptions = $pdo->query( 'SELECT option_name, option_value FROM bp_options' );
while( $result = $getOptions->fetch() ) {
$options[ $result['option_name'] ] = $result['option_value'];
}
return $options;
}
$bpOptions = getPanelOptions( $pdo ); // Get settings to arr.
// Example use
if( $bpOptions['post_max_lenght'] === 400 ) ...
I've read a lot that global variables are not best way to do this, so I call function in file that is included on every page. I don't have problem with using hard coded variable, because I won't change it (even so I can replace all occurrences in sublime). My biggest problem is that I can't find a way to use settings to create a 'wrapper' functions like in WordPress, for example 'getHtmlLang()'. In JS it would be easy, but in PHP I need to pass setting to this function, at it gets to lengthy.
// Now i use
<html lang="<?php echo $bpOptions['panel_lang']; ?>">
// I'd like some wrapper function.
<html <?php getHtmlLang() ?>>
I'm not familiar with OOP in PHP so maybe this is way to achieve this, or should I simply use global because it's justified?

preg_replace not retrieving correct data

I'm using my own cms from scratch, so, i'm adding useful functions for my system, but i got stuck on this:
A phrase is being loaded from lang file on array, in this case, $lang['sign']['server'] = 'Sign in with your {{servername}} registered account:';, and then, by a function, {{servername}} must be replaced by $config['servername'].
What i have so far on my functions class is the following:
public function replaceTags($text)
{
global $config;
return preg_replace("/{{(.*?)}}/" , $config[strtolower("$1")], $text) ;
}
Im calling this function here: $main->set('ssocial', $FUNC->replaceTags($lang['sign']['social']));, but the result is Sign in with your registered account: instead of Sign in with your "Server Name Goes Here" registered account.
Any ideas about why the preg_replace is not retrieving the value?
Also, when $config[”$1”] is inside '' like this '$config[”$1”]', the output is Sign in with your $config[”servername”] registered account:, so i have no clues about what's wrong.
Thanks in advance.
This is a quick and dirty working example using preg_replace_callback
<?php
$config = array('server' => 'my custom text');
function handler($matches){
global $config;
return $config[$matches[1]];
}
function replaceTags($text)
{
return preg_replace_callback("/{{(.*?)}}/" , 'handler', $text) ;
}
print replaceTags("Hello {{server}}");
Output:
Hello my custom text
As for why your code doesn't work: the second parameter of preg_replace is $config[strtolower("$1")], so php will literally look for key "$1" in $config, which probably doesn't exist.

Zend View array variable inside a partialLoop

Here is the code in my controller:
$this->view->myArray = array();
$this->view->test = "";
$out = $this->view->partialLoop('tab/partial.phtml', $data);
echo $this->view->test; // Output: This works
echo count($this->view->myArray); // Output: 0
And the partial partial.phtml:
$v->test = $this->partialLoop()->view;
$v = "This works";
echo $v->test; // Output: This works
$v->myArray[] = "hello";
echo count($v->myArray); // Output: 0
I don't think that accessing view variables from a partialLoop is a wonderful idea. That aside, why doesn't it work for my array variable?
it doesn't work because you don't have access to the view variables in the partial. You have access to the data you pass to the partial.
$out = $this->view->partialLoop('tab/partial.phtml', $data);
This line of code would have access to the information contained in $data.
So this code in your current partial is basically meaningless:
$v = $this->partialLoop()->view; //you choose to assign view data to the partial, and I don't think it's working as expected.
//By not passing any args to the partial you have at least some access to the view object.
$this->view->test = "This works";//assign data to view locally
echo $v->test; // you seem to be echoing out locally assigned data
$v->myArray[] = "hello";//you didn't assign this to the view
echo count($v->myArray); // myArray probably doesn't exist in this context or dosen't work as expected. If you make this an associative array it might work.
I don't think I've ever seen partials used in quite this manner before. The point of the partial is to establish a different variable scope for a specific portion of the view.
The partial and partialLoop are view helpers so the only action you need to take in your controller (data may be or come from a model as well) is to make available any data you want to use in your partials as well as any data you want available in your normal view scope.
//in a controller
public function userAction() {
$model = Application_Model_DbTable_User();//Table columns = id, name, role
$this->view->partailData = $model->fetchAll();//assign data to view that we want to use in partial, should be an array or object.
}
//in a view script
<?php
//pass the path to the partial as the first arg and the data to be displayed as the second arg
echo $this->partialLoop('/path/to/partial.phtml', $this->partialData);
//we could pass data explicitly as well
echo $this->partial('/path/to/partial.phtml', array('id'=>1,'name'=>'jason','role'=>'user'));
?>
//now for our partial.phtml
//this could be used a simple partial or as a partialLoop
<p>My name is <?php echo $this->name ?>.</p>
<p>My data file id is <?php echo $this->id ?>.</p>
<p>My access control role is <?php echo $this->role ?>. </p>
<!-- name, id and role would be column names that we retrieved from the database and assigned to the view -->
To use a partial or partialLoop you need to pass an array of some type or an object that implements toArray().
[EDIT]
Clean up your code your still in left field.
//controller code
$this->view->myArray = array();
//view code
<?php $v = $this->partial()->view ?>
<?php $v->myArray[] = 'newName' ?>
<?php Zend_Debug::dump(count($this->partial()->view->myArray)) ?>
//my output =
int(1)
I don't seem to be able to pass the view any further then this, if I assign to an actual partial script and attempt to output the view object errors are thrown:
//my view again
<?php echo $this->partial('partial.phtml', $this->partial()->view) ?>
//This and attempts similar result in the error
/*Catchable fatal error: Object of class Zend_View could not be converted to string in E:\www\home-local\application\views\scripts\partial.phtml on line 1*/
//when the partial.phtml looks like
<?php echo $this />
//however when I access the data available in the view
<?php echo $this->myArray[0] ?>
//the result works and the output is
newName
it looks like an empty partial() (partialLoop()) call will give you access to the view object, when you already have access to the view object. If you leave the scope of the view object you will have only the access available to your current scope as provided by __get() and __call().
I hope I was able to explain this enough to help.
maybe you cant set the value of $v or the item because its private or static or discarded
also from the code you posted its using recursion which could make it a lot more breakable (ie the controller is referencing the views data, and the view is setting it or hasnt set it or has set it twice)
agreed i dont think accessing view var's from a partialLoop is a good idea.
edit:
$this->view->assign('variablename', $my_array);
I think the variable is otherwise "lost" on the Rerender, so work on your variables in your controller, and before you are done assign them to the view. I wouldn't really do array operations on $this->view->myArray

Query string, populating a page from DB or file

Is this facebook link populated fully from the DB? Or, is it a physical file with PHP in it? Just, how is this page called?
http://www.facebook.com/profile.php?id=49300915&sk=photos
They probably do something like:
if(isset($_GET['id'], $_GET['sk'])) {
mysql_query("SELECT info, photos FROM users WHERE id = '$id'");
}
I'm trying to ask, how do they include this page? Is it like Drupal / any CMS where the PHP and page is stored in the DB, or is it a physical file on the server? If the latter, what's the best way to get the file (case insensitive URL)?
I would have a class with a single method, which reads 'sk' and runs another method, depending on what it's value is.
One method would be 'photos' which would read 'id' and fetch a photo from the database. It would then run another method, displayPage, which will display a page from that data.
The displayPage method takes a "template" filename and an array of variables to provide to the template. It sets up a smarty object, provides the variables, and instructs it to display the template.
Inside the template, I'd include another template for the global header that's on every page in the site, then i'd have the html page content, using smarty to insert dynamic values, then include a global footer.
Note that i've simplified this system a lot. A real page like that would take me a week to write all the code, since a big website does a lot of stuff just to display a simple page (for example: find out if the logged in user actually has access to the page... i don't have access to the example one you gave).
<?php
// profile.php
class ProfileController
{
public function run()
{
if ($_GET['sk'] == 'photos')
return $this->photosPage();
}
protected function photosPage()
{
$id = (int)$_GET['id'];
$result = mysql_query("select * from photo where id = $id");
$photo = mysql_fetch_object($photo);
$this->displayPage('view-photo.tpl', array('photo' => $photo);
}
protected function displayPage($templateFile, $templateVariables)
{
$smarty = new Smarty();
foreach ($templateVariables as $variableName => $variableValue) {
$smarty->assign($variableName, $variableValue);
}
$smarty->display($templateFile);
}
}
$conntroller = new ProfileController();
$controller->run();
And the smarty code:
<!-- view-photo.tpl -->
{include file='head.tpl'}
<h1>View Photo {$photo->name|escape}</h1>
<img src="{$photo->src|escape}" width="{$photo->width|escape} height="{$photo->height|escape}>
{include file='foot.tpl'}

PHP Hook Function

Can I basically do something like:
register_function_hook('myFunctionHook');
so then when any function is run:
functionA(); //The hook runs myFunctionHook();
anoterFunction(); //The hook runs myFunctionHook();
Class::functionA(); //The hook runs myFunctionHook();
Does such a thing exist?
-- Edit --
What I want to do is to get a breakdown of durations of each function. Ie. Performance Tuning. I want to get an idea of what takes all the time without installing xDebug on my Apache server, however I don't know if it is possible.
It's possible with register_tick_function(), also check this comment on the PHP manual:
$script_stats = array();
$time = microtime(true);
function track_stats(){
global $script_stats,$time;
$trace = debug_backtrace();
$exe_time = (microtime(true) - $time) * 1000;
$func_args = implode(", ",$trace[1]["args"]);
$script_stats[] = array(
"current_time" => microtime(true),
"memory" => memory_get_usage(true),
"file" => $trace[1]["file"].': '.$trace[1]["line"],
"function" => $trace[1]["function"].'('.$func_args.')',
"called_by" => $trace[2]["function"].' in '.$trace[2]["file"].': '.$trace[2]["line"],
"ns" => $exe_time
);
$time = microtime(true);
}
declare(ticks = 1);
register_tick_function("track_stats");
// the rest of your project code
// output $script_stats into a html table or something
This "hooks" to everything, not just functions but I think it fits your purpose.
No, its not possible the way you like
But You can achieve something close with inheritance.
class Vehicle {
function __construct() {
$this->hookFunction();
}
function hookFunction() {
//
}
}
class Car extends Vehicle {
}
Class Toyota extends Car {
}
new Toyota(); // will you hook function
// this exclude static call to member functions, or other inline functions.
What you looking for is called profiler. And PQP looks like one, which is standalone.
Instead of polluting the code, you should use a real Profiler, like that one provided by xdebug
Not sure if the Topic Starter needs this anymore, but perhaps others can still benefit from this.
There is a PHP lib, written completely in PHP, that allows you to do exactly what you want.
Here's an article about how it works, including the source code:
http://phpmyweb.net/2012/04/26/write-an-awesome-plugin-system-in-php/
It allows you to register a function from a class to be hooked. So it basically executes your code first, and then you determine wether you want to call the original function too after your code has been executed.

Categories