1. Use a SQL Injection Cheat Sheet
A basic principle is to never trust user-submitted data.
Another rule is to escape data when you send or store it.
can be summarized as: filter input, escape output (FIEO). Input filtering, output escape.
The usual cause of SQL injection vulnerabilities is that the input is not filtered, as in the following statement:
Copy code The code is as follows:
$query = "SELECT *
FROM users
WHERE name = '{$_GET['name']}'";
In this In the example, $_GET['name'] comes from user-submitted data, which is neither escaped nor filtered~~
For escaped output, you have to remember that data used outside your program needs to be escaped meaning, otherwise, it may be parsed incorrectly.
In contrast, filtering input ensures that the data is correct before use.
With filtered input, you have to remember that raw data outside your program needs to be filtered because it cannot be trusted.
The following example demonstrates input filtering and output escaping:
Copy the code The code is as follows:
// Initialize arrays for filtered and escaped data, respectively.
$clean = array();
$sql = array();
// Filter the name. (For simplicity, we require alphabetic names.)
if (ctype_alpha($_GET['name'])) {
$clean['name'] = $_GET['name'];
} else {
/ / The name is invalid. Do something here.
}
// Escape the name.
$sql['name'] = mysql_real_escape_string($clean['name']);
// Construct the query.
$query = "SELECT *
FROM users
WHERE name = '{$sql['name']}'";
?>
Another effective way to prevent SQL injection is to use prepare statements, such as:
Copy code The code is as follows:
< ;?php
// Provide the query format.
$query = $db->prepare('SELECT *
FROM users
WHERE name = :name');
// Provide the query data and execute the query.
$query->execute(array('name' => $clean['name']));
?>
2. Understand the difference between comparison operators For example, you use strpos() to detect whether a substring exists in a string (if the substring is not found, the function returns FALSE ), the result may result in an error:
Copy code The code is as follows:
$authors = 'Chris & Sean';
if (strpos($authors, 'Chris')) {
echo 'Chris is an author.';
} else {
echo 'Chris is not an author.';
}
?>
In the above example, since the substring is at the very beginning, the strpos() function correctly returns 0, indicating that the substring At the very beginning of the string. Then, because the conditional statement treats the result as a Boolean (Boolean) type, 0 is calculated as FALSE by PHP, which ultimately causes the conditional statement to fail.
Of course, this BUG can be corrected using strict comparison statements:
Copy code The code is as follows:
< ?php
if (strpos($authors, 'Chris') !== FALSE) {
echo 'Chris is an author.';
} else {
echo 'Chris is not an author .';
}
?>
3. Shortcut the else (Shortcut the else)
Remember, always before you use a variable You need to initialize them first.
Consider the following conditional statement to detect whether the user is an administrator based on the username:
Copy the code The code is as follows:
if (auth($username) == 'admin') {
$admin = TRUE;
} else {
$admin = FALSE;
}
?>
This one seems safe enough because it’s easy to understand at a glance. Imagine a more complex example that sets variables for both name and email, for convenience:
Copy code The code is as follows:
if (auth($username) == 'admin') {
$name = 'Administrator';
$email = 'admin@example.org' ;
$admin = TRUE;
} else {
/* Get the name and email from the database. */
$query = $db->prepare('SELECT name, email
FROM users
WHERE username = :username');
$query->execute(array('username' => $clean['username']));
$result = $ query->fetch(PDO::FETCH_ASSOC);
$name = $result['name'];
$email = $result['email'];
$admin = FALSE;
}
?>
Because $admin is still explicitly set to TRUE or FALSE, everything seems to be fine. However, if another developer later adds an elseif statement to the code, it is likely that he will forget about it:
Copy code The code is as follows:
if (auth($username) == 'admin') {
$name = 'Administrator';
$email = 'admin@example.org ';
$admin = TRUE;
} elseif (auth($username) == 'mod') {
$name = 'Moderator';
$email = 'mod@example.org ';
$moderator = TRUE;
} else {
/* Get the name and email. */
$query = $db->prepare('SELECT name, email
FROM users
WHERE username = :username');
$query->execute(array('username' => $clean['username']));
$result = $query- >fetch(PDO::FETCH_ASSOC);
$name = $result['name'];
$email = $result['email'];
$admin = FALSE;
$ moderator = FALSE;
}
?>
If a user provides a username that triggers an elseif condition, $admin is not initialized, which may result in an error. Necessary behavior, or worse, a security hole. Additionally, a similar situation exists for the $moderator variable, which is not initialized in the first condition.
It is completely easy to avoid this situation by initializing $admin and $moderator:
Copy code The code is as follows:
$admin = FALSE;
$moderator = FALSE;
if (auth($username) == 'admin') {
$name = ' Administrator';
$email = 'admin@example.org';
$admin = TRUE;
} elseif (auth($username) == 'mod') {
$name = ' Moderator';
$email = 'mod@example.org';
$moderator = TRUE;
} else {
/* Get the name and email. */
$query = $db->prepare('SELECT name, email
FROM users
WHERE username = :username');
$query->execute(array('username' => $clean[' username']));
$result = $query->fetch(PDO::FETCH_ASSOC);
$name = $result['name'];
$email = $result['email '];
}
?>
Whatever the rest of the code is, it is now clear that $admin is FALSE unless it is explicitly set to something else. . The same goes for $moderator. The worst thing that can happen is that $admin or $moderator are not modified under any conditions, resulting in someone who is an administrator or moderator not being treated as the corresponding administrator or moderator.
If you want to shortcut something, and you feel a little disappointed to see that our examples include else. We have a bonus tip you might be interested in. We're not sure it can be considered a shortcut, but we hope it's still helpful.
Consider a function that detects whether a user is authorized to view a particular page:
Copy the code The code is as follows:
function authorized($username, $page) {
if (!isBlacklisted($username)) {
if (isAdmin($username)) {
return TRUE ;
} elseif (isAllowed($username, $page)) {
return TRUE;
} else {
return FALSE;
}
} else {
return FALSE ;
}
}
?>
This example is quite simple, as there are only three rules to consider:
administrators are always allowed access,
Those in the blacklist are always prohibited from accessing.
isAllowed() determines whether others have access.
(There is also a special case: when an administrator is in the blacklist, but this seems unlikely, so we will ignore this situation here).
We use functions to make this judgment to keep the code simple and focus on the business logic.
For example:
Copy code The code is as follows:
function authorized($username, $page) {
if (!isBlacklisted($username)) {
if (isAdmin($username) || isAllowed( $username, $page)) {
return TRUE;
} else {
return FALSE;
}
} else {
return FALSE;
}
}
?>
In fact, you can reduce the entire function to a compound condition:
Copy code Code As follows:
function authorized($username, $page) {
if (!isBlacklisted($username) && (isAdmin($username) || isAllowed( $username, $page)) {
return TRUE;
} else {
return FALSE;
}
}
?>
Finally , this can be reduced to only one return:
Copy code The code is as follows:
function authorized($username, $page) {
return (!isBlacklisted($username) && (isAdmin($username) || isAllowed($username, $page));
}
?>
If your goal is to transcribe the number of lines of code, then you can do it. However, you should notice that we are using isBlacklisted(), isAdmin() and isAllowed(). Depending on what's involved, reducing the code to just a single compound condition may not be attractive.
Now comes our little trick, an "immediate return" function, so if you return as soon as possible, You can express these rules very simply:
Copy the code The code is as follows:
function authorized ($username, $page) {
if (isBlacklisted($username)) {
return FALSE;
}
if (isAdmin($username)) {
return TRUE;
}
return isAllowed($username, $page);
}
?>
This example uses more lines of code, but it is very simple and unobtrusive. More importantly, this approach reduces the amount of context you have to consider. For example, once you determine whether a user is blacklisted, you can safely forget about it. This is quite helpful especially if your logic is complex.
4. Always use braces
PS: Forgiveness means "Drop Those Brackets"
According to the content of this article, our corresponding author should mean "braces" ," rather than brackets. "Curly brackets" may mean curly brackets, but "brackets" usually means "square brackets." This tip should be unconditionally ignored because, without curly braces, readability and maintainability are destroyed.
Give a simple example:
Copy code The code is as follows:
if ( date('d M') == '21 May')
$birthdays = array('Al Franken',
'Chris Shiflett',
'Chris Wallace',
'Lawrence Tureaud' );
?>
If you're good enough, smart enough, secure enough, notorious enough, or pitied enough, you might want to attend a social gathering on May 21st:
Copy code The code is as follows:
if (date('d M') == '21 May')
$birthdays = array('Al Franken',
'Chris Shiflett',
'Chris Wallace',
'Lawrence Tureaud');
party(TRUE) ;
?>
Without braces, this simple condition leads you to social gatherings every day. Maybe you have perseverance and therefore this mistake is a welcome one. Hopefully that silly example doesn't distract from the point that excessive partying can have an unexpected side effect.
To advocate dropping braces, previous articles used short statements like the following as examples:
Copy code The code is as follows:
if ($gollum == 'halfling') $height --;
else $height ++;
?>
Because each condition is placed on a separate line, this error may seem to occur less frequently, but this will lead to another problem: the code will be inconsistent and require more time to read and understand. Consistency is such an important characteristic that developers often adhere to a coding standard even if they don't like the coding standard itself.
We advocate always using braces:
Copy code The code is as follows:
if (date('d M') == '21 May') {
$birthdays = array('Al Franken',
'Chris Shiflett' ,
'Chris Wallace',
'Lawrence Tureaud');
party(TRUE);
}
?>
It doesn’t matter if you party every day Yes, but make sure this is well thought out, and please be sure to invite us!
5. Try to use str_replace() instead of ereg_replace() and preg_replace()
We hate it Hear the word of denial, but (sic) this little trick used to demonstrate misuse leads to the same abuse problem it was trying to avoid. (
We hate to sound disparaging, but this tip demonstrates the sort of misunderstanding that leads to the same misuse it's trying to prevent.)
It is obvious that string functions are faster and more efficient at character matching than regular expression functions , but the author's attempt to draw a corollary from this fails miserably :)
If you're using regular expressions, then ereg_replace() and preg_replace() will be much faster than str_replace().
Because str_replace() does not support pattern matching, this statement makes no sense. The choice between string functions and regular expression functions comes down to which is fit for purpose, not which is faster. If you need to match a pattern, use a regular expression function. If you need to match a string, use a string function.
6. Use the ternary operator
The benefits of the ternary operator are worth discussing. Here is a line taken from a recent audit we conducted:
Copy code The code is as follows:
$host = strlen($host) > 0 ? $host : htmlentities($ host);
?>
Ah, the author’s true intention was to escape $host if the length of the string is greater than 0, but he accidentally did the opposite. An easy mistake to make, right? Maybe. Easy to miss during code audit? certainly. Simplicity doesn't necessarily make code great.
The triple operator is also suitable for single rows, prototypes, and templates, but we believe that a plain conditional statement is always better. PHP is descriptive and detailed, and we think code should be too.
7. Memcached
Disk access is slow, network access is also slow, and databases usually use both. Memory is fast. Using a local cache avoids the overhead of network and disk access. Combine these principles, and you have memcached, a "distributed memory object caching system" originally developed for the Perl-based blogging platform LiveJournal.
If your application is not distributed across multiple servers, you may not need memcached. Single caching method - serialize the data and save it in a temporary file. For example – a lot of redundant work can be eliminated for each request. In fact, this is the type of low-hanging fruit we consider when helping our customers optimize their applications.
What is low-hanging fruit:
A fruit-bearing tree often contains some branches low enough for animals and humans to reach without much effort. The fruit contained on these lower branches may be not be as ripe or attractive as the fruit on higher limbs, but it is usually more abundant and easier to harvest. From this we get the popular expression “low hanging fruit”, which generally means selecting the easiest targets with the least amount of effort. The simplest and most common way to cache data in memory is to use the shared type helper methods in APC, a caching system originally developed by our colleague George Schlossnagle. Consider the following example:
Copy code The code is as follows:
$feed = apc_fetch('news');
if ($feed === FALSE) {
$feed = file_get_contents('http://example.org/news.xml');
// Store this data in shared memory for five minutes.
apc_store('news', $feed, 300);
}
// Do something with $feed.
?>
With this type of caching, you don’t have to wait for the remote server to send feed data on every request. Some latency is incurred - in this example the upper limit is five minutes, but this can be adjusted to near real-time depending on your application needs.
8. Use a framework
All decisions have consequences, we love frameworks - in fact, the lead developers of CakePHP and Solar work with us at OmniTI - but use a framework It doesn't magically make what you're doing better.
In October, our colleague Paul Jones wrote an article for HP Advent called The Framework as Franchise, in which he compared frameworks to commercial franchises. He quotes advice from Michael Gerber's book "The E-Myth Revisited":
Gerber points out that to run a successful business, the entrepreneur needs to act like he is going to sell his business as a Acts like the franchise's archetypes. This is the only way a business owner can make the business run without being personally involved in every decision.
( Gerber notes that to run a successful business, the entrepreneur needs to act as if he is going to sell his business as a franchise prototype. It is the only way the business owner can make the business operate without him being personally involved in every decision.)
This is good advice. Whether you plan to use a framework or define your own tags and conventions, it's important to see the value from a future developer's perspective.
While we would love to give you a one-size-fits-all truth, stretching the idea to show that a framework is always appropriate is not what we want to do.
If you ask us if we should use a framework, the best answer we can give is, "It depends."
9. Correct use of error suppression operators Always try to avoid using error suppression operator symbols. In a previous article, the author stated:
The @ operator is quite slow and can be very expensive if you need to write high-performance code.
Error suppression is slow because PHP dynamically changes the error_reporting level to 0 before executing the suppression statement, and then immediately restores it. This costs money.
Worse yet, using error suppressors makes it difficult to track down the root cause of the problem.
The previous article used the following example to support assigning a value to a variable by reference. . . (How to translate this sentence? I’m confused~~~)
The previous article uses the following example to support the practice of assigning a variable by reference when it is unknown if $albus is set:
Copy code The code is as follows:
$albert =& $albus;
?>
While this works - for now - relying on strange, undefined behavior, having a good understanding of why this works is a good way to generate bugs.
Because $albert refers to $albus, later modifications to $albus will also affect $albert.
A better solution is to use isset() and add braces:
Copy code The code is as follows:
if (!isset($albus)) {
$ albert = NULL;
}
?>
Assigning NULL to $albert has the same effect as assigning it a non-existent reference, but it is more clear and greatly improved Improves code clarity and avoids reference relationships between two variables.
If you inherit code that uses the error suppression operator excessively, we've got a bonus tip for you. There is a new PECL extension called Scream that disables error suppression.
10. Use isset() Instead of strlen()
this is actually a neat approach, although the previous article didn't explain this at all. The following is a supplementary example:
Copy code The code is as follows:
if (isset($ username[5])) {
// The username is at least six characters long.
}
?>
When you treat a string as an array (no lights in the wilderness: in fact, in C language, characters usually exist in the form of arrays), each character in the string is an element of the array. By checking for the presence or absence of a specific element, you can check whether the string has at least that many characters present. (Note that the first character is element 0, so $username[5] is the 6th character in $username.)
The reason why using isset in this way is slightly faster than strlen is complicated. The simple explanation is that strlen() is a function and isset() is a syntactic structure. Generally speaking,
calling a function is more expensive than using language constructs.
About the author:
Hi, we are Chris Shiflett and Sean Coates. We both work at OmniTI ("the most important web company you've never heard of"), blog about PHP and other stuff at shiflett.org and seancoates.com, curate PHP Advent, and do the Twitter thing as @shiflett and @coates.
Translation FROM: http://coding.smashingmagazine.com/2009/03/24/10-useful-php-tips -revisited/
http://www.bkjia.com/PHPjc/324064.htmlwww.bkjia.comtruehttp: //www.bkjia.com/PHPjc/324064.htmlTechArticle1. Use a SQL injection cheat sheet. A basic principle is to never trust user-submitted data. Another rule is to escape data when you send or store it (...