I currently use a one file design... where all my php code is in one index.php file, I have about 13,000 lines (~1mb) in one file, and it is starting to hang a little on load time... I was thinking it could be the file size, but I had always thought PHP is preprocessed on the server, so it doesn't matter what is in the other if statements, because it won't be rendered.
Below is an example of my index.php:
if ($_POST['action'] == 'view') {
// code
} else if ($_POST['action'] == 'something') {
// code
} else if ($_POST['action'] == 'otherthings') {
// code
} else {
// homepage
}
Questions:
Am I losing any speed by having my code in one file? or does this not affect the speed at all?
Are there any code layout/organizational styles that are more efficient for PHP? or does this not matter either?
As others have recommended, it's better to break this file into parts, for ease of maintainability as much as anything. One thing you might consider is using an opcode cache like APC as this will reduce the number of times the index.php file is parsed.
Every line you put needs to be parsed, so putting all code in a unique file affects to response time.
A very simple way to reorganize all it would be:
$action = $_POST['action'];
$path = 'path_to_your_application';
//you should put some validation about action, for example
$allowed_actions = (array of possible values of "action");
if(in_array($action, $allowed_actions) && file_exists($path.$action.".php"))) require($path.$action.".php");
else //homepage
or something like this :-)
No, the more consume time is I/O, as opening files. In your case,
server open and read an unique file, it's optimized
But, code is not maintenable, has cyclomatic complex, is not really
testable... It's recommended to organize your code in breaking it
into many files, with MVC Logic for example. You can also use a
micro framework to help you organize your code around conventions.
See http://silex.sensiolabs.org/ for example.
Related
What I am trying to do is change a variable in fileb from filea. Kind of like using fileb as a config file in a way.
Example:
File A:
require_once "fileb.php";
if($power == 'off') {
exit;
}
if($test1 == 'one') {
echo "The first option is selected";
} elseif($test1 == 'two') {
$power = 'off';
}
File B:
$power = 'on';
So in this example a user id prompted for $test1, if they reply with "one" they get a echo. What I want to do is make it so if they reply with "two" it shuts down the page, and not just for them but for everyone. I am trying to do all of this without using a DB, that would be too easy lol. Thanks for the help!
I am trying to do all of this without using a DB, that would be too easy
There's a reason using a database for this is easy. It's the correct way to accomplish this task. Modifying actual PHP code files is a famously bad idea. (And one that somebody on Stack Overflow has almost weekly, it seems.)
If you include the file as part of the executing code, you can use the variable as any other. This allows you to manipulate the variable in a transient way, but not manipulate the code which creates the variable.
What you're trying to do is persist that changed variable. In order to do that, it needs to be written somewhere outside of the application. Databases are really good for that sort of thing. You could also write to a simple text file (a string of text, structured XML, etc.) though in that case you'll have to manually watch out for concurrent writes and other such errors. (Databases are really good at that too, which makes them ideally suited for multi-thread/multi-user applications like web apps.)
I suppose you could treat the PHP file itself as an editable text file like any other. (Since PHP is, after all, just text.) But, again, that's a really bad idea. For one thing, parsing out exactly the value you want and writing back a change only to that value is going to be very difficult. Also, you run the risk of breaking a file which is treated as executable code which opens up all sorts of potential risks.
Just write to a database, or to a file, or to any other simple data persistence medium outside of the application.
Your fileb is lacking the <?php ... ?> tags. Without those, you "code" is never seen as code. it'll just be treated as plain text.
file b:
<?php
$power = 'on';
file c:
Hello
<?php
$foo = 'world!';
file a:
<?php
include('fileb.php');
echo $power;
include ('filec.php'); // "Hello" is immediately output
echo $foo; // tell PHP to put the $foo var, which will print out "world!"
I want to make a programming environment. I will explain it with an example.
One programmer will write that code;
<html>
<head>
<?php definedMetaTags(); ?>
</head>
</body>
Programmer will save this file and then upload to my system. That file will be executed at server side and then they system will turn generated code back.
That definedMetaTags() function will be already written in the system.
An example of Compiler.php:
<?php
require_once("definitionsForProgrammer.php");
include("uploadedfile.php");
?>
My question is that I want to allow that uploadedfile.php only what functions I want. Else, maybe that programmer writes some codes what I want him/her to do. (Deleting files, mysql connection, etc.)
Is there any way to allow a code only specific functions, variables, constans?
If the goal is to allow a user to insert placeholders that will be replaced by some PHP function execution, then there's no need to treat the uploaded file as PHP code:
<html>
<head>
{[definedMetaTags]}
</head>
</body>
Then Compiler.php would look like this:
<?php
require_once("definitionsForProgrammer.php");
$macros = array();
$macros['definedMetaTags'] = definedMetaTags();
$output = file_get_contents("uploadedfile.php");
foreach($macros as $macro=>$value) $output = str_replace("{[$macro]}", $value, $output);
echo $output;
?>
The definedMetaTags() function would need to be reworked so that it returns the tags as a string instead of printing them directly to output.
This method would allow you to define any number of macros without exposing yourself to all the security risks the others here have mentioned.
If you're aiming for security and you want to let them to write functions, then the short answer is: no.
Essentially you're asking for a PHP sandbox which will let you constrain what code can be executed. PHP would have to support this at a fundamental level for it to work. For example, supposing you took the approach of saying "I only allow the user to write a function named 'foo'". Inside that function, though the user can do all kinds of bad things like making system calls, downloading other code and executing it, etc. In order to prevent this you'd need to implement checks at a much lower level in the system.
If you're willing to restrict the scope only to variable definitions then yes you can do it. You can use token_get_all() and token_name() to examine the file to make sure that it doesn't have any code that you don't want in it. For example:
foreach (token_get_all(file_get_contents("uploadedfile.php")) as $token) {
if (is_array($token)) {
echo token_name($token[0]), " ";
} else {
echo $token;
}
}
If you don't like any tokens you see, don't include the file. You could theoretically guard against bad functions this way as well, but it'll require a fair amount of effort to properly parse the file and make sure that they're not doing something bad.
references:
http://www.php.net/manual/en/function.token-get-all.php
http://www.php.net/manual/en/function.token-name.php
http://www.php.net/manual/en/tokens.php
Well, if i'm understanding your question correctly. If you include("uploadedfile.php"); you will acquire everything in it.
What you could do is break your code up into related sections (whether it be via classes or just function definitions in a file) then only include the file/class that you want.
(let me know if that's not what your asking)
Will I be ok doing this?
foreach ($item as $val)
{
include('external_script.php');
}
Where external script is about 800 lines of code I want to keep separate for organizational sakes.
Gracious!
I guess you should better use a function for this.
Including a file requires to read, parse, and interpret the file. But if you have a function that you just feed with the current $item, it its code is just read, parsed and interpreted once and you won’t have that overhead you would have with including.
It will work but there's a disk I/O overhead for calling an external file in a loop unless you happen to have APC, XCache, eAccelerator running. Besides, you can't use include. You should be using include_once if it's the same file you're reloading
You wound not be killed by a god for doing that, and it would even work.
But still function is better.
Whether you will be okay or not depends on if you want to include your external script in each iteration or not.
Note that if your included file contains functions, you will end up with errors for trying to define the same function multiple times.
ermmmm - why?
if its the same file include it once - perhaps put the code in it in a function and just call that function how ever many times you need to.
I think you should consider using the eval() function instead.
I'd like to adhere to the Don't-Repeat-Yourself principle, but sometimes when I write PHP together with HTML and CSS, if I re-use the same code for different situations, my code soon will have so many if-then-else that the code is not easily maintainable.
This may be a bigger issue if Smarty, the templating engine is used, because most code editor won't match up {if} {else} {/if} So the programmer needs to look for the matching tag visually, and is not easy when there are 3 or 4 levels of nested {if} {else} {/if}.
In such situation, is there a way to stick to DRY, but still have good maintainable code?
Just so we have more info... What program are you using to write your code?
Tips for not repeating yourself:
Use some sort of templates. Doing this keeps you from having to repeat code for displaying content in each of your pages. I.E. If you have a site with 20 pages and you decide to change your layout, you don't want to have to go through and then change all 20 of your pages.
Use functions. If you have code that performs a specific task, DON'T write that code multiple times throughout your program/page. Create a function and then call it in each spot where you need that task performed. That way if you need to make a change you just modify that one function and don't have to search through your code to find every place that you performed that task. If you know about classes & methods (a method is a function in a class), for many tasks, this is even better as it provides you with data encapsulation and allows you to group related functions together so that you can include the class in future projects as needed.
If you are having difficulty with lots of if/else statements and code not being very readable there are a few things you can do:
1. Consider trying a new editor. Code folding is a must. Some editors also have vertical lines that highlight and match up indented code so you know what goes with what. If you want a decent free editor, I would recommend Notepad++ as it has both these features (just google it, I can't add links here).
2. There are techniques you can use to reduce the number of nested if statements that you have...
Example (this code):
if (item1 == true) {
if (item2 == true) {
item3 = 5;
}
else {
item3 = 10;
}
}
else {
if (item2 == true) {
item3 = 15;
}
else {
item3 = 20;
}
}
Can also be flattened out into:
if (item1 == true && item2 == true) {
item3 = 5;
}
else if (item1 == true && item2 == false) {
item3 = 10;
}
else if (item1 == false && item2 == true) {
item3 = 15;
}
else {
item3 = 20;
}
So if you have 3 or 4 levels of nested if/elses and you want to flatten them out, you may find your code more readable to use multiple arguments such as above. It does the same thing, it's just a matter of preference for which way you do it.
Try and not mix your logic (I'm assuming PHP) and your display (I'm assuming HTML/CSS). This is not always easy to do, but using templates and css, it is possible. Let me give you a practical example of how you can do this on a home page that displays a users name as a welcome message.
Inline PHP (try to avoid):
<html>
<body>
<?php
if ($logged_in == true) {
echo "Welcome ",$user->name(),"!";
}
else {
echo "Welcome Guest!";
}
?>
</body>
</html>
Logic separate from display (better):
<?php
if ($logged_in == true) {
$greetingMessage = "Welcome ",$user->name(),"!";
}
else {
$greetingMessage = "Welcome Guest!";
}
?>
<html>
<body>
<?php echo $greetingMessage; ?>
</body>
</html>
^ Keeping your logic separate from your view (HTML) will help you not get overwhelmed when your project starts getting really complex. It's best just not to mix! :)
Good luck man!
Short of a full framework, what I tend to do for content (even if it contains logic) is separate it out into files and use another logical evaluation to merge them together (mangle them) and then evaluate the templating logic after that. This chunkifies your content and makes chunks sharable / reusable on common state.
This way each final template buffer is a flattened tree of discrete re-usable content nuggets that you can store on disk or a database. Even something as simple as a little parser that replaces:
<h1>{{insert:shared_page_header}}</h1>
With shared_page_header.txt helps keep things separate. It also forces you to look at separation on concerns even in the logic that is embedded in your templates. Manageable, reusable chunks of anything (dynamic or not) are always the way to go. Your templates are just strings until evaluated, so treat them as shared components merged into a big-dirty-string(TM) and then evaluated.
Good Luck
The first sentence of your question is the problem, IMO. You really shouldn't be mixing code with your view (i.e. HTML and CSS). There are several PHP MVC frameworks that will help you not do this. The Zend framework is pretty decent but there are others as well.
If you don't want to use a framework, then I'd suggest refactoring your pages to not use code like this and call objects on the back end. Mixing your code and view quickly becomes unmaintainable in any language, not just PHP.
Now I may not be that familiar with implementing OOP concepts using PHP, but refactoring those nested if-else statements and placing them in a well-named function helps a lot in keeping up with the DRY principle. And besides, sticking with the DRY principle does make your code maintainable.
With an example script file it would be a lot easier for us to point out where you are going wrong, however some things which may or may not help you depending on what you are trying to achieve:
Taking a look at alternative syntax for control structures. Some people prefer to use this style when writing files which mainly contain HTML, with PHP being used only to decide which HTML sections to output.
Split up the reusable sections of code into files which you can later include, ie. header.php, footer.php etc.
Using an IDE which supports code folding
Good luck
If statements are considered to be logic statements, they should be avoided in views as much as possible as they violate MVC principles.
Switch to view helpers instead, for example:
class LoggedUsernameHelper
{
protected $user;
public function __construct(SomeUserObject $user)
{
$this->user=$user;
}
public function __toString()
{
return $user->isLogged() ? sprintf('Welcome %s', $user->getUsername()) :
'Welcome guest';
}
}
This code is reusable, testable, will keep your code dry :)
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.