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.
Related
I know this code works but I don't know if it'd be valid to do. The reason I wanted to support this is to allow people to overwrite this function with another file. Sounds slightly strange, but for my purpose it makes sense.
I only ask because I seriously can't find an example of this being done and have been searching for an hour or so.
$jerry = function(){
return 'hello world';
};
echo $jerry();
Yes, it is valid to use anonymous functions assigned to variables.
You should make use of the PHP documentation (under "Language Reference" > "Functions" > "Anonymous functions") when you are not sure about something. The website is actually quite easy to use.
Another way of finding stuff on php.net is to use the URL path. For example, if you are interested in functions then you can just go to php.net/functions, and it will attempt to direct you to the right place. This will work with quite a lot of stuff; php.net/juggling, for instance, will direct you to the "type juggling" page. If it is unable to direct you to something relevant then it will show you search results instead, using the URL path as the search query.
I believe you can do something else... say you have
function1() {
//code for function1 here
}
function2() {
//code for function2 here
}
you can actually do this
$var = 'function1';
$var(); //runs function1()
$var = 'function2';
$var(); //runs function2()
Hope it clears out things
Otherwise all the information you seek is in www.php.net/functions as the fellow user pointed out earlier. Learn to search php.net for any issues, at the bottom of every documentation page there are EXAMPLES that 95% help you for what you're looking to achieve
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.
I have a function that loops through different types of listings pulled from MySQL and displays them as a Facebook-esque "feed". Each type of listing has a different appearance, and therefore requires a different template.
Here is the below function example might be called 100 times (if there are 100 listings):
function display_listing($id,$type) {
global $abs_path;
switch($type) {
case 'photo':
include($abs_path . '/templates/photo.php');
break;
case 'video':
include($abs_path . '/templates/video.php');
break;
}
}
Is there a better way to do this, where I don't potentially end up with 100 includes - which may slow my process down? Can I somehow save the include once on the page, and refer to it as many times as needed?
...or is this the best practice?
Also, I want to know how to do this on my own, without a template engine...
EDIT: The problem isn't solved just by include_once (I dont believe)...I need to be able to reuse the included file multiple times, replacing the variables each time.
Although a switch is not the most scalable way to write this code, I'm afraid that includes is the only way to keep your templates in separate files, here.
You could, conceivably, encapsulate each template's code in a function, however:
/*
photoTemplate.php
*/
<?php
function loadPhotoTemplate($id) {
?>
<div id="photo">
...
</div>
<?php
}
?>
/*
listing.php
*/
function display_listing($id,$type) {
global $abs_path;
switch($type) {
case 'photo':
include_once($abs_path . '/templates/photo.php');
loadPhotoTemplate($id);
break;
case 'video':
include_once($abs_path . '/templates/video.php');
loadVideoTemplate($id);
break;
}
}
This will load each template file at most once, and then just call the function each time you want to display the template with the specific data for that item.
Edit
It would probably be even better to include all template files at the beginning, then just call the appropriate function in the switch. PHP's *_once() functions are slow, as they must consult the list of previously included/required files every time they are called.
create an array of allowed templates. have you function look to see if the requested template is in the array. if it is, then use the $type variable to include the file. yes, in general you shouldn't use user-supplied data in an include file name, but since you've validated it against a known-good array of values, it's safe.
If your concern is performance, I personally wouldn't get into this loop at all.
Presuming that items in the list are viewed more frequently than they're created, I would generate the HTML as the items are created and store the output alongside the data in the database. (Or in memcache or files or somewhere else - but generate it and store it.)
In doing so you'd move this logic back into the creation process of the items so you're doing the same switch statement, but only for one item at a time - you're cutting out the loop.
Then at display time, instead of calling display_listing(), you just echo out the HTML you've already stored.
I think you ought to look at a few things. Firstly, is there even a possibility you will include the same "template" 100 times? That seems like a massive amount of content to put on a page.
If I'm using tiny "snippets" - say, a table row that's repeated many times - I tend to use a function that returns a string, like this:
/* snippets.php */
function tableRow( $row )
{
return
'<tr><td>' . $row['var1'] . '</td>' .
'<td>' . $row['var2'] . '</td></tr>';
}
/* main page/view */
foreach ( $data as $row )
echo tableRow( $row );
The main advantage here is you can have loops and all sorts in the function.
If you're looking for a straight variable-replacement, you could create your own mini-templates in an HTML file; something like:
<p>{name}<br />
Posted {date} by {author}</p>
Then read in the template, pass the whole string to your display_listing function, which runs str_replace on all the {variables}. I don't think there would be too much of a performance hit, but you'd have to try it to be sure.
You want to use the include_once function instead of include.
The include_once() statement includes
and evaluates the specified file
during the execution of the script.
This is a behavior similar to the
include() statement, with the only
difference being that if the code from
a file has already been included, it
will not be included again. As the
name suggests, it will be included
just once.
If you're going to be including templates using a switch for different keywords, then you should set a variable, say $template_filename, in the switch and then once you break out of the switch, do the include like so:
include_once("/templates/{$filename}.php");
If you don't want to use including at all, then you might as well use a templating engine...
This method seems reasonable to me however.
Is there any way to safely include pages without putting them all in an array?
if (preg_match('/^[a-z0-9]+/', $_GET['page'])) {
$page = $_GET['page'].".php";
$tpl = $_GET['page'].".html";
if (file_exists($page)) include($page);
if (file_exists($tpl)) include($tpl);
}
What should I add to make this pretty safe?
I'm doing it this way bacause I don't like having to include stuff that has to be included on all pages. The "include header > content > include footer"-way. I don't wanna use any template engines/frameworks neither.
Thanks.
The weakness in your current implementation is that …
the regular expression just tests the beginning of the string, so “images/../../secret” would pass, and
without further validation, “index” would also be a valid value and would cause a recursion.
To make your implementation safe, it’s a good practice to put everything, that’s intended to be included, in its own directory (e.g. “includes” and “templates”). Based on this, you just have to ensure that there is no way out of this directory.
if (preg_match('/^[a-z0-9]+$/', $_GET['page'])) {
$page = realpath('includes/'.$_GET['page'].'.php');
$tpl = realpath('templates/'.$_GET['page'].'.html');
if ($page && $tpl) {
include $page;
include $tpl;
} else {
// log error!
}
} else {
// log error!
}
Note: realpath returns the absolute path to the given relative path if file exists and false otherwise. So file_exists is not necessary.
Despite what you stated about not wanting to store a list of available pages in an array it is likely going to be the best, non-db, solution.
$availFiles = array('index.php', 'forum.php');
if(in_array($_GET['page'].".php", $availFiles))
{
//Good
}
else
{
//Not Good
}
You could easily build the array dynamicly with either DB queries or by reading a file, or even reading the contents of a directory and filtering out the things you don't want available.
You should never use user supplied information for includes. You should always have some sort of request handler that does this for you. While a regular expression may filter somethings it will not filter everything.
If you do not want your site to get hacked you do not allow your users to control the flow of the application by designating an include.
I agree with Unkwntech. This is such an insecure way to include files into your website, I wish PHP programmers would do away with it altogether. Even so, an array with all possible matches is certainly safer. However, You'll find that the MVC pattern works better and it is more secure. I'd download code igniter and take a tutorial or two, you'll love it for the same reason you wanna use dynamic includes.
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.