過濾、驗證和轉義數據
過濾數據
- 不要相信任何外部數據!
- 常見的有如下幾種數據須要過濾:HTML,SQL查詢,用戶提交的信息(郵件地址、電話號碼、身份證)
HTMLphp
- htmlentities()
- HTML Purifier library (https://github.com/ezyang/htmlpurifier)
SQL querieshtml
User profilemysql
- filter_var(), filter_input()
驗證數據
轉義輸出
- htmlentities() ENT_QUOTES UTF-8
- twig/twig 或 smarty/smarty 等模板引擎默認輸出轉義
密碼
- bcrypt
- Password Hashing API: password_hash(), password_verify(), password_needs_rehash()
時間和日期
不建議本身手動處理時間和日期,由於裏面有太多要考慮的東西:時間格式,時區,夏令時,閏年,閏秒,以及不一樣天數的月份。web
而是,應當使用 DateTime, DateInterval, DateTimeZone 類來處理時間sql
設置默認時區
- php.ini 中設置
date.timezone = 'PRC'
date_default_timezone_set('PRC')數據庫
DateTime類
- new DateTime('2014-04-27 5:03 AM'), 傳入一個PHP可以理解的時間字符串
DateTime::createFromFormat('Y-m-d H:i:s', '2019-04-02 18:08:00'),從指定的時間格式建立時間瀏覽器
DateInterval
- DateInterval 表示一段長度的時間,在 DateTime 類的 add() 或 sub() 方法中,能夠傳入一我的 DateInterval 實例,來修改時間
new DateInterval('P2W2DT5H'),實例化須要傳入一個字符串,這個字符串第一個字符是"P",第二個字符表示數量,第三個字符表示單位,合法的單位有:Y(年),M(月),D(天),W(周),H(小時),M(分鐘),S(秒)。日期和時間之間使用「T」分隔。好比 「P2W2DT5H」 表示 2周2天5小時安全
DateTimeZone
- 表示時區,new DateTimeZone('PRC')
- 用途:做爲 new DateTime() 的第二個參數。若是不指定,則使用默認的時區設置(上面提到)
- setTimezone() 能夠用來修改 DateTime() 的時區
在數據庫和代碼中使用UTC來處理時間很方便,只有當顯示給用戶看時,再轉換爲對應的時區。
DatePeriod
- 用於遍歷時間(以給定的間隔),用途:日曆中重複的事件
- new DatePeriod($datetime, $dateinterval, $number)
DatePeriod 是一個迭代器,每次迭代輸出一個 DateTime 對象
- 推薦使用:nesbot/carbon 庫來處理時間
數據庫
使用PDO來鏈接數據庫,針對不一樣的底層數據庫,提供了統一的訪問方式。但缺點在於不一樣的數據庫有本身的方言,這是PDO所不能支持的。建議是寫標準的SQL。
數據庫鏈接和DSN
- new PDO($dsn, $username, $password),會拋出 PDOException
- DSN 示例:"mysql:host=127.0.0.1;dbname=books;port=3306;charset=utf8",其中 mysql 是驅動名錶示 MySQL 數據庫驅動
- 安全:(1)不要直接在代碼中寫用戶和密碼,應當在web目錄以外增長一個配置文件,經過配置獲取(2)不要把用戶和密碼加到版本控制系統中
預處理語句
- 一般咱們使用請求參數來構造SQL語句,這樣很危險,幸而 PDO 使用預處理語句和參數綁定幫咱們處理了參數的過濾。
- 預處理語句就是 PDOStatement 實例,可是咱們不多直接實例化它,而是經過 PDO 實例的 prepare() 方法來獲取。這個方法第一個參數爲一個SQL字符串
- 命名佔位符:$sql = "SELECT id FROM users WHERE email = :email";
- 綁定參數:$statement->bindValue(':email', $email),預處理語句會自動過濾 email 參數,從而防止 SQL 注入。
查詢結果
- 調用 PDOStatement::execute() 執行語句查詢。
- 調用 PDOStetement::fetch(),fetchAll(),fetchColumn(),fetchObject()來獲取結果集
- fetch() 方法返回結果集中的下一行,能夠用它來遍歷比較大的結果集。
- fetch() 和 fetchAll() 接受一個常量來設置獲取結果集的形式,有如下:PDO::FETCH_ASSOC, PDO::FETCH_NUM, PDO::FETCH_BOTH, PDO::FETCH_OBJ
- fetchColumn() 獲取一行,能夠指定一個參數來獲取某列
事務
- 添加事務很簡單,在執行查詢以前,調用 PDO::beginTransaction(),在執行查詢結束後 調用 PDO::commit() 便可。
多字節字符串
多字節字符是指ASCII範圍以外的字符,PHP默認提供的字符串函數只支持8位的ASCII字符,若是用來處理Unicode字符就會產生錯誤,爲此,能夠使用 mbstring 擴展。大部分的PHP字符串處理函數都提供了對應的 mb_* 版本。
字符編碼
- 使用 UTF-8,全部現代瀏覽器都支持
mbstring 還能夠轉換字符編碼:mb_detect_encoding(),mb_convert_encoding()
輸出UTF-8數據
- 在 php.ini 中:default_charset = "UTF-8",這個設置會被許多PHP函數使用以及做爲PHP默認輸出編碼
推薦HTML代碼中增長:<meta charset="UTF-8"/>
流
- 流是現代PHP中最神奇的、也是使用得最少的一個的功能。
- 流是什麼?流是數據在起點和終點之間的傳輸。也就是提及點和終點,多是一個文件、也多是一個命令行進程,一個網絡鏈接,或者一個ZIP壓縮包,臨時內存,標準輸入輸出,或者其餘資源。
流提供了許多PHP IO函數的底層實現,好比:file_get_contents(),fopen(),fgets(),fwrite()
流包裝器
- 不一樣種類的流式數據須要各自的協議來讀寫數據,這些協議就是流包裝器。
- 標識流數據:
<scheme>://<target>
- HTTP流:http://www.baidu.com
- 文件流:file:///etc/hosts,因爲它是PHP默認流包裝器,因此咱們在使用文件函數時直接輸入路徑就能夠了,於是感覺不到底層其實使用了 file:// 來獲取數據的
- php:// 流:命令行腳本會用到,php://stdin, php://stdout, php://memory, php://tmp
- ZIP或TAR流:直接讀取寫入壓縮文件
FTP或FTPS流:ftp://user:pass@ftp.example.com/foo.txt
流上下文
- 流能夠接受一個上下文參數,來自定義流的行爲。
stream_context_create() 建立上下文參數,返回的流上下文對象,能夠被傳入大多數的文件函數和流函數。
流過濾器
- 以前使用流來打開、讀取、寫入數據,可是PHP流的真正用武之處是在數據傳輸過程當中進行過濾、添加、轉換或刪除操做。好比:打開一個markdown文件流,當讀取到內存中時,自動轉換爲HTML。
- php提供了幾個默認的流過濾器,沒什麼用,應當使用本身自定義的流過濾器。
stream_filter_append($stream, 'filter.name') 添加過濾器到流中
建立自定義流過濾器
建立一個繼承自 php_user_filer 的類,實現 filter(), onCreate(), onClose() 方法,而後使用 stream_filter_register() 註冊該過濾器。
錯誤和異常
PS - 我的博客連接 《modern-php》-閱讀筆記-最佳實踐