《Head First PHP & MySQL》學習總結
第1章 為靜態頁面賦予生命
1 通過引入PHP,web伺服器能夠動態地生成HTML web頁面
2 表單使用HTML<form>標籤建立,每個<form>標籤都有一個action屬性,不論為action屬性設定什麼檔名,表單提交時Web伺服器都會用設定的這個檔案來處理表單。如
<form method="post" action="report.php"> </form>
3 php變數可以直接寫在雙引號字串中
$msg = "$name was abducted $when_it_happened and was gone for $how_long.\n".
"Number of aliens: $how_many\n".
"Alien description: $alien_description\n".
"What they did: $what_they_did\n".
"Fang spotted: $fang_spotted\n".
"Other comments: $other";
4 php是一種程式語言,需要一個允許它允許的環境。
5 <?php ...... ?> 為php程式碼區
6 php的一些規則
- 每個php語句都必須以一個分號( ; )結束,如 echo "hello " ;
- 如果web頁面有php程式碼,一個好的想法是將web伺服器上的副檔名命名為.php而不是.html
- php變數總是以一個美元符號( $ ) 開頭,如 $email
- php變數美元符號後第一個字元可以是一個字母或下劃線( _ )。變數名只能由字母,數字或下劃線組成
7 php的字串可以用雙引號或單引號
8 $_POST是一個特殊的變數,稱為超級全域性變數。是php內建。直接繫結到HTML表單使用的表單post提交方法
9 echo命令用於將字串作為html內容輸出到瀏覽器上
10 點號( . ) 用於將字串和變數連結在一起
11 換行符(\n)只能在雙引號串中轉義,才會生效。單引號字串被認為是原始文字,而php處理雙引號串時會尋找變數。在一個雙引號中遇到變數時,php會在串中插入該變數的值。
$t = 123;
echo "hello , $t \n"; // 輸出 hello , 123 ,並另起一行
echo 'hello , $t\n'; // 輸出hello , $t\n
第2章 連線MySQL
1 操作MySQL的三個函式
// mysqli_connect()連線資料庫
$dbc = mysqli_connect("127.0.0.1","root","root","aliendatabase") or die("Error connecting to MySQL server.");
$query = "INSERT INTO aliens_abduction (first_name, last_name, when_it_happened, how_long, " .
"how_many, alien_description, what_they_did, fang_spotted, other, email) " .
"VALUES ('$first_name', '$last_name', '$when_it_happened', '$how_long', '$how_many', " .
"'$alien_description', '$what_they_did', '$fang_spotted', '$other', '$email')";
//操作查詢語句
$result = mysqli_query($dbc,$query) or die("Error querying database.");
//斷開與資料庫的連線
mysqli_close($dbc);
2 用mysqli_connect( host,username,password,dbname,port,socket) 建立連線,引數都是可選項
$dbc = mysqli_connect(
"127.0.0.1", // 資料庫所在的位置
"yang", // 資料庫的帳號
"123456", // 密碼
"aliendatabase" ) ; // 資料庫名
3 也可以使用mysqli_select_db( ) 選擇資料庫
$dbc = mysqli_connect("localhost" , "root" , "root") or die("Error"); // 如果失敗會直接呼叫die()
mysqli_select_db($dbc , "aliendatabase"); // 此處選擇資料庫
4 使用mysqli_query(database_connection , query) 函式操作MySQL資料庫。
$result = mysqli_query($dbc , $query) or die("Error querying database");
5 用mysqli_close(database_connection) 關閉連線,用完MySQL資料庫連線進行關閉是個好習慣。
6 資料庫伺服器同時只允許有一定數目的可用連線,所以要儘可能地節省。關閉一個連線會釋放掉這個連線。
第3章 建立與填充資料庫
1 如果知道某個欄位最多有n個字元,使用varchar比char要好。char比varchar效率高,它不必維護可變長度。如果明確的 知道欄位的固定長度更適合用char。
2 查詢結果,用mysqli_fetch_array()獲取查詢結果,呼叫一次讀一行
$query = "SELECT * FROM elvis_database" ;
$result = mysqli_query($dbc , $query) ;
while( $row = mysqli_fetch_array($result)){ // $row是一個數組
echo $row['first_name']." ".$row["last_name"]." ".$row["email"];
}
第4章 現實的實際應用
1 isset()判斷一個變數是否存在,empty()函式判斷變數是否包含一個空值。當一個變數已被賦值,isset()返回true。當一個變數設定為0,空串,false或NULL時empty()返回true。
2 isset()無法顯示出空表單域與已填充表單域之間有何區別。
3 php中,與操作符(&&)和或操作符(||)都是短路操作符
4 php巢狀html程式碼
<?php
$t = 1;
if($t == 1){
?>
<h>hello</h>
<?php
} else {
?>
<h>ok</h>
<?php
}
?>
5 將表單動作指向指令碼,指令碼URL可以用$_SERVER["PHP_SELF"],如下
<form action="<?php echo $_SERVER['PHP_SELF'];?>" method="post"> . . . </form>
6 如果表單form定義了提交控制元件<input type="submit" name="submit">,則可以用isset($_POST["submit"])判斷是否已經點選過提交
<form action = "<?php echo $_SERVER['PHP_SELF'];?>" method="post">
<input type="submit" name="submit" value="ok">
</form>
<?php
if(isset($_POST['submit']))
echo "submit";
else
echo "none";
?>
7 MySQL插入欄位
mysql> alter table email_list ADD id int not null auto_increment FIRST , add primary key(id); ### FIRST表示插入到第一列
8 複選框的name屬性帶方括號([ ])會自動將複選框值放入該name值的陣列中,如下
<input type="checkbox" value="1" name="school[ ]">
9 php可以利用foreach迴圈處理陣列,如下
foreach($colors as $color) {
echo $color ;
}
第5章 使用儲存在檔案中的資料
1 MySQL的alter語句
- alter table xxtable add column age tinyint // 新增一列
- alter table xxtable drop column age // 刪除一列
- alter table xxtable change column score high_score int // 修改列,列名改為high_score,型別改為int
- alter table xxtable modify column date datetime after age // 修改列的資料型別或位置
2 表單上傳檔案
<form enctype="multipart/form-data" method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">
<input type="hidden" name="MAX_FILE_SIZE" value="32768"/>
<label for="name">Name:</label><input type="text" id="name" name="name" value="<?php if(!empty($name)) echo $name;?>"/><br />
<label for="score">Score:</label><input type="text" id="score" name="score" value="<?php if(!empty($score)) echo $score;?>"/><br />
<label for="screenshot">Screen shot:</label>
<input type="file" id="screenshot" name="screenshot"/>
<hr />
<input type="submit" name="submit" value="Add"/>
</form>
echo $_FILES['screenshot']['name'].": ".$_FILES['screenshot']['type'].": ".$_FILES['screenshot']['size'].": ".$_FILES['screenshot']['tmp_name'].": ".$_FILES['screenshot']['error'];
if(is_file($row['screenshot']) && filesize($row['screenshot'])>0)
- <form enctype="multipart/form-data" ... > 中的enctype屬性告訴表單要使用檔案上傳所需的一種特殊型別編碼
- <input type="file" ... > type屬性表示檔案
- 表單上傳的檔案要用 $_FILES這個PHP內建的超級全域性變數,而不是$_POST。$_FILES['screenshot']['name']為檔名,$_FILES['screenshot']['type']為檔案的MIME型別,$_FILES['screenshot']['size']為檔案大小,$_FILES['screenshot']['tmp_name']為檔案在伺服器上的臨時儲存位置,$_FILES['screenshot']['error']為上傳結果,0表示成功
- is_file() 判斷是否為檔案,filesize()獲取檔案大小
- <input type="hidden" name="MAX_FILE_SIZE" value="32768"/> 這樣的設定可以限制form上傳的檔案大小隻能為32k
3 php函式move_uploaded_file()接受一個檔案的源位置和目標位置,然後負責完成檔案移動。如下
define('GW_UPLOADPATH','images/');
$screenshot = $_FILES['screenshot']['name'];
$target = GW_UPLOADPATH.$screenshot;
move_uploaded_file($_FILES['screenshot']['tmp_name'], $target); // 將檔案從臨時儲存位置移動到目標位置
4 define()定義常量,如下
define( 'DW' , 123) ; // 定義常量DW的值為123
5 共享指令碼資料
1) 在指令碼appvars.php先定義變數
<?php define('GW_UPLOADPATH','images/'); ?>
2) 在其他的檔案用require_once()來包含這個指令碼,這個檔案就可以使用這個變數
<?php require_once('appvars.php'); ?>
6 require_once()和include()的區別在於如果未找到包含檔案,require_once()會產生一個錯誤,而include()不會顯示任何錯誤。require_once也保證檔案不會被包含多次。php還有include_once()和require()。
7 MySQL的結果排序
select * from guitarwars order by score asc;
select * from guitarwars order by score desc,date asc;
8 unlink()函式用於刪除一個檔案,如下所示,符號@為了避免檔案刪除失敗報錯
@unlink($_FILES['screenshot']['tmp_name'];
9 POST請求只能從表單發出,而GET請求可以打包成URL
第6章 保證應用安全
1 http認證提供了一種使用PHP保護頁面的簡單方法,$_SERVER['PHP_AUTH_USER']儲存了使用者名稱,$_SERVER['PHP_AUTH_PW']儲存了密碼。
2 HTTP認證的基本思想是,伺服器會“扣留”一個受保護的web頁面,然後要求瀏覽器向用戶詢問一個使用者名稱和口令。瀏覽器和伺服器之間是通過首部完成,首部是一個短小的文字訊息,包含所請求或傳送的特定指令。首部如下
3 瀏覽器鍵入一個URL或點選Web頁面一個連結時,瀏覽器會組裝一個GET請求,併發送到伺服器。這個請求會打包成一系列的首部,每個首部包含有關請求的一些資訊。
4 利用php控制首部,header()函式允許從php指令碼建立和傳送首部,header()函式會立即從伺服器向瀏覽器傳送一個首部,而且這個函式必須在向瀏覽器傳送任何具體內容之前呼叫。header()函式呼叫應當放在php指令碼的所有html程式碼之前。如下所示
<?php
header("Content-Type:text/html");
?>
注:在首部之前即使傳送一個空格或字元瀏覽器都會拒絕。使用即使是<?php標記前面多一個隨意的空格都會導致這個指令碼失效。
5 首部可以做很多事
- 位置首部,重定向到其他頁面。
<?php
// 重定向到百度
header('Location:http://www.baidu.com');
?>
- 重新整理首部,設定時間重新整理頁面
<?php
// 5秒後重新整理頁面,到百度
header("Refresh:5;url=http://www.baidu.com");
echo "In 5 seconds you'll be taken to baidu";
?>
- 內容首部,控制由伺服器傳送的內容型別
<?php
// 瀏覽器會根據text/plain只作為文字顯示
header('Content-Type:text/plain');
echo "This <strong>text</strong> won't actually be bold";
?>
6 http的認證,會自動有彈窗提示要求輸入使用者名稱和密碼
<?php
$username = 'rock';
$password = 'roll';
if(!isset($_SERVER['PHP_AUTH_USER'])||!isset($_SERVER['PHP_AUTH_PW'])||($_SERVER['PHP_AUTH_USER']!=$username||$_SERVER['PHP_AUTH_PW']!=$password)){
header('HTTP/1.1401 Unauthorized');
header('WWW-Authenticate:Basic realm="Guitar Wars"');
exit('<h2>Guitar Wars</h2>Sorry, you must enter a valid user name and password to access this page.');
}
?>
7 保護資料避免SQL注入
- 可以採用trim()去掉字串前面和後面多餘的空格
- 內建函式mysqli_real_escape_string( )將有危險的字元進行轉義。
$score = "1000','1v1.jpg',1);";
$score = mysqli_real_escape_string($dbc,trim($score)); //$score 變成"1000\',\'1v1.jpg\',1);"
- MySQL裡某些欄位可以宣告為預設值,不需要insert該欄位值
- 表單驗證安全後再插入資料
第7章 構建個性化Web應用
1 MySQL有個SHA()的函式,SHA(Secure Hash Algorithm )會對文字串應用一個加密演算法,結果是一個唯一加密串,長度固定為40個十六進位制字元,如下
insert into mismatch_user(username , password , join_date) values( 'Yang' , SHA('123456') , NOW())
注:SHA()函式提供的是單向加密,即無法對已經加密的資料解密。
2 MySQL提供了另一個與SHA()類似的函式,名為MD5(),一般認為SHA()會更安全些。
3 可以使用mysqli_num_rows()函式檢視搜尋結果個數
$dbc = mysqli_connect(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME) or die("Fail to connect");
$user_name = mysqli_real_escape_string($dbc,trim($_SERVER["PHP_AUTH_USER"]));
$user_password = mysqli_real_escape_string($dbc,trim($_SERVER["PHP_AUTH_PW"]));
$query = "select user_id,username from mismatch_user where username='$user_name' and password=sha('$user_password')";
$data = mysqli_query($dbc,$query);
if(mysqli_num_rows($data) == 1){
$row = mysqli_fetch_array($data);
$user_id = $row['user_id'];
$username = $row['username'];
}
注:sql語句如果是字串變數記得一定要在包圍在引號裡,不如sql語句執行時會異常
4 HTTP認證只有在瀏覽器關閉時才會重置,或人工手動清除。
5 PHP通過一個名為setcookie()函式和一個$_COOKIE的超級全域性變數提供對cookie的訪問。如下
// 將"sidneyk"存在名為username的cookie中
setcookie("username","sidneyk");
// 通過$_COOKIE['username']取到"sidneyk"值
$username = $_COOKIE['username'];
6 setcookie()還接受可選的第三個引數,即設定cookie的到期日期。到了這個日期時cookie會自動刪除。如果沒有指定日期,cookie會在瀏覽器關閉時自動到期。
<?php
require_once('connectvars.php');
$error_msg = "";
if(!isset($_COOKIE['user_id'])){
if(isset($_POST['submit'])){
$dbc = mysqli_connect(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME) or die("Fail to connect");
$user_name = mysqli_real_escape_string($dbc,trim($_POST['username']));
$user_password = mysqli_real_escape_string($dbc,trim($_POST['password']));
if(!empty($user_name) && !empty($user_password)){
$query = "select user_id,username from mismatch_user where username='$user_name' and password=sha('$user_password')";
error_log($query);
$data = mysqli_query($dbc,$query);
error_log(mysqli_num_rows($data));
if(mysqli_num_rows($data) == 1){
$row = mysqli_fetch_array($data);
setcookie("user_id",$row['user_id']);
setcookie("username",$row['username']);
$home_url = "http://".$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF'])."/index.php";
header("Location: ".$home_url);
}else{
$error_msg = "Sorry, you must enter a valid username and password to log in.";
}
}else{
$error_msg = "Sorry, you must enter your username and password to log in.";
}
}
}
?>
<html>
<head>
<title>Mismatch - Log In</title>
<link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
<h3>Mismatch - Log In</h3>
<?php
if(empty($_COOKIE["user_id"])){
echo "<p class='error'>$error_msg</p>";
?>
<form method="post" action="<?php echo $_SERVER['PHP_SELF'];?>">
<fieldset>
<legend>Log In</legend>
<label for="username">Username: </label>
<input type="text" id="username" name="username" value="<?php if(!empty($user_name)) echo $user_name;?>"/><br />
<label for="password">Password: </label>
<input type="password" id="password" name="password"/>
</fieldset>
<input type="submit" name="submit" value="Log In"/>
</form>
<?php
}else{
echo "<p class='login'>You are logged in as ".$_COOKIE['username'].".</p>";
}
?>
</body>
</html>
7 刪除cookie要通過呼叫setcookie()設定過期的時間,如下
setcookie("username","sidneyk",time()-3600);
8 會話允許將小段資料持久地儲存在伺服器上,而不依賴於客戶端。它比cookie更安全和可靠。但不同於cookie,會話無法對一個會話變數將資料儲存多久做太多控制。會話一結束就會自動銷燬會話變數。關閉瀏覽器,會話也會結束。
會話有非常明確的開始和結束。session_start()函式開始一個會話,並允許在會話變數中儲存資料。session_start()不會設定任何資料,而只是建立會話並開始執行。會話在內部由一個唯一的會話識別符號標識。一旦會話開始,就可以用超級變數$_SESSION來設定會話變數。瀏覽器關閉或呼叫session_destroy()時會話會結束。
session_start(); // 開始會話
$_SESSION['username'] = 'sidneyk'; // 設定會話變數
$username = $_SESSION['username'] ; // 獲取會話變數
session_destroy(); // 結束會話
注:session_destroy()只是結束會話,但不會銷燬會話變數。所以一般在結束之前要手動刪除會話變數。有一個快捷方法即把$_SESSION設定為空陣列,$_SESSION = array()。
9 會話在後臺實際上會使用cookie,如果瀏覽器支援cookie,會話可能會設定一個cookie臨時儲存會話ID。PHP還必須刪除可能在瀏覽器上自動建立來儲存會話ID的所有cookie。如下
if(isset($_COOKIE[session_name()])){
setcookie(session_name(),"",time()-3600);
}
10 使用會話完成登出的必要步驟
- 刪除會話變數,$_SESSION = array()
- 檢視會話cookie是否存在,存在則將其刪除 if(isset($_COOKIE[session_name()]))
- 銷燬會話 session_destroy()
- 將使用者重定向到主頁 header()
11 不同的地方呼叫session_start(),即session_start()多次被呼叫,但不會建立多個會話,還是隻有一個會話。
12 cookie的生命期並不與瀏覽器例項繫結,即使關閉瀏覽器,cookie也不會消失。cookie可以永存,至少在它的到期日期來到之前。會話session可以比cookie儲存更大的資料。
13 為了避免程式碼重複,將重複的程式碼可以獨立出來做一個檔案,如下
- header.php 頁首
- navmenu.php 導航選單
- startsession.php 會話啟動指令碼
- footer.php 頁尾
第8章 收穫資料
1 外來鍵(foreign key)將一個表中的一行連結到另一個表中的一行。一個表中的外來鍵引用另一個表的主鍵,從而建立這兩個表間的一個聯絡用於查詢。
2 php支援三元操作符( ? : ) , condition ? A : B
第9章 通過函式改善生活
1 預設情況下MySQL的where子句是不區分大小寫
2 在SQL中,百分號(%)可以代表0或多個字元,下劃線(_)表示一個字元,如下
select * from xxx like '_ _ _ hello' ; // 表示匹配xxxhello
3 explode()可以將一個字串拆分為多個單獨的子字串陣列,如下
$search_words = explode( ' ' , 'Tipper Cow') ; // 第一個引數是定界符,即根據什麼拆分,可以是一個字元或多個字元。
4 implode()可以將多個子字串組合成一個字串,如下
$where_clause = implode(' or ' , $where_list) ; // 第一個引數是定界符,即子字串間加入該引數組合
5 str_replace()替換字串或單個字元,如下
$clean_search = str_replace("thousands" , "hundreds" , "Make thousands of dollars your very first month"); // 在第三個引數裡找出第一個引數的字串,用第二個字串替換
注:explode()和implode(),str_replace()都是準確使用定界符,如定界符為一個空格,源字串的連續三個空格會被當成三個定界符,如下
$user_search = "bull matador cape";
$search_words = explode(" ",$user_search);
var_dump($search_words);輸出: array(5) { [0]=> string(4) "bull" [1]=> string(7) "matador" [2]=> string(0) "" [3]=> string(0) "" [4]=> string(4) "cape" }
6 陣列增加
$user_search = "bull matador cape ok";
$search_words = explode(" ",$user_search);
$temp = array();
foreach($search_words as $word){
$temp[] = $word; // 可以不用填寫陣列下標
}
7 substr( string , start , length) 擷取字串的一部分,第一個引數string是源字串,第二個引數是擷取起點,第三個引數是擷取的長度,這個是可選引數。
$job_desc = "Are you a practioner of the lost art of cat juggling?";
echo substr($job_desc,4,3) ; // 輸出 you
echo substr($job_desc,49) ; // 輸出ing?
echo substr($job_desc,-53,7) ; // 輸出 Are you
echo substr($job_desc,-9) ; // 輸出juggling?
8 定義函式,使用關鍵詞function
function replace_commas($str){
$new_str = str_replace(',',' ',$str);
return $new_str;
}
第10章 正則表示式
1