I have the following dilemma. I have a complex CMS, and this CMS is to be themed by a graphic designer. The templates are plain HTML, with several nested inclusions. I'd like to make it easier for the designer to locate the file to be modified, by looking at the HTML of the page.
What I thought in the first place was to build something stupid like this:
function customInclude($what) {
print("<!-- Including $what -->");
include($what);
print("<!-- End of $what -->");
}
but, guess what? Variables obviously come out of scope in the included file :-) I can't declare them as global or as parameters, as I don't know how they are called and how many are there.
Is there any possibility to implement some kind of "macro expansion" in PHP? An alternative way to call it: I'd like to modify each call of the modify function, in an aspect-oriented style.
I have thought about eval(), is it the only way? Will it have a big impact on performance?
I know this is an old question, but I stumbled upon it and it reminds me of something I used to do it too.
how about if you create the function using a very weird variable?
<?php
function customInclude($___what___) {
echo '<!-- Including '.$___what___.' -->';
include($what);
echo '<!-- End of '.$___what___.' -->';
}
?>
I usually suggest to add a possible variable to display those tags only when necessary, you do not want other people to know...
<?php
function __printIncludeInfo($info, $dump = false){
//print only if the URL contains the parameter ?pii
//You can modify it to print only if coming from a certain IP
if(isset($_GET['pii'])){
if($dump){
var_dump($info);
} else {
echo $info;
}
}
}
function customInclude($___what___) {
__printIncludeInfo('<!-- Including '.$___what___.' -->');
include($what);
__printIncludeInfo('<!-- End of '.$___what___.' -->');
}
?>
in this way you can use the function to print any other information that you need
Not sure if I entirely understand the question, but if you're just trying to make life easier for the designer by showing them the underlying filename of the included file, then you can probably just use this within the template files:
echo '<!-- Start of '.__FILE__.' -->';
....content...
echo '<!-- End of '.__FILE__.' -->';
__FILE__ is just one of several Magic Constants.
Also there's the get_included_files() function that returns an array of all the included files, which might be of use (you could output a list of all the included files with 'tpl' in their name for example).
This is my 100% harcoded solution to custom include problem. It's about using a global var to point the next include filename and then include my custom proxy-include-file (wich replace your custom proxy-include-function)
1 - Add this code to a global include (wherever your customInclude function is defined)
$GLOBALS['next_include'] = "";
$GLOBALS['next_include_is_once'] = false;
function next_include($include_file) {
$GLOBALS['next_include_is_once'] = false;
$GLOBALS['next_include'] = $include_file;
}
function next_include_once($include_file) {
$GLOBALS['next_include_is_once'] = true;
$GLOBALS['next_include'] = $include_file;
}
2 - Create some include proxy-include-file, by example "debug_include.php"
<?php
if(empty($GLOBALS['next_include'])) die("Includes Problem");
// Pre-include code
// ....
if($GLOBALS['next_include_is_once']) {
include_once($GLOBALS['next_include']);
} else {
include($GLOBALS['next_include']);
}
// Post-include code
// ....
$GLOBALS['next_include'] = "";
3 - Perform a search and replace in all your files: (except debug_include.php)
search: 'include((.*));' as a reg.exp
replace with: '{next_include($1);include('debug_include.php');}'
and
search: 'include_once((.*)); as a reg.exp
replace with: '{next_include_once($1);include('debug_include.php');}'
Maybe you should need another search-and-replaces if you have some non-standard includes like
include (.... include (.... include (....
I think you can find some better search-and-replace patterns, but I'm not a regular expression user so I did it the hard way.
You should definitely use objects, namespaces and MVC model. Otherwise there is no pure and clean solution to your problem. And please, don't use eval, it's evil.
Related
I have a basic page structure in php that contains include files for head and footer.
In the footer, i want to add an include file that will load only if the page as the data-table class.
Something like:
if ($class == 'data-table')
include(SHARED_PATH . '/load-datatables.php');
My goal is to load scripts only when needed. I'm a newby in PHP so I want to start with simple things.
Thanks!
If you are going to search for the "data-table" class in the page using php that would be hard. Although here's what you can do.
Add a php variable that indicates whether the datatable class "data-table" is being used in the page
// index.php
<?php $pageUsesDataTable = true; ?>
...
...
<table class="data-table">.....</table>
// Then load the script if depending on the variable
if ($pageUsesDataTable)
include(SHARED_PATH . '/load-datatables.php');
Or you could just check if the "data-table" class exists in the page, if so initialize the datatable if it is generic
// dTable.js or <script>
if($('.data-table').length != 0) {
// initialize the datatable
}
Although there's always a cleaner approach out there, try to search deeper. Good luck
Put this variable in those pages where you want to include the php-file load-datatables:
$include_datatables_file = true;
Then include a generic file called checkinclude.php on all your pages:
checkinclude.php:
if (!isset($include_datatable_file)) {$include_datatable_file = false;}
if ($include_datatable_file === true) {
include_once(SHARED_PATH . '/load-datatables.php');
}
After Anurag's comment: Did you try it... Of course I did, but I didn't get the right path so it didn't work. Changed the path and it works as expected.
Like I said, it might not be the cleanest way or the best practice. But it works and it's easy to set up. Thanks for all answers!
I found a question on stack overflow about loading a template file in php, which was fine, but I wish to loop a template file of one line, many times instead.
The article I have read is here
[PHP Content Separation.
The best answer on that page was from prodigitalson with his function GetTemplate.
Now I wanted to use something like this, but if I put his function in a loop then it wouldn't be very efficient, as it would keep loading the same file many times.
So I tried this. I would get the html included. Then store it in a variable, before putting it in the loop. However it didn't work.
Here is my code. The data is already in an array called $result.
$salesTemp=$this->tempLine('salesTEM.php');
while($row = array_shift($result)):
echo $salesTemp;
endwhile;
private function tempLine($file){
ob_start();
require $file;
return ob_get_clean();
}
The problem is that my variable is not being updated in the template.
Here is my template
<li class="list-group-item"><?php echo $Customer;?><span class="label label-primary pull-right">SALES</span></li>
So is there a way of re-writing this so my $Customer variable is updated.
I am doing this to try to keep php and html separate.
The primary problem I see with the code as it stands is that when $salesTemp is declared and ran through the tempLine() method, a string is returned (due to ob_get_clean()). The variable within the template has been resolved, and when the string is echoed in the loop the variables in the template are not updated because they have already been resolved and processed into a string. To fix the situation I would:
while ($row = array_shift($result)) {
echo $this->tempLine('salesTEM.php', $Customer);
}
/**
* #return string
*/
private function tempLine($file, $Customer) {
ob_start();
require $file;
return ob_get_clean();
}
This would be the shortest path to getting what you want. If you wish to not include the template on each iteration, try:
$salesTEM = include 'salesTEM.php';
while ($row = array_shift($result)) {
echo sprintf($salesTEM, $Customer);
}
/**
* salesTEM.php
*/
<li class="list-group-item">
%s
<span class="label label-primary pull-right">SALES</span>
</li>
There are many frameworks available that provide this functionality out of the box and may be perused for additional information on templating techniques. Essentially, it is always good form to pass the information in via the function (file name and data) and expect the string back out. It will make it easy to unit test as well. Allowing it to pick up the information passively tends to make the code error prone, for example:
while ($row = array_shift($result)) {
echo include 'salesTEM.php';
}
/**
* salesTEM.php
*/
<li class="list-group-item">
<?php echo $Customer;?>
<span class="label label-primary pull-right">SALES</span>
</li>
You could accidentally include the file and have not declared the $Customer variable resulting in a difficult to find bug. Define everything going in and coming out and it will make it much more manageable down the road.
You should really move the loop to inside the template file, seeing as you've already used PHP as the templating language inside of it. This will make things a whole lot easier for you, and give you the best possible performance (without rewriting the entire templating system).
As for the statement about keeping the HTML and PHP separate: It is actually not quite accurate, as it's a subtle rewrite from the original goal. Namely keeping the business code and the presentation code separate.
Normally, the presentation code is pure HTML, but in the case of dynamic sites the presentation code also requires dynamic elements. Most of the time this is solved by using a template engine that provides its own template language, but PHP can also be used as one. Matter of fact, PHP started as a template langauge. :)
So, using PHP in your views is perfectly fine. Provided said PHP code only controls output, and not business operations.
I have an answer which works. However as ChristianF says it may not be the best answer, but this does solve my question.
Right instead of having an echo in the html I put the tag in %% like this
<li class="list-group-item">%CUSTOMER%<span class="label label-primary pull-right">SALES</span></li>
Then my loop in my class. I can build the object in the previous line for better readability or do it inline like I have.
$salesTemp=$this->tempLine('salesTEM.php');
while($row = array_shift($result)):
echo $this->replaceTemp($salesTemp, $obj=(object)array ( 'CUSTOMER' => $row['CustomerName'] ));
endwhile;
and a small function
private function replaceTemp($file, $obj){
return preg_replace('~%(\w+)%~e', '$obj->$1', $file);
}
private function tempLine($file){
ob_start();
require $file;
return ob_get_clean();
}
The function basically replaces everything in the html where there are %% symbols with whatever is in the object.
UPDATE
After posting this I have improved my answer, but I will leave the above there as it was my original answer. Below is a class which improves on the above answer. In the rTemplate function I can have one, or many tags that will be replaced in the template. For the example I only have one tag to replace, but you could add many. Running testLoad will list the array, grab the template and fill in the tags with what is in rTemplate.
class testlist{
private $myfile;
public function __construct(){
$this->myfile=$this->loadTemplate('salesTEM.php');
}
public function testload(){
// At this point the array is populated from a database, but I haven't shown this.
// You can populate the array anyway you like.
while($row = array_shift($result)):
echo $this->rTemplate($row['CustomerName']);
endwhile;
}
// This loads in a file into a string and then returns it.
private function loadTemplate($file){
ob_start();
require $file;
return ob_get_clean();
}
// This makes the object to replace keywords, then replaces them
private function rTemplate($customer)
{
$obj = (object) array(
'CUSTOMER' => $id
);
return preg_replace('~%(\w+)%~e', '$obj->$1', $this->myfile);
}
}
I have two files that are included in my page. Like this:
// mypage.php
include 'script1.php';
include 'script2.php';
I need both of them in first, and then I need to remove one of them, something like this:
if ($var == 'one') {
// inactive script1.php file
} else {
// inactive script2.php file
}
That's hard to explain why I need to inactive one of them, I Just want to know, how can I do that? Is it possible to do unlike include?
The simple answer is no, you can't.
The expanded answer is that when you run PHP, it makes two passes. The first pass compiles the PHP into machine code. This is where includes are added. The second pass is to execute the code from the first pass. Since the compilation pass is where the include was done, there is no way to remove it at runtime.
Since you're having a function collision, here's how to get around that using objects(classes)
class Bob {
public static function samename($args) {
}
}
class Fred {
public static function samename($args) {
}
}
Note that both classes have the samename() function but they live within a different class so there's no collision. Because they are static you can call them like so
Bob::samename($somearghere);
Fred::samename($somearghere);
If you need just the output of either file you could do this
ob_start();
include('file1.php');
$file1 = ob_get_contents();
ob_start();
include('file2.php');
$file2 = ob_get_contents();
Then later if you need to call them
if ($var == 'one') {
echo $file2;
} else {
echo $file1;
}
Your only option is something like this:
if ($var == 'one') {
include('script2.php');
} else {
include('script1.php');
}
You can't 'remove' code, you can only choose to not include/execute it in the first place.
As by your comments you said its because of duplicated function names, i'm assuming you use both files elsewhere separately, but what your trying to achieve now is to merge these files together for a different reason (both files have functions/variables, etc that you need)
If your first file had a function like so my_function:
my_function() {
// code here
}
and your second file also had the same named function you can wrap an if statement around it to exclude it:
if (!function_exists('my_function')) {
my_function() {
// code here
}
}
This way the second file's function wont be available when merging the two files together but using file separately both functions will be available.
For the sake of providing options for others that come here, some solutions I've used myself on occasion...
If the files you're including, you're including for some function with a return value or some execution that doesn't need to be displayed on the page (such as mailing stuff out), and let's say you can't alter either of the target files (let's say they're somebody else's code or part of some highly integrated other piece of software that you really don't want to untangle).
A solution is to create a quick and dirty restful interface for both files to pull from them what you need from them, and then call that interface with your program, effectively bypassing the need to include them.
A worse method but if your situation is truly desperate, and is truly the route of last resort, and will only work in some cases (for example, will break on namespacing)...
$bad_idea = file_get_contents("foo.php");
eval($bad_idea);
unset($bad_idea);
Again, note, this is an option of last resort.
I am building a website using php. I would want to separate the php from the html. Smarty engine, I guess does that, but right now its too complicated for me. Looking for a quick fix and easy to learn solution, one which is an accepted standard as well. Anyone helping please.
Consider frameworks or choose a template engine
Use a framework. Depending on your project, either a micro framework like Slim or something more complete like Laravel.
What I sometimes do when writing complex systems with quite much php code is separating it the following way (don't know your exact project, but it might work for you):
You create a php file with all the functions and variables you need. Then, you load every wepgage through the index.php file using .htaccess (so that a user actually always loads the index.php with a query string). Now, you can load the html page using file_get_contents (or similar) into a variable (I call this $body now); this variable can be modified using preg_replace.
An example: In the html file, you write {title} instead of <title>Sometext</title>
The replacement replaces {title} with the code you actually need:
$body = str_replace('{title}', $title, $body);
When all replacements are done, simply echo $body...
Just declare a lot of variables and use them in the template:
In your application:
function renderUserInformation($user)
{
$userName = $user->userName;
$userFullName = $user->fullName;
$userAge = $user->age;
include 'user.tpl.php';
}
In user.tpl.php:
User name: <?=$username?><br>
Full name: <?=userFullName?><br>
Age: <?=$userAge?>
By putting it in a function, you can limit the scope of the variables, so you won't pollute your global scope and/or accidentally overwrite existing variables.
This way, you can just 'prepare' the information needed to display and in a separate php file, all you need to do is output those variables.
Of course, if you must, you can still add more complex PHP code to the template, but try to do it as little as possible.
In the future, you might move this 'render' function to a separate class. In a way, this class is a view (a User View, in this case), and it is one step in creating a MVC structure. (But don't worry about that for now.)
Looking for a quick fix and easy to learn solution
METHOD 1 (the laziest; yet you preserve highlighting on editors like notepad++)
<?php
// my php
echo "foo";
$a = 4;
// now close the php tag -temporary-
// to render some html in the laziest of ways
?>
<!-- my html -->
<div></div>
<?php
// continue my php code
METHOD 2 (more organized; use template files, after you passed some values on it)
<?php
// my php
$var1 = "foo";
$title = "bar";
$v = array("var1"=>"foo","title"=>"bar"); // preferrable
include("template.php");
?>
template.php
<?php
// $var1, $var2 are known, also the array.
?>
<div>
<span> <?php echo $v["title"]; ?> </span>
</div>
Personally, i prefer method 2 and im using it in my own CMS which uses lots and lots of templates and arrays of data.
Another solution is of course advanced template engines like Smarty, PHPTemplate and the likes. You need a lot of time to learn them though and personally i dont like their approach (new language style)
function renderUserInformation($user)
{
$userName = $user->userName;
$userFullName = $user->fullName;
$userAge = $user->age;
include 'user.tpl.php';
}
I want to define something like this in php:
$EL = "\n<br />\n";
and then use that variable as an "endline" marker all over my site, like this:
echo "Blah blah blah{$EL}";
How do I define $EL once (in only 1 file), include it on every page on my site, and not have to reference it using the (strangely backwards) global $EL; statement in every page function?
Most PHP sites should have a file (I call it a header) that you include on every single page of the site. If you put that first line of code in the header file, then include it like this on every page:
include 'header.php';
you won't have to use the global keyword or anything, the second line of code you wrote should work.
Edit: Oh sorry, that won't work inside functions... now I see your problem.
Edit #2: Ok, take my original advice with the header, but use a define() rather than a variable. Those work inside functions after being included.
Sounds like the job of a constant. See the function define().
Do this
define ('el','\n\<\br/>\n');
save it as el.php
then you can include any files you want to use, i.e
echo 'something'.el; // note I just add el at end of line or in front
Hope this help
NOTE please remove the '\' after < br since I had to put it in or it wont show br tag on the answer...
Are you using PHP5? If you define the __autoload() function and use a class with some constants, you can call them where you need them. The only aggravating thing about this is that you have to type something a little longer, like
MyClass::MY_CONST
The benefit is that if you ever decide to change the way that you handle new lines, you only have to change it in one place.
Of course, a possible negative is that you're calling including an extra function (__autoload()), running that function (when you reference the class), which then loads another file (your class file). That might be more overhead than it's worth.
If I may offer a suggestion, it would be avoiding this sort of echoing that requires echoing tags (like <br />). If you could set up something a little more template-esque, you could handle the nl's without having to explicitly type them. So instead of
echo "Blah Blah Blah\n<br />\n";
try:
<?php
if($condition) {
?>
<p>Blah blah blah
<br />
</p>
<?php
}
?>
It just seems to me like calling up classes or including variables within functions as well as out is a lot of work that doesn't need to be done, and, if at all possible, those sorts of situations are best avoided.
#svec yes this will, you just have to include the file inside the function also. This is how most of my software works.
function myFunc()
{
require 'config.php';
//Variables from config are available now.
}
Another option is to use an object with public static properties. I used to use $GLOBALS but most editors don't auto complete $GLOBALS. Also, un-instantiated classes are available everywhere (because you can instatiate everywhere without telling PHP you are going to use the class). Example:
<?php
class SITE {
public static $el;
}
SITE::$el = "\n<br />\n";
function Test() {
echo SITE::$el;
}
Test();
?>
This will output <br />
This is also easier to deal with than costants as you can put any type of value within the property (array, string, int, etc) whereas constants cannot contain arrays.
This was suggested to my by a user on the PhpEd forums.
svec, use a PHP framework. Just any - there's plenty of them out there.
This is the right way to do it. With framework you have single entry
point for your application, so defining site-wide variables is easy and
natural. Also you don't need to care about including header files nor
checking if user is logged in on every page - decent framework will do
it for you.
See:
Zend framework
CakePHP
Symfony
Kohana
Invest some time in learning one of them and it will pay back very soon.
You can use the auto_prepend_file directive to pre parse a file. Add the directive to your configuration, and point it to a file in your include path. In that file add your constants, global variables, functions or whatever you like.
So if your prepend file contains:
<?php
define('FOO', 'badger');
In another Php file you could access the constant:
echo 'this is my '. FOO;
You might consider using a framework to achieve this. Better still you can use
Include 'functions.php';
require('functions');
Doing OOP is another alternative
IIRC a common solution is a plain file that contains your declarations, that you include in every source file, something like 'constants.inc.php'. There you can define a bunch of application-wide variables that are then imported in every file.
Still, you have to provide the include directive in every single source file you use. I even saw some projects using this technique to provide localizations for several languages. I'd prefer the gettext way, but maybe this variant is easier to work with for the average user.
edit For your problem I recomment the use of $GLOBALS[], see Example #2 for details.
If that's still not applicable, I'd try to digg down PHP5 objects and create a static Singleton that provides needed static constants (http://www.developer.com/lang/php/article.php/3345121)
Sessions are going to be your best bet, if the data is user specific, else just use a conifg file.
config.php:
<?php
$EL = "\n<br />\n";
?>
Then on each page add
require 'config.php'
the you will be able to access $EL on that page.