一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

10條PHP高級技巧[修正版]

1.使用一個SQL注射備忘單
一個基本的原則就是,永遠不要相信用戶提交的數據。
另一個規則就是,在你發送或者存儲數據時對它進行轉義(escape)。
可以總結為:filter input, escape output (FIEO). 輸入過濾,輸出轉義。
通常導致SQL注射漏洞的原因是沒有對輸入進行過濾,如下語句:
復制代碼 代碼如下:
<?php
$query = "SELECT *
FROM users
WHERE name = '{$_GET['name']}'";

在這個例子中,$_GET['name']來自用戶提交的數據,既沒有進行轉義,也沒有進行過濾~~
對于轉義輸出,你要記住用于你程序外部的數據需要被轉義,否則,它可能被錯誤地解析。
相反,過濾輸入能確保數據在使用前是正確的.
對于過濾輸入,你要記住,在你程序外部的原始數據需要被過濾,因為它們是不可信任的。
如下例子演示了輸入過濾和輸出轉義:
復制代碼 代碼如下:
<?php
// 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']}'";
?>

另一個有效防止SQL注射的方法是使用prepare 語句,如:
復制代碼 代碼如下:
<?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.了解比較運算符之間的不同
例如,你使用strpos() 來檢測在一個字符串中是否存在一個子串 (如果子串沒有找到,函數將返回 FALSE ), 結果可能會導致錯誤:
復制代碼 代碼如下:
<?php
$authors = 'Chris & Sean';
if (strpos($authors, 'Chris')) {
echo 'Chris is an author.';
} else {
echo 'Chris is not an author.';
}
?>

上例中,由于子串處于最開始的位置,因此strpos() 函數正確地返回了0,表明子串處于字符串中最開始的位置。然后,因為條件語句會把結果當成Boolean(布爾)類型的,因此 0 就被php給計算成了 FALSE,最終導致條件語句判斷失敗。
當然,這個BUG可以用嚴格的比較語句來修正:
復制代碼 代碼如下:
<?php
if (strpos($authors, 'Chris') !== FALSE) {
echo 'Chris is an author.';
} else {
echo 'Chris is not an author.';
}
?>

3.減少else(Shortcut the else)
記住,在你使用變量前總是要先初始化它們。
考慮如下一個用來根據用戶名來檢測用戶是否是管理員的條件語句:
復制代碼 代碼如下:
<?php
if (auth($username) == 'admin') {
$admin = TRUE;
} else {
$admin = FALSE;
}
?>

這個看起來似乎足夠安全,因為看一眼就很容易理解。想象一下有一個更復雜一點的例子,它為name和email同時設置變量,為方便起見:
復制代碼 代碼如下:
<?php
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;
}
?>

因為 $admin 還是明確地被設置為TRUE or FALSE,似乎一切都完好。但是,如果另一個開發者后來在代碼里加了一個elseif語句,很可能他會忘記這回事:
復制代碼 代碼如下:
<?php
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;
}
?>

如果一個用戶提供一個能夠觸發elseif條件的用戶名(username), $admin 沒有被初始化,這可能會導致不必要的行為,或者更糟糕的情況,一個安全漏洞。另外,一個類似的情況對于 $moderator 變量來說同樣存在,它在第一個條件中沒有被初始化。
通過初始化$admin 和 $moderator ,這是完全很容易避免這一情況的發生的:
復制代碼 代碼如下:
<?php
$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'];
}
?>

不管剩下的代碼是什么,現在已經明確了 $admin 值 為FALSE ,除非它被顯式地設置為其它值。對于 $moderator 也是一樣的。最壞的可能發生的情況就是,在任何條件下都沒有修改$admin 或 $moderator ,導致某個是administrator 或moderator的人沒有被當作相應的administrator 或moderator 。
如果你想 shortcut something ,并且你看到我們的例子有包含有else覺得有點失望。我們有一個bonus tip 你可能會感興趣的。我們并不確定它可以被認為是a shortcut,但是我們希望它仍然是有幫助的。
考慮一下一個用于檢測一個用戶是否被授權查看一個特定頁面的函數:
復制代碼 代碼如下:
<?php
function authorized($username, $page) {
if (!isBlacklisted($username)) {
if (isAdmin($username)) {
return TRUE;
} elseif (isAllowed($username, $page)) {
return TRUE;
} else {
return FALSE;
}
} else {
return FALSE;
}
}
?>

這個例子是相當的簡單,因為只有三條規則需要考慮:
administrators 總是被允許訪問的,
處于黑名單的永遠是禁止訪問的,
isAllowed()決定其它人是否有權訪問。
(還有一個特例是:當一個administrator 處于黑名單中,但這似乎是不太可能的事,所以我們這里直接忽視這種情況)。
我們使用函數來做這個判斷以保持代碼的簡潔然后集中注意力到業務邏輯上去。
如:
復制代碼 代碼如下:
<?php
function authorized($username, $page) {
if (!isBlacklisted($username)) {
if (isAdmin($username) || isAllowed($username, $page)) {
return TRUE;
} else {
return FALSE;
}
} else {
return FALSE;
}
}
?>

事實上,你可以精減整個函數到一個復合條件:
復制代碼 代碼如下:
<?php
function authorized($username, $page) {
if (!isBlacklisted($username) && (isAdmin($username) || isAllowed($username, $page)) {
return TRUE;
} else {
return FALSE;
}
}
?>

最后,這個可以被減少到只有一個return:
復制代碼 代碼如下:
<?php
function authorized($username, $page) {
return (!isBlacklisted($username) && (isAdmin($username) || isAllowed($username, $page));
}
?>

如果你的目標是謄清代碼的行數,那么這樣你做到的。但是,你要注意到,我們在用isBlacklisted(), isAdmin() 和 isAllowed() ,這取決于參與這些判斷的東西,減少代碼到只剩下一個復合條件可能不吸引人。
這下說到我們的小技巧上了,一個“立即返回”函數,所以,如果你盡快返回,你可以很簡單地表達這些規則:
復制代碼 代碼如下:
<?php
function authorized($username, $page) {
if (isBlacklisted($username)) {
return FALSE;
}
if (isAdmin($username)) {
return TRUE;
}
return isAllowed($username, $page);
}
?>

這個例子使用了更多行數的代碼,但是它是非常簡單和不惹人注意的。更重要的是,這個方法減少了你必需考慮的上下文的數量。例如,一旦你決定了用戶是否處于黑名單里面,你就可以安全地忘掉這件事了。特別是你的邏輯很復雜的時候,這是相當的有幫助的。
4. 總是使用大括號
PS:原諒是“扔掉那些方括號 Drop Those Brackets”
根據本文的內容, 我們相應作者的意思應該是 “braces,” 而不是brackets. “Curly brackets” 可能有大括號的意思, 但是”brackets” 通常表示 “方括號”的意思。這個技巧應該被無條件的忽略,因為,沒有大括號,可讀性和可維護性被破壞了。
舉一個簡單的例子:
復制代碼 代碼如下:
<?php
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, 你可能會想在5月21號參加社交聚會:
復制代碼 代碼如下:
<?php
if (date('d M') == '21 May')
$birthdays = array('Al Franken',
'Chris Shiflett',
'Chris Wallace',
'Lawrence Tureaud');
party(TRUE);
?>

沒有大括號,這個簡單的條件導致你每天參加社交聚會 。也許你有毅力,因此這個錯誤是一個受歡迎的。希望那個愚蠢的例子并不分散這一的觀點,那就是過度狂歡是一種出人意料的副作用。
為了提倡丟掉大括號,先前的文章使用類似下面的簡短的語句作為例子:
復制代碼 代碼如下:
<?php
if ($gollum == 'halfling') $height --;
else $height ++;
?>

因為每個條件被放在單獨的一行, 這種錯誤似乎會較少發生, 但是這將導致另一個問題:代碼的不一致和需要更多的時間來閱讀和理解。一致性是這樣一個重要的特性,以致開發人員經常遵守一個編碼標準,即使他們不喜歡編碼標準本身。
我們提倡總是使用大括號:
復制代碼 代碼如下:
<?php
if (date('d M') == '21 May') {
$birthdays = array('Al Franken',
'Chris Shiflett',
'Chris Wallace',
'Lawrence Tureaud');
party(TRUE);
}
?>

你天天聚會是沒關系的,但要保證這是經過思考的,還有,請一定要邀請我們!
5. 盡量用str_replace() 而不是 ereg_replace() 和 preg_replace()
我們討厭聽到的否認的話,但是(原文)這個用于演示誤用的小技巧導致了它試圖避免的同樣的濫用問題。(
We hate to sound disparaging, but this tip demonstrates the sort of misunderstanding that leads to the same misuse it's trying to prevent.)
很明顯字符串函數比正則表達式函數在字符匹配方面更快速高效,但是作者糟糕地試圖從失敗中得出一個推論:
(FIX ME: It's an obvious truth that string functions are faster at string 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. 使用三重運算符
三元運算符的好處是值得討論的. 下面是一行從最近我們進行的審計的代碼中取出的:
復制代碼 代碼如下:
<?php
$host = strlen($host) > 0 ? $host : htmlentities($host);
?>

啊,作者的真實意愿是如果字符串的長度大于0 就轉義 $host , 但是卻意外地做了相反的事情。很容易犯的錯誤是吧?也許吧。在代碼審計過程中很容易錯過?當然。簡潔并不一定能使代碼變得很好。
三重運算符對于單行,原型,和模板也行是適合的,但是我們相信一個普通的條件語句總是更好的。php是描述性的和詳細的,我們認為代碼也應該是。
7. Memcached
磁盤訪問是慢速的,網絡訪問也是慢的,數據庫通常使用這二者。
內存是很快的。使用本地緩存可以避免網絡和磁盤訪問的開銷。結合這些道理,然后,你想到了memcached,一個“分布式內存對象緩存系統”,最初為基于Perl的博客平臺LiveJournal開發的。
如果你的程序不是分布在多個服務器上,你可能并不需要memcached。單的緩存方法――序列化數據然后將它保存在一個臨時文件中。例如 主站蜘蛛池模板: 国产伦精品一区二区三区视频小说 | 中文字幕在线观看一区二区三区 | 亚洲午夜精品久久久久久成年 | 欧美人与禽 | 伊人久久香| 色啦啦 | 成人黄色小视频在线观看 | 国产精品第5页 | 激情在线播放免费视频高清 | 久久综合亚洲鲁鲁五月天欧美 | 色综合久久88色综合天天提莫 | 日韩香蕉网 | 91自啪| 亚洲精品高清国产一线久久97 | 日韩在线视频中文字幕 | 伊人激情网 | 亚洲一区二区三区免费看 | 免费永久国产在线视频 | 国产成人久久蜜一区二区 | 在线观看视频网站www色 | 国产三级级在线观看大学生 | 四虎影视在线永久免费看黄 | 欧美成人福利 | 欧美日韩乱国产 | 欧美一区二区三区视视频 | 在线免费色 | 免费观看成人www精品视频在线 | 四色成人 | 一级女毛片 | 婷婷色综合网 | 中文字幕日韩理论在线 | 2021久久精品国产99国产 | 黄视频在线免费看 | 伊人不卡久久大香线蕉综合影院 | 国产v精品成人免费视频71sao | 日本一区二区三区久久久久 | 在线永久免费观看黄网站 | 欧美午夜色大片在线观看免费 | 亚洲综合激情 | 永久免费aavv视频播放 | 欧美性色视频 |