一個簡單的小型PHP MVC框架骨架,封裝了許多包圍有強大安全層的功能。
MinIPHP是一個非常簡單的應用程序,可用於小型項目,有助於了解PHP MVC骨架,知道如何進行身份驗證和授權,加密數據並應用安全概念,消毒和驗證,進行AJAX調用等等。
這不是一個完整的框架,也不是一個非常基本的框架,但並不復雜。您可以在任何項目中輕鬆安裝,理解和使用它。
縮進了刪除框架的複雜性。我不是從頭開始發明的路由,身份驗證,授權,管理用戶會話和cookie等的東西,但是,它們是在其他框架中已經實現的概念的匯總,但是,以一種簡單的方式構建的概念,因此,您可以理解它,並將其進一步了解。
如果您需要構建更大的應用程序,並利用框架中可用的大多數功能,則可以看到Cakephp,Laravel,Symphony。
無論哪種方式,重要的是要了解PHP MVC骨架,並知道如何進行身份驗證和授權,了解安全問題以及如何使用該框架來擊敗以及如何構建自己的應用程序。
完整的文檔也可以在此處找到 - 由GitHub自動頁面生成器創建。
現場演示可以在這裡使用。實時演示是針對本節本框架之上構建的演示應用程序。感謝@everterstraat。
某些功能Migh在演示中不起作用。
通過作曲家安裝
composer install
每當您向應用程序提出請求時,它都會直接使用index.php公共文件夾。因此,如果提出請求: http://localhost/miniPHP/User/update/412 。這將被拆分並翻譯成
實際上,HTACCESS將所有內容分解為http://localhost/miniPHP ,並將其添加到URL中作為querystring參數。因此,此請求將轉換為: http://localhost/miniPHP?url='User/update/412' 。
然後, App類(在splitUrl()內部,將查詢字符串$_GET['url']分為控制器,操作方法以及對操作方法的任何傳遞的參數。
在App類,Inside run()中,它將從控制器類實例化對象,並進行調用操作方法,如果存在,則通過任何參數。
在App類Intantiating Controller對象之後,它將調用$this->controller->startupProcess()方法,這又將觸發3個連續的事件/方法:
initialize() :使用它加載組件beforeAction() :在調用控制器的操作方法之前執行任何邏輯操作triggerComponents() :加載組件的觸發啟動()方法不應覆蓋Controller類的構造函數,相反,您可以在擴展類中覆蓋initialize() & beforeAction()方法。
在重製的啟動過程完成工作之後,將調用請求的操作方法,並將通過參數(如果有)。
組件是中間的。它們提供可重複使用的邏輯,以用作控制器的一部分。在組件內實現了身份驗證,授權,篡改和驗證CSRF令牌。
最好將這些邏輯從控制器類中刪除,並在這些組件中保留所有各種任務和驗證。
每個組件都從稱為Component的基本/超級類繼承。每個都有一個定義的任務。有兩個組件,一個用於身份驗證和授權的auth ,另一個用於其他安全問題的安全性。
它們非常易於處理,並且將在控制器構造函數內部稱為。
用戶有正確的憑據嗎?
AuthComponent會處理用戶會話。
您有權訪問還是執行X操作? AUTH組件負責每個控制器的授權。因此,每個控制器都應實現isAuthorized()方法。您需要做的是返回boolean值。
因此,例如,為了檢查當前用戶是否是管理員,您將做類似的事情:
// AdminController
public function isAuthorized (){
$ role = Session:: getUserRole ();
if ( isset ( $ role ) && $ role === " admin " ){
return true ;
}
return false ;
}如果您想進一步應用並應用一些權限規則,則有一個強大的類,稱為Permission負責定義權限規則。此類允許您定義“允許誰在當前控制器上執行特定的操作方法”。
因此,例如,為了允許管理員對註釋執行任何操作,而普通用戶只能編輯其註釋:
// NotesController
public function isAuthorized (){
$ action = $ this -> request -> param ( ' action ' );
$ role = Session:: getUserRole ();
$ resource = " notes " ;
// only for admins
// they are allowed to perform all actions on $resource
Permission:: allow ( ' admin ' , $ resource , [ ' * ' ]);
// for normal users, they can edit only if the current user is the owner
Permission:: allow ( ' user ' , $ resource , [ ' edit ' ], ' owner ' );
$ noteId = $ this -> request -> data ( " note_id " );
$ config = [
" user_id " => Session:: getUserId (),
" table " => " notes " ,
" id " => $ noteId
];
// providing the current user's role, $resource, action method, and some configuration data
// Permission class will check based on rules defined above and return boolean value
return Permission:: check ( $ role , $ resource , $ action , $ config );
}現在,您可以根據用戶的角色,資源和每個操作方法檢查授權。
SecurityComponent負責各種安全任務和驗證。
限制請求方法很重要。例如,如果您有一種接受表單值的操作方法,則僅接受發布請求。 Ajax的想法相同,獲取,.. etc。您可以在beforeAction()方法中執行此操作。
// NotesController
public function beforeAction (){
parent :: beforeAction ();
$ actions = [ ' create ' , ' delete ' ];
$ this -> Security -> requireAjax ( $ actions );
$ this -> Security -> requirePost ( $ actions );
}另外,如果您需要通過有安全連接的所有請求,則可以配置整個控制器或特定操作,以將所有請求重定向到HTTPS而不是HTTP。
// NotesController
public function beforeAction (){
parent :: beforeAction ();
$ actions = [ ' create ' , ' delete ' ]; // specific action methods
$ actions = [ ' * ' ]; // all action methods
$ this -> Security -> requireSecure ( $ actions );
}它檢查並驗證請求是否來自同一域。儘管它們可以偽造,但最好將它們作為我們安全層的一部分。
驗證提交的表格來自郵政請求。此方法的陷阱是您需要定義預期的表單字段,或者將隨後請求發送的數據。
默認情況下,框架將在提出發布請求時驗證是否篡改表單,並確保將CSRF令牌與表單字段傳遞。在這種情況下,如果您沒有通過CSRF令牌,它將被視為安全線程。
// NotesController
public function beforeAction (){
parent :: beforeAction ();
$ action = $ this -> request -> param ( ' action ' );
$ actions = [ ' create ' , ' delete ' ];
$ this -> Security -> requireAjax ( $ actions );
$ this -> Security -> requirePost ( $ actions );
switch ( $ action ){
case " create " :
$ this -> Security -> config ( " form " , [ ' fields ' => [ ' note_text ' ]]);
break ;
case " delete " :
// If you want to disable validation for form tampering
// $this->Security->config("validateForm", false);
$ this -> Security -> config ( " form " , [ ' fields ' => [ ' note_id ' ]]);
break ;
}
}CSRF令牌對於驗證提交的表格很重要,並確保它們不會偽造。黑客可以欺騙用戶向網站提出請求,或單擊鏈接,依此類推。
它們在一定持續時間內有效(> = 1天),然後將其再生並存儲在用戶的會話中。
默認情況下禁用CSRF驗證。如果要驗證CSRF代幣,則如下示例所示,為true分配validateCsrfToken 。當請求是發布並啟用表單篡改時,CSRF驗證將被迫。
現在,您無需在每個請求中手動驗證CSRF令牌。安全組件將在請求中驗證令牌與會話中存儲的令牌。
// NotesController
public function beforeAction (){
parent :: beforeAction ();
$ action = $ this -> request -> param ( ' action ' );
$ actions = [ ' index ' ];
$ this -> Security -> requireGet ( $ actions );
switch ( $ action ){
case " index " :
$ this -> Security -> config ( " validateCsrfToken " , true );
break ;
}
}CSRF令牌是每個會話生成的。您可以添加隱藏的表單字段,也可以在URL中作為查詢參數添加。
形式
<input type="hidden" name="csrf_token" value="<?= Session::generateCsrfToken(); ?>" />
URL
<a href="<?= PUBLIC_ROOT . "?csrf_token=" . urlencode(Session::generateCsrfToken()); ?>">Link</a>
JavaScript
您還可以將CSRF令牌分配給JavaScript變量。
<script>config = <?= json_encode(Session::generateCsrfToken()); ?>;</script>
index.php 。有時,您需要對這些組件進行控制,例如當想要在沒有身份驗證或授權的情況下具有控制器或啟用安全組件。這可以通過在控制器類中的Override initialize()方法來完成,並且只需加載所需的組件。
示例1 :不要加載任何組件,沒有身份驗證,授權或安全驗證。
public function initialize (){
$ this -> loadComponents ([]);
}示例2 :加載安全性和auth組件,但不要進行身份驗證和授權,以防萬一要在操作方法中使用auth組件。 LoginController是如何無需登錄的用戶訪問頁面的示例。
public function initialize (){
$ this -> loadComponents ([
' Auth ' ,
' Security '
]);
}示例3 :加載安全性和AUTH組件,並驗證當前控制器的用戶並授權。這是核心/控制器類中的默認行為
public function initialize (){
$ this -> loadComponents ([
' Auth ' => [
' authenticate ' => [ ' User ' ],
' authorize ' => [ ' Controller ' ]
],
' Security '
]);
}在操作方法中,您可以調用模型以獲取一些數據和/或渲染頁面內部瀏覽夾文件夾
// NotesController
public function index (){
// render full page with layout(header and footer)
$ this -> view -> renderWithLayouts (Config:: get ( ' VIEWS_PATH ' ) . " layout/default/ " , Config:: get ( ' VIEWS_PATH ' ) . ' notes/index.php ' );
// render page without layout
$ this -> view -> render (Config:: get ( ' VIEWS_PATH ' ) . ' notes/note.php ' );
// get the rendered page
$ html = $ this -> view -> render (Config:: get ( ' VIEWS_PATH ' ) . ' notes/note.php ' );
// render a json view
$ this -> view -> renderJson ( array ( " data " => $ html ));
}在MVC中,該模型表示信息(數據)和業務規則;該視圖包含用戶界面的元素,例如文本,表單輸入;控制器管理模型和視圖之間的通信。來源
在模型類中實現了所有創建,刪除,更新和驗證的操作。
// NotesController
public function create (){
// get content of note submitted to a form
// then pass the content along with the current user to Note class
$ content = $ this -> request -> data ( " note_text " );
$ note = $ this -> note -> create (Session:: getUserId (), $ content );
if (! $ note ){
$ this -> view -> renderErrors ( $ this -> note -> errors ());
} else {
return $ this -> redirector -> root ( " Notes " );
}
}在註釋模型中
// Notes Model
public function create ( $ userId , $ content ){
// using validation class(see below)
$ validation = new Validation ();
if (! $ validation -> validate ([ ' Content ' => [ $ content , " required|minLen(4)|maxLen(300) " ]])) {
$ this -> errors = $ validation -> errors ();
return false ;
}
// using database class to insert new note
$ database = Database:: openConnection ();
$ query = " INSERT INTO notes (user_id, content) VALUES (:user_id, :content) " ;
$ database -> prepare ( $ query );
$ database -> bindValue ( ' :user_id ' , $ userId );
$ database -> bindValue ( ' :content ' , $ content );
$ database -> execute ();
if ( $ database -> countRows () !== 1 ){
throw new Exception ( " Couldn't create note " );
}
return true ;
}使用框架,您可能會進行登錄,註冊和註銷。這些操作是在App/Model/Login & App/Controllers/LoginController中實現的。在大多數情況下,您無需修改與登錄操作相關的任何內容,只需了解框架的行為即可。
請注意,如果您沒有SSL,則最好希望在客戶端手動加密數據,如果是的話,請閱讀此內容。
每當用戶寄存器時,將與加密用戶ID串聯的令牌發送電子郵件。這個令牌將在24小時後過期。最好將這些代幣到期,並在註冊電子郵件過期時重複使用。
密碼使用PHP v5.5中的最新算法進行哈希。
$ hashedPassword = password_hash ( $ password , PASSWORD_DEFAULT , array ( ' cost ' => Config:: get ( ' HASH_COST_FACTOR ' )));如果用戶忘記了密碼,他可以還原。同樣的代幣的想法也在這裡。
此外,如果用戶在一定持續時間內超過了遺忘的密碼嘗試(5)(> = 10分鐘),則阻止某些持續時間(> = 10分鐘)。
限制蠻力攻擊是黑客嘗試所有可能的輸入組合,直到找到正確的密碼為止。
解決方案:
驗證碼在防止自動登錄方面特別有效。使用CAPTCHA一個很棒的PHP驗證碼庫。
阻止IP地址是最後考慮的解決方案。如果相同的IP使用不同的憑據(> = 10)多次登錄,則IP地址將被阻止。
PHP數據對象(PDO)用於準備和執行數據庫查詢。在Database類中,有多種方法可以隱藏複雜性,並讓您實例化數據庫對象,準備,綁定和執行幾行。
SELECT, INSERT, UPDATE, DELETE足以容納用戶Admin類中提到。utf8mb4 。utf8 Charset僅存儲由一到三個字節組成的UTF-8編碼符號。但是,它不能用於具有四個字節的符號。utf8 。但是,如果您想升級到utf8mb4 ,請遵循以下鏈接:utf8mb4 Encryption類負責數據的加密和解密。加密應用於cookie,用戶ID,發布ID,..ETC。加密的字符串經過身份驗證,每次加密時都不同。
驗證是一個用於驗證用戶輸入的小庫。所有驗證規則都在Validation類中。
$ validation = new Validation ();
// there are default error messages for each rule
// but, you still can define your custom error message
$ validation -> addRuleMessage ( " emailUnique " , " The email you entered is already exists " );
if (! $ validation -> validate ([
" User Name " => [ $ name , " required|alphaNumWithSpaces|minLen(4)|maxLen(30) " ],
" Email " => [ $ email , " required|email|emailUnique|maxLen(50) " ],
' Password ' => [ $ password , " required|equals( " . $ confirmPassword . " )|minLen(6)|password " ],
' Password Confirmation ' => [ $ confirmPassword , ' required ' ]])) {
var_dump ( $ validation -> errors ());
}Handler類負責處理所有例外和錯誤。它將使用Logger來記錄錯誤。默認情況下,錯誤報告將關閉,因為每個錯誤都會被記錄並保存在app/logs/log.txt中。
如果遇到錯誤或異常,該應用程序將顯示系統內部錯誤(500)。
您可以記錄任何內容並將其保存到App/log/log.txt的地方。您可以編寫任何失敗,錯誤,異常或任何其他惡意動作或攻擊。
Logger:: log ( " COOKIE " , self :: $ userId . " is trying to login using invalid cookie " , __FILE__ , __LINE__ );電子郵件是使用phpmailer通過SMTP發送的,SMTP是另一個用於發送電子郵件的庫。您不應使用PHP的mail()函數。
在應用程序/配置中,有兩個文件,一個用於主應用程序配置的config.php ,另一個用於JavaScript,稱為JavaScript.php 。然後,JavaScript配置將被分配給footer.php中的JavaScript變量。
為了發送請求並收到響應,您可以取決於Ajax的電話。該框架在很大程度上取決於AJAX執行操作的請求,但是,您仍然可以使用小調整來為普通請求做同樣的事情。
配置對像被分配給footer.php中的鍵值對。這些鍵值對可以使用Config::setJsConfig('key', "value"); ,然後將其分配給配置對象。
AJAX一個名稱空間,該空間具有兩個用於發送AJAX請求的主要功能。一個用於普通的AJAX調用,另一個用於上傳文件。
助手一個具有多種功能的名稱空間顯示錯誤,序列化,重定向,encodehtml等
應用一個名稱空間,用於使當前頁面的整個JavaScript事件歸化
事件一個用於聲明所有可能發生的事件的名稱空間,例如用戶單擊鏈接以創建,刪除或更新時。
為了展示如何在現實生活中使用該框架,該框架隨附用於管理用戶配置文件管理,儀表板,新聞提要,上傳和下載文件,帖子和評論,分頁,管理面板,管理系統備份,Notificatons,Notificatons,Reports Bugs等功能。
步驟:
在應用程序/config/config.php中編輯配置文件和憑據
在_安裝目錄中執行SQL查詢按順序執行
登入
電子郵件設置
您需要在應用程序/config/config.php中配置SMTP帳戶數據。但是,如果您沒有SMTP帳戶,則使用Logger將電子郵件保存在App/logs/log.txt中。
為此,在核心/電子郵件中,請註釋$mail->Send()和uncomment Logger::log("EMAIL", $mail->Body);
每個用戶都可以更改他的姓名,電子郵件,密碼。另外上傳配置文件圖片(即最初分配給default.png)。
每當用戶要求更改他的電子郵件時,都會將通知發送給用戶的舊電子郵件以及新電子郵件。
發送給舊電子郵件的通知使用戶有機會撤銷電子郵件更改,而發送給新電子郵件的通知要求確認。用戶仍然可以使用他的舊電子郵件登錄,直到他確認更改為止。
這是在UserController中完成的,方法是在Methods updateProfileInfo() , revokeEmail()和updateEmail()中完成。在大多數情況下,您無需修改這些方法的行為。
您可以上傳和下載文件。
file_uploads設置為trueupload_max_filesize, max_file_uploads, post_max_size將新聞提要視為Twitter中的推文,以及在Github打開問題時的帖子中。
它們在此框架的頂部實現。
管理員可以在普通用戶無法執行的情況下執行操作。他們可以刪除,編輯,創建任何新聞源,發布或評論。他們還可以控制所有用戶配置文件,創建和還原備份。
只有管理員才能訪問所有註冊用戶。他們可以刪除,編輯他們的信息。
在大多數情況下,您需要為系統創建備份,並隨時隨地還原它們。
這是通過使用mySqlDump創建和還原備份來完成的。所有備份將存儲在應用程序/備份中。
您是否在Facebook上看到了紅色通知,或者在Twitter上看到了藍色通知?同樣的想法也在這裡。但是,它是使用觸發器實現的。觸發器是在_安裝/Triggers.sql中定義的。
因此,每當用戶創建新的新聞源,發布或上傳文件時,這都會為所有其他用戶增加計數,並將在導航欄中顯示紅色通知。
用戶可以報告錯誤,功能和增強功能。提交表格後,將發送電子郵件至app/config/config.php中定義的ADMIN_EMAIL
假設您想構建一個簡單的待辦器應用程序。在這裡,我將逐步介紹如何使用和沒有AJAX調用的框架創建一個TODO應用程序。
(1)如果您遵循上面的安裝設置步驟,則創建初始用戶帳戶時應該沒有任何問題。
(2)創建一個具有ID users表
CREATE TABLE ` todo ` (
` id ` int ( 11 ) NOT NULL AUTO_INCREMENT,
` user_id ` int ( 11 ) NOT NULL ,
` content ` varchar ( 512 ) NOT NULL ,
PRIMARY KEY ( ` id ` ),
FOREIGN KEY ( ` user_id ` ) REFERENCES ` users ` ( ` id ` ) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8 COLLATE = utf8_general_ci;(3)創建todocontroller
創建一個名為TodoController.php的文件在應用程序/控制器內部
class TodoController extends Controller{
// override this method to perform any logic before calling action method as explained above
public function beforeAction (){
parent :: beforeAction ();
// define the actions in this Controller
$ action = $ this -> request -> param ( ' action ' );
// restrict the request to action methods
// $this->Security->requireAjax(['create', 'delete']);
$ this -> Security -> requirePost ([ ' create ' , ' delete ' ]);
// define the expected form fields for every action if exist
switch ( $ action ){
case " create " :
// you can exclude form fields if you don't care if they were sent with form fields or not
$ this -> Security -> config ( " form " , [ ' fields ' => [ ' content ' ]]);
break ;
case " delete " :
// If you want to disable validation for form tampering
// $this->Security->config("validateForm", false);
$ this -> Security -> config ( " form " , [ ' fields ' => [ ' todo_id ' ]]);
break ;
}
}
public function index (){
$ this -> view -> renderWithLayouts (Config:: get ( ' VIEWS_PATH ' ) . " layout/todo/ " , Config:: get ( ' VIEWS_PATH ' ) . ' todo/index.php ' );
}
public function create (){
$ content = $ this -> request -> data ( " content " );
$ todo = $ this -> todo -> create (Session:: getUserId (), $ content );
if (! $ todo ){
// in case of normal post request
Session:: set ( ' errors ' , $ this -> todo -> errors ());
return $ this -> redirector -> root ( " Todo " );
// in case of ajax
// $this->view->renderErrors($this->todo->errors());
} else {
// in case of normal post request
Session:: set ( ' success ' , " Todo has been created " );
return $ this -> redirector -> root ( " Todo " );
// in case of ajax
// $this->view->renderJson(array("success" => "Todo has been created"));
}
}
public function delete (){
$ todoId = Encryption:: decryptIdWithDash ( $ this -> request -> data ( " todo_id " ));
$ this -> todo -> delete ( $ todoId );
// in case of normal post request
Session:: set ( ' success ' , " Todo has been deleted " );
return $ this -> redirector -> root ( " Todo " );
// in case of ajax
// $this->view->renderJson(array("success" => "Todo has been deleted"));
}
public function isAuthorized (){
$ action = $ this -> request -> param ( ' action ' );
$ role = Session:: getUserRole ();
$ resource = " todo " ;
// only for admins
Permission:: allow ( ' admin ' , $ resource , [ ' * ' ]);
// only for normal users
Permission:: allow ( ' user ' , $ resource , [ ' delete ' ], ' owner ' );
$ todoId = $ this -> request -> data ( " todo_id " );
if (! empty ( $ todoId )){
$ todoId = Encryption:: decryptIdWithDash ( $ todoId );
}
$ config = [
" user_id " => Session:: getUserId (),
" table " => " todo " ,
" id " => $ todoId ];
return Permission:: check ( $ role , $ resource , $ action , $ config );
}
} (4)創建Note Model類,稱為Todo.php在應用程序/模型中
class Todo extends Model{
public function getAll (){
$ database = Database:: openConnection ();
$ query = " SELECT todo.id AS id, users.id AS user_id, users.name AS user_name, todo.content " ;
$ query .= " FROM users, todo " ;
$ query .= " WHERE users.id = todo.user_id " ;
$ database -> prepare ( $ query );
$ database -> execute ();
$ todo = $ database -> fetchAllAssociative ();
return $ todo ;
}
public function create ( $ userId , $ content ){
// using validation class
$ validation = new Validation ();
if (! $ validation -> validate ([ ' Content ' => [ $ content , " required|minLen(4)|maxLen(300) " ]])) {
$ this -> errors = $ validation -> errors ();
return false ;
}
// using database class to insert new todo
$ database = Database:: openConnection ();
$ query = " INSERT INTO todo (user_id, content) VALUES (:user_id, :content) " ;
$ database -> prepare ( $ query );
$ database -> bindValue ( ' :user_id ' , $ userId );
$ database -> bindValue ( ' :content ' , $ content );
$ database -> execute ();
if ( $ database -> countRows () !== 1 ){
throw new Exception ( " Couldn't create todo " );
}
return true ;
}
public function delete ( $ id ){
$ database = Database:: openConnection ();
$ database -> deleteById ( " todo " , $ id );
if ( $ database -> countRows () !== 1 ){
throw new Exception ( " Couldn't delete todo " );
}
}
}(5)內部視圖/
(a)創建header.php & footer.php內部視圖/佈局/todo
<! DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf- 8 ">
<meta http-equiv="X- UA -Compatible" content=" IE =edge">
<meta name="viewport" content="width=device-width, initial-scale= 1 ">
<meta name="description" content="mini PHP ">
<meta name="author" content="mini PHP ">
<title>mini PHP </title>
<!-- Stylesheets -->
<link rel="stylesheet" href=" <?= PUBLIC_ROOT ; ?> css/bootstrap.min.css">
<link rel="stylesheet" href=" <?= PUBLIC_ROOT ; ?> css/sb-admin-2.css">
<link rel="stylesheet" href=" <?= PUBLIC_ROOT ; ?> css/font-awesome.min.css" rel="stylesheet" type="text/css">
<!-- Styles for ToDo Application -->
<style>
.todo_container{
width:80%;
margin: 0 auto;
margin-top: 5%
}
#todo-list li{
list-style-type: none;
border: 1px solid #e7e7e7;
padding: 3px;
margin: 3px;
}
#todo-list li:hover{
background-color: #eee;
}
form button{
float:right;
margin: 3px;
}
form:after{
content: '';
display: block;
clear: both;
}
</style>
</head>
<body> <!-- footer -->
<script src="https: //ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!--<script src=" <?= PUBLIC_ROOT ; ?> js/jquery.min.js"></script>-->
<script src=" <?= PUBLIC_ROOT ; ?> js/bootstrap.min.js"></script>
<script src=" <?= PUBLIC_ROOT ; ?> js/sb-admin-2.js"></script>
<script src=" <?= PUBLIC_ROOT ; ?> js/main.js"></script>
<!-- Assign CSRF Token to JS variable -->
<?php Config:: setJsConfig ( ' csrfToken ' , Session:: generateCsrfToken ()); ?>
<!-- Assign all configration variables -->
<script>config = <?= json_encode (Config:: getJsConfig ()); ?> ;</script>
<!-- Run the application -->
<script>$(document).ready(app.init());</script>
<?php Database:: closeConnection (); ?>
</body>
</html> (b)內部視圖/創建將具有index.php文件夾,其中將包含我們的待辦事項列表。
<div class="todo_container">
<h2> TODO Application</h2>
<!-- in case of normal post request -->
<form action= " <?= PUBLIC_ROOT . " Todo/create " ?> " method="post">
<label>Content <span class="text-danger " >*</span></label>
<textarea name= " content" class ="form-control " required placeholder= " What are you thinking? " ></textarea>
<input type='hidden' name = "csrf_token" value = " <?= Session:: generateCsrfToken (); ?> ">
<button type="submit" name="submit" value="submit" class="btn btn-success">Create</button>
</form>
<!-- in case of ajax request
<form action= "#" id="form-create-todo" method="post">
<label>Content <span class="text-danger">*</span></label>
<textarea name="content" class="form-control" required placeholder="What are you thinking?"></textarea>
<button type="submit" name="submit" value="submit" class="btn btn-success">Create</button>
</form>
-->
<br>
<?php
// display success or error messages in session
if (! empty (Session:: get ( ' success ' ))){
echo $ this -> renderSuccess (Session:: getAndDestroy ( ' success ' ));
} else if (! empty (Session:: get ( ' errors ' ))){
echo $ this -> renderErrors (Session:: getAndDestroy ( ' errors ' ));
}
?>
<br><hr><br>
<ul id="todo-list">
<?php
$ todoData = $ this -> controller -> todo -> getAll ();
foreach ( $ todoData as $ todo ){
?>
<li>
<p> <?= $ this -> autoLinks ( $ this -> encodeHTMLWithBR ( $ todo [ " content " ])); ?> </p>
<!-- in case of normal post request -->
<form action= " <?= PUBLIC_ROOT . " Todo/delete " ?> " method="post">
<input type='hidden' name= "todo_id" value=" <?= " todo- " . Encryption:: encryptId ( $ todo [ " id " ]); ?> ">
<input type='hidden' name = "csrf_token" value = " <?= Session:: generateCsrfToken (); ?> ">
<button type="submit" name="submit" value="submit" class="btn btn-xs btn-danger">Delete</button>
</form>
<!-- in case of ajax request
<form class="form-delete-todo" action= "#" method="post">
<input type='hidden' name= "todo_id" value=" <?= " todo- " . Encryption:: encryptId ( $ todo [ " id " ]); ?> ">
<button type="submit" name="submit" value="submit" class="btn btn-xs btn-danger">Delete</button>
</form>
-->
</li>
<?php } ?>
</ul>
</div>(6)JavaScript代碼發送AJAX呼叫,並處理響應
// first, we need to initialize the todo events whenever the application initalized
// the app.init() is called in footer.php, see views/layout/todo/footer.php
var app = {
init : function ( ) {
events . todo . init ( ) ;
}
} ;
// inside var events = {....} make a new key called "todo"
var events = {
// ....
todo : {
init : function ( ) {
events . todo . create ( ) ;
events . todo . delete ( ) ;
} ,
create : function ( ) {
$ ( "#form-create-todo" ) . submit ( function ( e ) {
e . preventDefault ( ) ;
ajax . send ( "Todo/create" , helpers . serialize ( this ) , createTodoCallBack , "#form-create-todo" ) ;
} ) ;
function createTodoCallBack ( PHPData ) {
if ( helpers . validateData ( PHPData , "#form-create-todo" , "after" , "default" , "success" ) ) {
alert ( PHPData . success + " refresh the page to see the results" ) ;
}
}
} ,
delete : function ( ) {
$ ( "#todo-list form.form-delete-todo" ) . submit ( function ( e ) {
e . preventDefault ( ) ;
if ( ! confirm ( "Are you sure?" ) ) { return ; }
var cur_todo = $ ( this ) . parent ( ) ;
ajax . send ( "Todo/delete" , helpers . serialize ( this ) , deleteTodoCallBack , cur_todo ) ;
function deleteTodoCallBack ( PHPData ) {
if ( helpers . validateData ( PHPData , cur_todo , "after" , "default" , "success" ) ) {
$ ( cur_todo ) . remove ( ) ;
alert ( PHPData . success ) ;
}
}
} ) ;
}
}
}我在學習期間的空閒時間裡寫了這個腳本。這是免費的,無薪的。我之所以這樣說,是因為我看到許多開發人員對任何軟件都很粗魯,而且他們的行為確實令人沮喪。我不知道為什麼? !每個人都傾向於抱怨,並說苛刻的話。我確實接受反饋,但是,以一種良好而尊重的方式。
在線購買許多其他腳本,可以做同樣的事情(如果不是更少),他們的作者從中賺了很多錢,但是,我選擇將其公開,適合所有人。
如果您學到了一些東西,或者我節省了您的時間,請通過傳播這個詞來支持該項目。
通過創建新問題,在github上發送拉動請求來做出貢獻,或者您可以發送電子郵件至:[email protected]
根據MIT許可建造。