I need to send $user to inside the class and render function to make it global variable.
because it not work unless i write "$user" in the class and render function.
Please help me.
$user = 'admin';
class Template{
public function render($template_name)
{
global $user;
$path = $template_name . '.html';
if (file_exists($path))
{
$contents = file_get_contents($path);
function if_condition($matches)
{
$parts = explode(" ", $matches[0]);
$parts[0] = '<?PHP if(';
$parts[1] = '$' .$parts[1]; // $page
$parts[2] = ' ' . '==' . ' ';
$parts[3] = '"' . substr($parts[3], 0, -1) . '"'; //home
$allparts = $parts[0].$parts[1].$parts[2].$parts[3].') { ?>';
return $allparts.$gvar;
}
$contents = preg_replace_callback("/\[if (.*?)\]/", "if_condition", $contents);
$contents = preg_replace("/\[endif\]/", "<?PHP } ?>", $contents);
eval(' ?>' . $contents . '<?PHP ');
}
}
}
$template = new Template;
$template->render('test3');
Never, never use global variables
They are awful, they bind your code to context and they are side-effect - if you'll change your variable somewhere in 2054-th line of 119-th included file, the behavior of your application will change and then good luck with debugging that.
Instead you should either pass your user in method's parameters:
public function render($template_name, $user)
or create property in class instance:
class Template
{
protected $user = null;
public function render($template_name)
{
//access to $this->user instead of $user
}
//...
}
-and, of course, initialize $user property in class constructor.
Related
I'm trying to replace {{key}} items in my $text with values from a passed array. but when I tried adding the print_r to see what was going on I got a Undefined variable: kvPairs error. How can I access my variable form within the preg_replace_callback?
public function replaceValues($kvPairs, $text) {
$text = preg_replace_callback(
'/(\{{)(.*?)(\}})/',
function ($match) {
$attr = trim($match[2]);
print_r($kvPairs[strtolower($attr)]);
if (isset($kvPairs[strtolower($attr)])) {
return "<span class='attr'>" . $kvPairs[strtolower($attr)] . "</span>";
} else {
return "<span class='attrUnknown'>" . $attr . "</span>";
}
},
$text
);
return $text;
}
Update:
I've tried the global scope thing, but it doesn't work either. I've added 2 print statements to see whats doing on, one inside and one outside the preg_replace_callback.
public function replaceValues($kvPairs, $text) {
$attrTest = 'date';
print_r("--" . strtolower($attrTest) . "--" . $kvPairs[strtolower($attrTest)] . "--\n");
$text = preg_replace_callback(
'/(\{{)(.*?)(\}})/',
function ($match) {
global $kvPairs;
$attr = trim($match[2]);
print_r("==" . strtolower($attr) . "==" . $kvPairs[strtolower($attr)] . "==\n");
if (isset($kvPairs[strtolower($attr)])) {
return "<span class='attr'>" . $kvPairs[strtolower($attr)] . "</span>";
} else {
return "<span class='attrUnknown'>" . $attr . "</span>";
}
},
$text
);
return $text;
}
The output I get is:
--date--1977-05-20--
==date====
As your callback function is a closure, you can pass extra arguments via use
function ($match) use ($kvPairs) {
...
}
better than polluting the global space
I have this function but it's not good. It's making it hard to debug my code:
fun... {
eval('?>' . str_replace(
'{yield}',
file_get_contents('templates/' . $template . '.phtml'),
file_get_contents('templates/layouts/' . $layout . '.phtml')
));
}
Please let me know of better replacements.
Thanks.
function render($template, $layout) {
$cache = "wherever/you/put/the/cache/file/{$template}_{$layout}.phtml";
if (!file_exists($cache)) {
$template = file_get_contents('templates/' . $template. '.phtml');
$layout = file_get_contents('templates/layouts/' . $layout . '.phtml');
$output = str_replace('{yield}', $template , $layout);
file_put_contents($cache, $output);
} else {
include($cache);
}
}
using output buffering is the best way for acheiving a filled template data
ob_start();
include "my/template/link.phtml";
$content = ob_get_contents();
ob_end_clean();
I need to find a string within a string ("foo", for example) and then replace it with a PHP code. Is it possible?
I'm creating a Joomla Plugin. When my article has something like "{foo}", i will replace it with an include (require, or whatever).
I've made something like:
public function onContentBeforeDisplay($context, &$row, &$params, $page=0)
{
// $row->text has the article text ...
if (preg_match('/{contact-form}/', $row->text))
{
require_once(dirname(__FILE__) . DS . 'tmpl' . DS . 'default.php');
}
}
But this code will insert default.php at the beginning. I want to replace it in {contact-form} tag.
Thank you.
You can use the PHP function "substr_replace()", whose details are given here.
\n";
/* These two examples replace all of $var with 'bob'. */
echo substr_replace($var, 'bob', 0) . "<br />\n";
echo substr_replace($var, 'bob', 0, strlen($var)) . "<br />\n";
/* Insert 'bob' right at the beginning of $var. */
echo substr_replace($var, 'bob', 0, 0) . "<br />\n";
/**
* Your food & search is here
*/
/* These next two replace 'MNRPQR' in $var with 'bob'. */
echo substr_replace($var, 'bob', 10, -1) . "<br />\n";
echo substr_replace($var, 'bob', -7, -1) . "<br />\n";
/* Delete 'MNRPQR' from $var. */
echo substr_replace($var, '', 10, -1) . "<br />\n";
?>
You can create a PHP file that matches the keyword (like: foo.php) and simply extract the keyword from the text and use it to include that file.
For example:
<?php
$str = "This is {foo} text";
$includePath = "/path/to/my/files/";
// Careful with the Regular Expression. If you allow chars like . in the
// keyword this could create a security problem. (Dots allow you to go backwards
// which would allow people to execute files outside your path.)
if (preg_match_all('/\{([\w]+)\}/', $str, $matches))
{
foreach ($matches[1] as $_match)
{
$filePath = $includePath . $_match . ".php";
if (file_exists($filePath))
{
include $filePath;
}
else
{
trigger_error("File does not exist '$filePath'.", E_USER_WARNING);
}
}
}
?>
I think you just want this, don't you?
<?php
$replacement = file_get_contents('myfile.php');
$content = str_replace('{foo}', eval($replacement), $content);
?>
If you need to replace any string on series of files on your remote server and well you don't have time for it! , here is your solution , I hope it can help someone.
////
//PHP 5.3 + Class find and replace string in files
//
//by Bruce Afruz
//
//2013
//
//example usage for single file:
//
//$new = new fileReplacement('./');
//$new->setExt("check.php");
//$new->changeContents("hello", "goodbye");
//
//example usage for multiple files:
//
//$new = new fileReplacement('./test');
//$new->setExt("*.html");
//$new->changeContents("hello", "goodbye");
//
//to change directory:
//
//$new = new fileReplacement('./test');
//$new->setDir("./test2");
//$new->setExt("*.html");
//$new->changeContents("hello", "goodbye");
////
class fileReplacement
{
private $ext , $dir ;
public function getDir() {
return $this->dir;
}
public function setDir($dir) {
$this->dir = $dir;
}
public function getExt() {
return $this->ext;
}
public function setExt($ext) {
$this->ext = $ext;
}
function __construct($dir) {
$this->dir = $dir;
}
public function rglob($pattern = '*', $flags = 0, $path = '') {
chdir($this->getDir());
$paths = glob($path . '*', GLOB_MARK | GLOB_ONLYDIR | GLOB_NOSORT);
$files = glob($path . $pattern, $flags);
foreach ($paths as $path) {
$files = array_merge($files, $this->rglob($pattern, $flags, $path));
}
return $files;
}
public function changeContents($replace , $sentence , $flags = 0, $path = '') {
$all = $this->rglob($this->getExt() , $flags, $path);
foreach ($all as $file) {
$filename = $file;
$handle = fopen($filename, "r");
$contents = fread($handle, filesize($filename));
fclose($handle);
$contents = str_replace($replace , $sentence, $contents);
if (is_writable($filename)) {
if (!$handle = fopen($filename, 'w+')) {
echo "Cannot open file ($filename)
";
exit;
}
// Write $contents to our opened file.
if (fwrite($handle, $contents) === FALSE) {
echo "Cannot write to file ($filename)
";
exit;
}
echo "Success, wrote content to file ($filename)
";
fclose($handle);
} else {
echo "The file $filename is not writable
";
}
}
}}
//file foo.php
<?php
namespace foo;
class foo{
function __construct(){
echo "hello";
}
}
?>
//file index.php
<?php
require_once("foo.php");
echo __NAMESPACE__;
?>
My question is, from my index.php file, is it possible to know what the namespace of foo.php is without reading the file contents and doing a regular expression on it? That just seems like a lot of overhead.
///EDIT
I'd really like to be able to dynamically add the namespace to the included file.
<?php
namespace dynamic;
require_once("foo.php");
echo __NAMESPACE__;
?>
I want to allow for third-party plugins, but php namespaces seems terrible. I don't want to have the plugin editors have to create a namespace.
No. But you could trick it this way round:
//file foo.php
<?php
namespace foo;
//...
return __NAMESPACE__; // must be last line
?>
And for reading it out:
//file index.php
<?php
$ns = require_once("foo.php");
Well, you could scan the class namespace. It contains namespaces. It's the PHPUnit way of doing things. So i.e.:
$namespaces = get_current_namespaces();
include 'plugin/main.php';
$newNamespaces = get_current_namespaces();
array_diff($namespaces, $newNamespaces)
Here is how you can implement get_current_namespaces(): is it possible to get list of defined namespaces
If you know the file, you can simply extract the namespace form it :).
function extract_namespace($file) {
$ns = NULL;
$handle = fopen($file, "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
if (strpos($line, 'namespace') === 0) {
$parts = explode(' ', $line);
$ns = rtrim(trim($parts[1]), ';');
break;
}
}
fclose($handle);
}
return $ns;
}
And you will be not constrain to return something at the end of file that can be broke from exit or other return instructions.
I worked out the fairly laborious manual way to do this.
Like discussed at top the process itself is simple:
get your list of files for each file. Now for each file:
create a random namespace id
trim file and replace the first start tag
add namespace id and start tag to file
write to temp file
import temp file
do any reflection required then cleanup
I've got an example with some zend here.... probably not the most efficient but it works.
<?php
//first setup zend
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__)."/../zend/library/");
require_once 'Zend/Loader/Autoloader.php';
$loader = Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace(dirname(__FILE__)."/../zend/library/");
//include my extender class
class Zend_Reflection_File_WithNamespace extends Zend_Reflection_File {
public function getFunctionsWithNamespace($namespace = '', $reflectionClass = 'Zend_Reflection_Function')
{
$functions = array();
foreach ($this->_functions as $function) {
$newName = $namespace . "\\" . $function;
$instance = new $reflectionClass($newName);
if (!$instance instanceof Zend_Reflection_Function) {
require_once 'Zend/Reflection/Exception.php';
throw new Zend_Reflection_Exception('Invalid reflection class provided; must extend Zend_Reflection_Function');
}
$functions[] = $instance;
}
return $functions;
}
}
//find file(s)
$startDir = 'hello/';
//$tempDir = 'php://temp/resource=';
$tempDir = 'temp/';
$fileList = scandir($startDir);
function ppPrintR($data) {
echo "<pre>";
print_r($data);
echo "</pre>";
}
//Now loop through each file, first writing to temp, including and then testing
foreach ($fileList as $key => &$fileItem) {
if (is_file($startDir . $fileItem)) {
//Take file and convert it
$findDir = $startDir . $fileItem;
echo $startDir . $fileItem;
$inContents = file_get_contents($findDir);
$randIden = 'm' . preg_replace('/\.|\s/', '', microtime());
//Replace the <?[php] at the start of the file with <? namespace xyz;
$inContents = trim($inContents);
$addString = 'namespace ' . $randIden . '; ';
$longTagPos = strpos($inContents,'<?php');
$shortTagPos = strpos($inContents,'<?');
if ($longTagPos !== false && $longTagPos < 10) {
$inContents = str_replace('<?php', '', $inContents);
$addString = '<?php ' . $addString;
}
else if ($shortTagPage !== false && $longTagPos < 10) {
$inContents = str_replace('<?', '', $inContents);
$addString = '<? ' . $addString;
}
$outContents = $addString . $inContents;
//Now write and require new temp file
$tempItem = $tempDir . $fileItem;
file_put_contents($tempItem, $outContents);
require($tempItem);
//Now do normal things
$reflectedFile = new Zend_Reflection_File_WithNamespace($tempItem);
echo 'Before<br/>';
$functions = $reflectedFile->getFunctionsWithNamespace($randIden);
echo 'After<br/>';
//Now foreach function, read params and consider execution
foreach($functions as &$functionItem) {
echo $functionItem->name . "<br/>";
$functionParams = $functionItem->getParameters();
ppPrintR($functionParams);
}
//FIXME should clean here
}
}
?>
I'm just experimenting first of all.
I just came up with an idea of making my own in a simple way here:
class Template
{
function parse($template_file, $braces)
{
if(file_exists($template_file))
{
$template = file_get_contents($template_file);
foreach($braces as $brace => $replacement)
{
$brace = trim(strtoupper($brace));
$build = str_replace('{' . $brace . '}', $replacement, $template);
}
echo $build;
}
else
{
trigger_error('Template file does not exist: ' . $template_file, E_ERROR);
}
}
}
This in order to work:
$template = new Template();
$template->parse('index_body.html', array('ONE' => 'one',
'TWO' => 'two',
'THREE' => 'three'));
index_body.html:
{ONE}
{TWO}
{THREE}
The problem is, that it only outputs:
{ONE} {TWO} three
It always replaces the last brace, how come not the whole array?
$build = str_replace('{' . $brace . '}', $replacement, $template);
^^^^^^^^^
You're always replacing against the original template, never against the updated one. Either keep assigning $template, or update $build
$template = file_get_contents($template_file);
$build = $template;
foreach($braces as $brace => $replacement)
{
$brace = trim(strtoupper($brace));
$build = str_replace('{' . $brace . '}', $replacement, $build);
}
It only replaces the last place because in each case, you're replacing the value in the original $template variable. It's not updating the variable each iteration.
You echo $build, which is being reassigned every foreach iteration.
You should've written this instead
$template = str_replace('{' . $brace . '}', $replacement, $template);
How about using like full php engine power (similar to smarty interface):
just for experimenting:
class Template {
private $_file;
private $_variables = array();
public function __construct($file = null) {
$this->_file = $file;
}
public function set($key, $value) {
$this->_variables[$key] = $value;
}
public function fetch($file = null) {
if (!$file) {
$file = $this->_file;
}
extract($this->_variables);
ob_start();
require($file);
$content = ob_get_contents();
ob_end_clean();
return $content;
}
public function display($file = null) {
if (!$file) {
$file = $this->_file;
}
$result = $this->fetch($file);
echo $result;
}
}
=============
$tpl = new Template('hello.tpl');
$tpl->set('world', 'earth');
$tpl->display();
=============
Template sample:hello.tpl
Hello <?=$world;?>
Your $build is overwritten in each iteration. This will solve the issue.
class Template
{
function parse($template_file, $braces)
{
if(file_exists($template_file))
{
$template = file_get_contents($template_file);
foreach($braces as $brace => $replacement)
{
$brace = trim(strtoupper($brace));
$temp = str_replace('{' . $brace . '}', $replacement, $template);//create a temporary array
$build = array_merge($build ,$temp);
}
echo $build;
}
else
{
trigger_error('Template file does not exist: ' . $template_file, E_ERROR);
}
}
}