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
";
}
}
}}
Related
i want rename all files and folder recursively i written a function that works and rename files but my problem when occurred when i make array of files and folders in a path, its not sort as parent child
so when i rename parent folder first , in next loop when function wants rename child said "No such file or directory" its true Error cause parent folder renamed a couple minutes ago
i changed my code but not help me
code for reading files and folder from ftp :
if (!self::ftp_is_dir($resource, $thisPath)) {
// for Files (anything that isnt a readable directory)
if ($first == TRUE) {
return array("Path doesn't Exist (" . $thisPath . ")");
}
$theList[] = $thisPath;
return $theList;
} else {
$contents = ftp_nlist($resource, $thisPath);
// For empty folders
if (count($contents) == 0) {
$theList[] = $thisPath;
return $theList;
} else {
$theList[] = $thisPath;
}
// Recursive Part
foreach ($contents As $file) {
$theList = self::ftp_nlistr($resource, $file, $theList, FALSE);
}
return $theList;
}
and this return array like this
enter image description here
and this code i used for renaming folder and files
$replacers = array(" ", "", " ", "-=", "=-", '©',"!", ";", "#", "#", "'", '<', '>');
foreach ($paths as $path) {
if (preg_match('/' . implode('|', $replacers) . '/', $path) != 0) {
$route = preg_replace('/ftp/', "ftp://ftp.mylocal.co", $path, 1);;
if (is_dir($route)) {
$newName = str_replace($replacers, "_", basename($path));
$directory = pathinfo($path);
if (ftp_rename($connectionID, $path, $directory['dirname'] . '/' . $newName)) {
Logger::setLog('renaming', "Renaming: $path to $newName");
} else {
Logger::setLog('failed to renaming', "Renaming: $path to $newName");
}
} else {
$newName = str_replace($replacers, "_", basename($path));
$directory = pathinfo($path);
if (ftp_rename($connectionID, $path, $directory['dirname'] . '/' . $newName)) {
Logger::setLog('renaming', "Renaming: $path to $newName");
} else {
Logger::setLog('failed to renaming', "Renaming: $path to $newName");
}
}
}
}
[1]: https://i.stack.imgur.com/xk3kx.png
public static function ftp_is_dir($conn, $dir)
{
$cdir = ftp_pwd($conn);
if (#ftp_chdir($conn, $dir)) {
ftp_chdir($conn, $cdir);
return true;
} else {
return false;
}
}
If you have:
+ folder
- file1
- file2
+ folder with space
- file with space
... you currently first rename /folder with space to /folder_with_space.
And then you try to rename /folder with space/file with space to /folder with space/file_with_space. But that file does not exist anymore.
The easiest solution is to actually first rename children, then parent:
$contents = ftp_nlist($resource, $thisPath);
// Recursive Part
foreach ($contents As $file) {
$theList = self::ftp_nlistr($resource, $file, $theList, FALSE);
}
$theList[] = $thisPath;
return $theList;
I have an a string declared at the top of my PHP script:
$dirname = "./rootfs/home/".$user."/";
After running the code, that string should be replace so it looks like this:
$dirname = "./rootfs/home/".$user."/testdir/";
Is there any way to replace the content? This is a dumb question for sure, but didn't found any way to do it, thanks! :D
Code I'm using:
Main PHP:
<?php
//Variables
$rootfs = "rootfs/";
$user = "www";
$dirname = "./rootfs/home/".$user."/";
//Variables
//Commands on rootfs/bin/
include($rootfs."/bin/ls.php");
include($rootfs."/bin/about.php");
include($rootfs."/bin/echo.php");
include($rootfs."/bin/uname.php");
include($rootfs."/bin/apt-get.php");
include($rootfs."/bin/whoami.php");
include($rootfs."/bin/cd.php");
//Commands on rootfs/bin/
$command=$_POST['command'];
$commandexp = explode(" ", $command);
switch ($commandexp[0]) {
case "cd":
//$dirname = "./rootfs/home/".$user."/";
//$prompt = cd($dirname, $commandexp[1]);
$dirname .= cd($dirname, $commandexp[1]);
echo $dirname;
break;
case "ls":
switch ($commandexp[1]) {
case "-la":
//$dirname = "./rootfs/home/".$user."/";
$files = ls($dirname);
foreach($files as $value){
$prompt .= substr(sprintf('%o', fileperms($dirname.$value)), -4)." ".$user." ".$value."<br>";
}
break;
case "--help":
$prompt = "Usage: ls [-la]";
break;
default:
echo $dirname." ";
$files = ls($dirname);
foreach($files as $value){
$prompt .= $value." ";
}
break;
}
break;
default:
$prompt = "command not found";
}
echo $prompt;
?>
The cd.php
<?php
function cd($actualdir, $dir) {
//echo $actualdir.$dir."<br>";
if(file_exists($actualdir.$dir)) {
echo $dir;
return $dir;
} else {
return "no";
}
}
?>
The ls.php
<?php
function ls ($directory) {
// create an array to hold directory list
$results = array();
// create a handler for the directory
$handler = opendir($directory);
echo $handler;
// open directory and walk through the filenames
while ($file = readdir($handler)) {
// if file isn't this directory or its parent, add it to the results
if ($file != "." && $file != "..") {
$results[] = $file;
}
}
// tidy up: close the handler
closedir($handler);
// done!
return $results;
}
?>
To add a string just do that:
$dirname .= "/testdir/";
To concatenate one string to the end of another string: $dirname .= 'testdir/'
To reassign a totally new string to the variable: $dirname = 'This is the new string'
See String Operators
Is this what you want:
$dirname .= "testdir/";
Finally used a session variable for storing the actual dir
//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 have a script. It recieves a variable called $node, which is a string; for now, lets assume the variable value is "NODEVALUE". When the script is called, it takes the variable $node, and tries to find an image called NODEVALUE.png. If it cant find that image, it then checks for NODEVALUE.jpg, if it can't find that it looks for NODEVALUE.gif... and after all that, it still cant find, it returns RANDOM.png.
Right now I am doing this script as follows:
if (file_exists($img = $node.".png")) { }
else if (file_exists($img = $node.".jpg")) { }
else if (file_exists($img = $node.".gif")) { }
else
{
$img = 'RANDOM.png';
}
There has to be a better way than this... anyone have any ideas?
$list = array_filter(array("$node.png", "$node.jpg", "$node.gif"), 'file_exists');
if (!$img = array_shift($list)) {
$img = 'RANDOM.png';
}
Alternatives :
$list = scandir(".");
$list = preg_grep("#".preg_quote($node,'#')."\.(jpg|png|gif)$#", $list);
This returns a list of file names that start with $node and with a .jpg, .png or .gif suffix.
If the directory contains many entries, if may be faster to use glob() first:
$list = glob("$node.*"); // take care to escape $node here
$list = preg_grep("#".preg_quote($node,'#')."\.(jpg|png|gif)$#");
The preg_grep() can also be replaced by
$list = array_intersect($list, array("$node.png", "$node.jpg", "$node.gif"));
Or with a loop:
$img = null;
foreach(array('png','jpg','gif') as $ext) {
if (!file_exists("$node.$ext")) continue;
$img = "$node.$ext"; break;
}
$img = $img ? $img : "RANDOM.png";
The most compact (and therefore not recommended) form would be:
if (array_sum(array_map("file_exists", array($fn1, $fn2, $fn3)))) {
It could be adapted to also returning the found filename using array_search:
array_search(1, array_map("file_exists", array($fn1=>$fn1, $fn2=>$fn2)))
Hardly readable. Note how it also requires a map like array("$node.png"=>"$node.png", "$node.gif"=>"$node.gif", ...). So it would not be that much shorter.
$n_folder="images/nodes/";
$u_folder="images/users/";
$extensions=array(".png",".jpg",".gif");
foreach ($extensions as $ext)
{
if (file_exists($n_folder.$node.$ext))
{
$img=$n_folder.$node.$ext;
break;
}
elseif (file_exists($u_folder.$node.$ext))
{
$img=$u_folder.$node.$ext;
break;
}
}
if (!$img)
{
random image generator script...
}
Okay... this is what I finalized on:
$searches = array(
$folder . "nodes/" . $node . ".png",
$folder . "nodes/" . $node . ".jpg",
$folder . "nodes/" . $node . ".gif",
$folder . "users/" . $user . ".png",
$folder . "users/" . $user . ".jpg",
$folder . "users/" . $user . ".gif"
);
foreach ($searches AS $search)
{
if (file_exists($search))
{
$img = $search;
break;
}
}
if (!$img)
{
random image generator script...
}
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);
}
}
}