I am trying to build my own simple template handler to easily be able to nest and combine files into variables and call these variables when neccessary, as shown below:
$partial['header'] = 'header.php';
foreach($partial as $part => $view ) {
$output[$name] = file_get_contents( APPPATH .'views/' . $view . '.php' );
}
extract($output, EXTR_PREFIX_ALL, 'template' );
include 'mytemplate.php';
The mytemplate.php template file:
<?php
echo $template_header; // Shows the header.
The question:
Obviously, loading a PHP file by file_get_contents isn't going to call any PHP code inside the loaded file and I am sure that there's better options available then using eval. What should I change to be able to use PHP inside my template files?
More ugly is possible but doing exactly what you're wanting :
function custom_get_content($filename){
if (is_file($filename)) {
ob_start();
include $filename;
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}
}
Then you can call it :
foreach($partial as $part => $view ) {
$output[$name] = custom_get_content( APPPATH .'views/' . $view . '.php' );
}
I copied that from a comment in the PHP manual but can't find it anymore (and that's why maybe it's too ugly :D)
Reading the scripts in is obiously not the best approach. You'll have to eval them.
And just for the record:
include($filename);
Is functionally identical to:
eval("?>" . file_get_contents($filename));
Get over it. The "eval is evil" meme is just that, a meme. So if you want to keep your appraoch, you could just use eval("?>$template_header"); instead of echo.
The alternative would be to skip the file reading, and have your $template_vars contain filenames rather than their content. Then do an ordinary include($template_header);
Related
I have a WordPress issue and want to simply write log messages to a text file. I am aware that error_log exists, but want to have a more segregated log file for different messages.
I am using wp_filesystem->put_contents, and it DOES write to the file and succeeds, but it ONLY outputs the last call's data.
I have the following method:
public static function log_message($msg) {
error_log($msg);
require_once(ABSPATH . 'wp-admin/includes/file.php');
global $wp_filesystem;
if ( ! is_a( $wp_filesystem, 'WP_Filesystem_Base') ){
$creds = request_filesystem_credentials( site_url() );
wp_filesystem($creds);
}
$bt = debug_backtrace();
$caller = array_shift($bt);
$logStr = date("Y-m-d hh:ii A",time())." - ".$caller['file'].":".$caller['line']." - ".$msg;
$filePathStr = SRC_DIR.DIRECTORY_SEPARATOR.$logFileName;
$success = $wp_filesystem->put_contents(
$filePathStr,
$logStr,
FS_CHMOD_FILE // predefined mode settings for WP files
);
if(!$success) {
error_log("Writing to file \"".$filePathStr."\" failed.");
} else {
error_log("Writing to file \"".$filePathStr."\" succeeded.");
}
}
I call it using:
log_message("\nTest 1");
log_message("\nTest 2");
log_message("\nTest 3");
The output is ALWAYS ONLY Test 3 with the other invocations being ignored yet, their output appears in the debug.log as well as all the success messages.
Why would this be?
Looking at the WPCodex for the source code of this, it uses fwrite behind the scenes. The file is closed in this code, and I cannot use any "flush" technique.
Is there a way to figure this out?
I found that the source of WP_Filesystem uses file_put_contents (as the name does suggest), and I assumed this is for APPENDING to the file's data.
This is incorrect.
This function is to take data, and then WRITE it to the file, erasing prior data.
Mainly useful for creating resources, downloading a file, etc.
If I want to APPEND to a file, I need to use 'fwrite'.
This post describes that.
This is the example to APPEND to a file:
$filepath = '\path\to\file\';
$filename = 'out.log';
$fullpath = $filepath.$filename;
if(file_exists($fullpath)) {
$file = fopen($filepath.$filename, "a");//a for append -- could use a+ to create the file if it doesn't exist
$data = "test message";
fwrite($file, "\n". $data);
fclose($file);
} else {
error_log("The file \'".$fullpath."\' does not exist.");
}
The fopen docs describe this method and it's modes.
I'm making a function on WordPress to get the content of the robots.txt file. If the file doesn't exist, create it with default content. I will use it for my options page. Well, this is my code, it should work almost creating the file, but it doesn't:
function get_robots($robots_file) {
$robots_file = get_home_path() . 'robots.txt'; //The robots file.
$dir = get_home_path(); //The root directory
if(is_file($robots_file)){
$handle = fopen($robots_file, "r");
$robots_content = fread($handle, filesize($robots_file));
fclose($handle);
} else {
$default_content = "User-agent: *\nDisallow:";
chmod($dir, 0777);
$handle = fopen($robots_file, "w+");
$robots_content = fwrite($handle, $default_content);
fclose($handle);
}
chmod($dir, 0744);
return $robots_content;
}
I'm not sure if the problem is is_file, or the fopen($robots_file, "w+" (should it be "r"?) after the else. And I'm not sure about the permissions. Is the 777 needed? Is the 744 the default for the root directory of WordPress?
And I use the return to use it as variable later; I suppose the fopen is already creating the file. Am I right?
Thanks in advance.
The first thing, I would use completely different functions, you have file_put_contents() and file_get_contents() for such simple operations.
So possible simpler solution is:
function get_robots() {
$robots_file = get_home_path() . 'robots.txt'; //The robots file.
if(file_exists($robots_file)){
return file_get_contents($robots_file);
} else {
$default_content = "User-agent: *\nDisallow:";
file_put_contents($robots_file, $default_content);
return $default_content;
}
}
I don't see any point to pass $robots_file as function argument so I removed it. You should check if this code simple works.
I also don't see any reason to change $dir permissions as you showed in your code. It should be rather set manually and you definitely shouldn't change your root directory permission in such function.
EDIT
Because this function uses get_home_path() and this one is available probably only on admin panel you have to do it in different way. You may add the following code to the end of your index.php file:
function get_robots($path)
{
$robots_file = $path . DIRECTORY_SEPARATOR . 'robots.txt'; //The robots file.
if(file_exists($robots_file)){
return file_get_contents($robots_file);
} else {
$default_content = "User-agent: *\nDisallow:";
file_put_contents($robots_file, $default_content);
return $default_content;
}
}
get_robots(getcwd());
(Of course if you want, you may move get_robots() function to some other files.
However you should consider if this is the best approach. You will run this function each time your site will be viewed and it's tiny waste (in fact you will probably want to create robots.txt file just once). You could for example create robots.php file and if you want to run it you can run http://yourwordpressurl/robots.php. It's of course your call.
I am building a PHP application that uses a select menu to build email templates. The templates are broken into reusable parts (each is a separate html file). Is there an easy way to require multiple files with one expression? (my PHP is really rusty...)
Essentially I want to do something like:
function require_multi() {
require_once($File1);
require_once($File2);
require_once($File3);
require_once($File4);
}
Well, you could turn it into a function:
function require_multi($files) {
$files = func_get_args();
foreach($files as $file)
require_once($file);
}
Use like this:
require_multi("one.php", "two.php", ..);
However, if you're including classes, a better solution would be to use autoloading.
Credit to Tom Haigh from how to require all files in a folder?:
$files = glob( $dir . '/*.php' );
foreach ( $files as $file )
require( $file );
Store all your required files in $dir and the above code will do the rest.
EDIT:
Because you want to require or include multiple files, you could use this recursive
algorithm to include files in a specified folder. The folder is the root that starts
the iterator. Because the algorithm is recursive, it will automatically traverse all
subsequent folders and include those files as well.
public function include_all_files($root) {
$d = new RecursiveDirectoryIterator($root);
foreach (new RecursiveIteratorIterator($d) as $file => $f) {
$ext = pathinfo($f, PATHINFO_EXTENSION);
if ($ext == 'php' || $ext == 'inc')
include_once ($file); // or require(), require_once(), include_once()
}
}
include_all_files('./lib');
So, I have a sidebar.php that is included in the index.php. Under a certain condition, I want sidebar.php to stop running, so I thought of putting exit in sidebar.php, but that actually exits all the code beneath it meaning everything beneath include('sidebar.php'); in index.php all the code would be skipped as well. Is there a way to have exit only skip the code in the sidebar.php?
Just use return;
Do also be aware that it is possible to actually return something to a calling script in this way.
if your parent script has $somevar = include("myscript.php"); and then in myscript.php you do say... return true; you will get that value in $somevar
Yes, you just use return;. Your sidebar.php file might look something like this:
<?php
if($certain_condition) {
return;
} else {
// Do your stuff here
}
?>
I know this is a really old question, but I've recently taken over the code base of another developer who used exit religiously, meaning that the parent file that included various files had to be designed in such a way that the include of the module files were done at the end so it didn't cut off the page. I wrote a small PHP script to replace all occurrences of "exit;" with "return;".
if($handle = opendir("path/to/directory/of/files")) {
while(false !== ($file = readdir($handle))) {
if("." === $file) continue;
if(".." === $file) continue;
$pageContents = file_get_contents($file);
$pageContents = str_replace("exit;", "return;", $pageContents);
file_put_contents($file, $pageContents);
echo $file . " updated<br />";
}
}
I hope this helps someone.
Hi
We have some php code using the file_get_contents() function, and I understand this is vulnerable to direcoty traversel attacks. Given the following code:
$mydata=$_GET['thefile'];
$data = file_get_contents ('/var/html'.$file);
echo $data
How can I do some simple input filtering so I can block the posibility that someone might do directory traversel by playing around with my input?
/MR
You want basename:
$mydata = basename(realpath($_GET['thefile']));
Appended to (slight modifications of) your example:
$file=$_GET['thefile'];
$mypath='/var/www/';
$location= basename(realpath($mypath.$file));
$data = file_get_contents($location);
echo $data;
Note... although this does some level of error checking, it does no error handling. I'll leave that up to you.
If the $_GET['thefile'] won't use folders like "images/fileX.jpg" you can use basename()
$filename = basename($_GET['thefile']);
readfile('/var/html/'.$filename);
When '../../passwords.txt' is given as $_GET['thefile'] it will be converted by basename to 'passwords.txt'.
Adding realpath() inside a basename doesn't add any security.
If your script does need to support subdirectories then use realpath() to determine if it's inside the '/var/html' directory.
$baseDir = realpath('/var/html/'); // (mayby /var/html is a symlink)
$baseDirLength = strlen($baseDir);
$filepath = realpath('/var/html/'.$_GET['thefile']);
if (substr($filepath, 0, $baseDirLength) == $baseDir) {
// Even when all the '../' in the thefile are resolved
// the path is within the $baseDir
} else {
// invalid $_GET['thefile']
}