user2616178
user2616178

Reputation: 59

Load file as string which contains variable definitions

What I'm trying to do in PHP is load a file which contains php style variables, and replace them with the contents of the variable. Here is my expample code which does not function how I intend it to.

module.html

<div class="module">
    $moduleText
</div>

index.php

<?php 
$moduleText = "Hello, World!";
$module = file_get_contents ( "module.html" );
echo $module;
?>

index.php Output

<div class="module">
    $moduleText
</div>

index.php Desired Output

<div class="module">
    Hello, World!
</div>

Is there an easy way in PHP to get this desired output?? I'm building a CMS and this would make module inclusion a snap for me. Any help, snarky comments, or points in the right direction are greatly appreciated!!

Upvotes: 3

Views: 1330

Answers (3)

centurian
centurian

Reputation: 1192

Yes it is possible as of today, making all template libraries a thing of the past.

For anyone searching for exactly this problem like I was:

Load file as string which contains variable definitions

The answer is quite simple:

  1. set your file with the text you want to output, e.g. a html file
  2. in place of your php vars write <?php echo $myvar ?> inside your file
  3. set your php file with the above variables and in scope start output buffering, collect the results and close the buffer as this answer proposes
  4. in the same scope use your collected results to do whatever you want before actually send to output and finally,
  5. don't forget to use the same variable names to be shared by the two files.

I'll give an example with CSRF protection(!)

form.html

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="utf-8">
   <title>Form Template</title>
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-social/5.1.1/bootstrap-social.min.css" />
   <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-xs-12 col-xs-offset-0 col-sm-8 col-sm-offset-2">
    <form method="POST" action="" novalidate="novalidate">
        <div class="form-group">
           <label for="email" class="control-label">Email</label>
           <div class="input-group">
              <label for="email" class="input-group-addon" aria-hidden="true"><i class="fa fa-at fa-lg"></i></label>
              <input type="text" class="form-control" id="email" name="email" value="" required="" title="Please enter your email" placeholder="[email protected]">
           </div>
           <span class="error help-block">Not acceptable domain</span>
        </div>
        <div class="form-group">
           <label for="password" class="control-label">Password</label>
           <div class="input-group">
              <label for="password" class="input-group-addon" aria-hidden="true"><i class="fa fa-lock fa-lg"></i></label>
              <input type="password" class="form-control" id="password" name="password" value="" required="" title="Please enter your password">
           </div>
           <span class="error help-block">Wrong password</span>
           <p><a href="/auth/newpass">Forgot password?</a></p>
        </div>
        <input type='hidden' name='csrf' value="<?php echo $arg[0] ?>">
        <button class="btn btn-primary btn-block">Sign in</button>
        <button class="btn btn-default btn-block">Cancel</button>
    </form>
</div>
</div>
</div>
</body>
</html>

Of special interest is line

<input type='hidden' name='csrf' value="<?php echo $arg[0] ?>">

template.php

session_start();
$csrf = $_SESSION['csrf']; //session stores the value
$arg = array($csrf);
ob_start();
   include './form.html';
   $include = ob_get_contents();
ob_end_clean();

// do whatever you want with $include

echo $include; // the page is rendered correctly!

We achived:

  1. separation between client view and server code with
  2. the help of a clean interface to assist the communication of two parties the server and the client so that, the designer need know nothing from the php developer and vice versa (here I used array $arg[n] to assist them)
  3. superior approach than the already there php's core function output_add_rewrite_var() as

    3.1. it's meant to solve a different problem

    3.2. it uses one buffer whereas here we control the buffer and avoid the delay that the one buffer introduces when echoing the page.

Hope that helps someone looking for this.

Upvotes: 0

user2616178
user2616178

Reputation: 59

I ended up creating a template system. The code should work if you copy and paste it while following my sample directory structure.

Let me know if you have any questions or alternative ways of doing this. I'm always open to improvements. :)

Sample Directory Structure:

- templates
---- index.html
---- module.html
- includes
---- functions.php
- index.php

index.html:

<b>${myVariable}</b>
<div>
    ${module}
</div>

module.html:

<b>${foo}</b>
<i>${bar}</i>

functions.php:

<?php 

function getTemplate($file, $hooks){
    //Read our template in as a string.
    $template = file_get_contents($file);

    $keys = array();
    $data = array();
    foreach($hooks as $key => $value){
        array_push($keys, '${'. $key .'}');
        array_push($data,  $value );
    }

    //Replace all of the variables with the variable
    //values.
    $template = str_replace($keys, $data, $template);

    return $template;
}

?>

index.php:

<?php

require_once('includes/functions.php');

/* 
 * Load Modules First so we can get the 
 * contents as a string and include that string
 * into another template represented by a 
 * variable in the template such as 
 * ${module}
 */ 
$moduleHooks = array(
    'foo' => 'Oh fooey',
    'bar' => 'Chocolate Bar'
);
$moduleTemplate= 'templates/module.html';
$moduleText = getTemplate($moduleTemplate, $moduleHooks);

/*
 * Load the module you want to display. Be sure
 * to set the contents of the contents to a hook
 * in the module that we will display
 */
$indexHooks = array(
    'myVariable' => 'Index Variable',
    'module' => $moduleText 
);

$indexTemplate = 'templates/index.html';
$indexText = getTemplate($indexTemplate, $indexHooks);

/*
 * Finally Display the page
 */
echo $indexText;

?>

Output:

<b>Index Variable</b>
<div>
    <b>Oh fooey</b><i>Chocolate Bar</i>
</div>

The problem that I had with using includes was that when I used say "include module.html;", I couldn't decide where to put that inside of a index.html file unless I turned index.html into a php file.

Upvotes: 0

Antoan Milkov
Antoan Milkov

Reputation: 2228

You can do this using Heredoc string

Let me give you a example:

index.php

<?php 
$moduleText = "Hello, World!";
include "module.php";
echo $module;
?>

module.php

<?php 
$module = <<<EOD
<div class="module">
    $moduleText
</div>
EOD;
?>

You can do this in any loop and it will behave as expected.

Hope this helps!

Upvotes: 2

Related Questions