Ein kleines, einfaches PHP -MVC -Framework -Skelett, das viele Merkmale zusammenfasst, die mit leistungsstarken Sicherheitsschichten umgeben sind.
MiniPHP ist eine sehr einfache Anwendung, die für kleine Projekte nützlich ist, um das PHP -MVC -Skelett zu verstehen, zu wissen, wie man authentifiziert und autorisiert, Daten verschlüsselt und Sicherheitskonzepte, Desinfektion und Validierung anwendet, AJAX -Anrufe tätigt und mehr.
Es ist weder ein vollständiger Rahmen noch ein sehr einfacher, aber es ist nicht kompliziert. Sie können es einfach in jedem Ihrer Projekte installieren, verstehen und verwenden.
Es ist eingerichtet, die Komplexität der Frameworks zu entfernen. Dinge wie Routing, Authentifizierung, Autorisierung, Verwaltung von Benutzersitzungen und Cookies usw. sind nicht etwas, das ich von Grund auf erfunden habe. Sie sind jedoch eine Aggregation von Konzepten, die bereits in anderen Frameworks implementiert wurden, sondern auf viel einfachere Weise aufgebaut, also können Sie es verstehen und weiterentwickeln.
Wenn Sie eine größere Anwendung erstellen und die meisten in Frameworks verfügbaren Funktionen nutzen müssen, können Sie CakePhp, Laravel und Symphonie sehen.
In beiden Fällen ist es wichtig, das PHP -MVC -Skelett zu verstehen und zu wissen, wie man sich authentifiziert und autorisiert, Sicherheitsprobleme kennenlernen und wie Sie sich gegen Ihre eigene Anwendung mit dem Framework erstellen können.
Die vollständige Dokumentation finden Sie auch hier - erstellt von GitHub Automatic Side Generator.
Hier ist eine Live -Demo erhältlich. Die Live -Demo gilt für die Demo -Anwendung, die in diesem Abschnitt über diesen Rahmen erstellt wurde. Vielen Dank an @everterstraat.
Einige Funktionen, die Migh in der Demo nicht funktionieren.
Installieren Sie über Komponist
composer install
Immer wenn Sie eine Anfrage an die Anwendung stellen, wird sie im öffentlichen Ordner in INDEX.PHP gerichtet. Wenn Sie also eine Anfrage stellen: http://localhost/miniPHP/User/update/412 . Dies wird aufgeteilt und übersetzt in
Tatsächlich spaltet Htaccess alles nach http://localhost/miniPHP und fügt es der URL als QueryString -Argument hinzu. Diese Anfrage wird also konvertiert in: http://localhost/miniPHP?url='User/update/412' .
Dann teilt App -Klasse in splitUrl() die Abfragezeichenfolge $_GET['url'] in Controller, Aktionsmethode und alle übergebenen Argumente an die Aktionsmethode.
In App -Klasse in run() wird ein Objekt aus der Controller -Klasse instanziiert und einen Aufruf zur Handlungsmethode erstellt, wobei Argumente vorhanden sind, falls sie existieren.
Nach dem Intantiates Controller-Objekt App Klasse wird $this->controller->startupProcess() -Methode aufgerufen, die wiederum 3 aufeinanderfolgende Ereignisse/Methoden auslöst:
initialize() : Verwenden Sie es, um Komponenten zu ladenbeforeAction() : Führen Sie Logikaktionen aus, bevor Sie die Aktionsmethode des Controller aufrufentriggerComponents() : Trigger startup () Methode geladener Komponenten Der Konstruktor der Controller -Klasse sollte nicht überschrieben werden. Stattdessen können Sie die Methoden initialize() & beforeAction() in den Erweiterungsklassen überschreiben.
Nach dem Startprozess des Einschränkers wird der Job beendet, und dann wird die angeforderte Aktionsmethode aufgerufen und Argumente werden übergeben (falls vorhanden).
Komponenten sind die Middlewares. Sie bieten eine wiederverwendbare Logik, die als Teil des Controllers verwendet werden soll. Authentifizierung, Autorisierung, Formmanipulationen und Validierung von CSRF -Token werden in Komponenten implementiert.
Es ist besser, diese Logikstücke aus der Controller -Klasse herauszuziehen und alle verschiedenen Aufgaben und Validierungen in diesen Komponenten zu halten.
Jede Komponente erbt aus der Basis/Superklasse, die als Component bezeichnet wird. Jeder hat eine definierte Aufgabe. Es gibt zwei Komponenten, eine für genannte Authentifizierung und Autorisierung, und die andere als Sicherheit für andere Sicherheitsprobleme.
Sie sind sehr einfach zu bewältigen und sie werden im Controller -Konstruktor bezeichnet.
Hat der Benutzer richtige Anmeldeinformationen?
Die AuthComponent kümmert sich um die Benutzersitzung.
Haben Sie das Recht, X -Aktion zuzugreifen oder X durchzuführen? Die Auth -Komponente kümmert sich um die Autorisierung für jeden Controller. Daher sollte jeder Controller isAuthorized() -Methode implementieren. Sie müssen boolean Wert zurückgeben.
Um beispielsweise zu überprüfen, ob der aktuelle Benutzer Administrator ist oder nicht, würden Sie so etwas tun:
// AdminController
public function isAuthorized (){
$ role = Session:: getUserRole ();
if ( isset ( $ role ) && $ role === " admin " ){
return true ;
}
return false ;
} Wenn Sie es weiter übernehmen und einige Berechtigungsregeln anwenden möchten, gibt es eine leistungsstarke Klasse namens Permission , die für die Definition von Berechtigungsregeln verantwortlich ist. Mit dieser Klasse können Sie definieren, dass "wer eine spezifische Aktionsmethode für den aktuellen Controller durchführen darf".
Um beispielsweise Administratoren zu ermöglichen, Aktionen auf Notizen auszuführen, während normale Benutzer ihre Notizen nur bearbeiten können:
// 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 );
}Jetzt können Sie die Autorisierung basierend auf der Rolle des Benutzers, der Ressource und für jede Aktionsmethode überprüfen.
Das SecurityComponent kümmert sich um verschiedene Sicherheitsaufgaben und Validierung.
Es ist wichtig, die Anforderungsmethoden einzuschränken. Wenn Sie beispielsweise eine Aktionsmethode haben, die Formularwerte akzeptiert, wird nur die Postanforderung akzeptiert. Die gleiche Idee für Ajax, Get, ..etc. Sie können dies innerhalb der Methode beforeAction() tun.
// NotesController
public function beforeAction (){
parent :: beforeAction ();
$ actions = [ ' create ' , ' delete ' ];
$ this -> Security -> requireAjax ( $ actions );
$ this -> Security -> requirePost ( $ actions );
}Auch wenn Sie alle Anfragen über eine gesicherte Verbindung benötigen, können Sie den gesamten Controller oder spezifische Aktionen konfigurieren, um alle Anforderungen an HTTPS anstelle von HTTP umzuleiten.
// NotesController
public function beforeAction (){
parent :: beforeAction ();
$ actions = [ ' create ' , ' delete ' ]; // specific action methods
$ actions = [ ' * ' ]; // all action methods
$ this -> Security -> requireSecure ( $ actions );
}Es überprüft und bestätigt, ob die Anfrage aus derselben Domain stammt. Obwohl sie gefälscht werden können, ist es gut, sie als Teil unserer Sicherheitsschichten zu behalten.
Validieren Sie ein eingereichtes Formular, das von der Postanfrage stammt. Die Gefahr dieser Methode besteht darin, dass Sie die erwarteten Formularfelder oder Daten definieren müssen, die mit der Postanforderung gesendet werden.
Standardmäßig wird das Framework bei der Erstellung von Postanfragen nach Formularen überprüft, und es wird sichergestellt, dass das CSRF -Token mit den Formularfeldern übergeben wird. In dieser Situation wird es als Sicherheits -Thread angesehen, wenn Sie das CSRF -Token nicht bestanden haben.
// 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 -Token sind wichtig, um die eingereichten Formulare zu validieren und sicherzustellen, dass sie nicht gefälscht sind. Ein Hacker kann den Benutzer dazu bringen, eine Anfrage an eine Website zu stellen oder auf einen Link zu klicken, usw.
Sie sind für eine bestimmte Dauer (> = 1 Tag) gültig, dann wird sie in der Sitzung des Benutzers regeneriert und gespeichert.
Die CSRF -Validierung ist standardmäßig deaktiviert. Wenn Sie das CSRF -Token validieren möchten, weisen Sie validateCsrfToken zu true wie im folgenden Beispiel gezeigt. Die CSRF -Validierung wird erzwungen, wenn die Anforderung nach dem Postantrag und die Manipulation des Formulars aktiviert ist.
Jetzt müssen Sie das CSRF -Token auf alle Anfragen nicht manuell überprüfen. Die Sicherheitskomponente überprüft Token in der Anforderung im Vergleich zu dem in der Sitzung gespeicherten Token.
// 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 -Token werden pro Sitzung generiert. Sie können entweder ein verstecktes Formularfeld oder in der URL als Abfrageparameter hinzufügen.
Bilden
<input type="hidden" name="csrf_token" value="<?= Session::generateCsrfToken(); ?>" />
URL
<a href="<?= PUBLIC_ROOT . "?csrf_token=" . urlencode(Session::generateCsrfToken()); ?>">Link</a>
JavaScript
Sie können das CSRF -Token auch einer JavaScript -Variablen zuweisen.
<script>config = <?= json_encode(Session::generateCsrfToken()); ?>;</script>
index.php umgeleitet. Manchmal müssen Sie eine Kontrolle über diese Komponenten haben, z. B. wenn Sie einen Controller ohne Authentifizierung oder Autorisierung haben möchten oder eine Sicherheitskomponente aktiviert ist. Dies kann durch Override initialize() -Methode in Ihrer Controller -Klasse erfolgen und nur die erforderlichen Komponenten laden.
Beispiel 1 : Laden Sie keine Komponente, keine Authentifizierung oder Autorisierung oder Sicherheitsvalidierungen.
public function initialize (){
$ this -> loadComponents ([]);
}Beispiel 2 : Sicherheit und Auth -Komponente laden, authentifizieren und autorisieren Sie sich jedoch nicht für den Fall, dass Sie die Auth -Komponente innerhalb der Aktionsmethoden verwenden möchten. Logincontroller ist ein Beispiel, wie Sie auf eine Seite zugreifen können, ohne dass ein angemeldeter Benutzer erforderlich ist .
public function initialize (){
$ this -> loadComponents ([
' Auth ' ,
' Security '
]);
}Beispiel 3 : Sicherheit laden und authentifizieren und Benutzer authentifizieren und für den aktuellen Controller autorisieren. Dies ist das Standardverhalten in der Kern-/Controller -Klasse
public function initialize (){
$ this -> loadComponents ([
' Auth ' => [
' authenticate ' => [ ' User ' ],
' authorize ' => [ ' Controller ' ]
],
' Security '
]);
}In der Aktionsmethode können Sie einen Aufruf zum Modell tätigen, um einige Daten zu erhalten, und/oder Seiten im Ordner "Views" rendern
// 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 ));
}In MVC repräsentiert das Modell die Informationen (die Daten) und die Geschäftsregeln. Die Ansicht enthält Elemente der Benutzeroberfläche wie Text, Formulareingänge. und der Controller verwaltet die Kommunikation zwischen dem Modell und der Ansicht. Quelle
Alle Vorgänge wie Erstellen, Löschen, Update und Validierung werden in Modellklassen implementiert.
// 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 " );
}
}In Notes -Modell
// 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 ;
}Mit dem Framework würden Sie sich wahrscheinlich anmelden, registrieren und abmelden. Diese Aktionen sind in App/Models/Login & App/Controller/LoginController implementiert. In den meisten Situationen müssen Sie nichts ändern, was mit Anmeldeaktionen zu tun hat, sondern nur das Verhalten des Frameworks verstehen.
Beachten Sie, wenn Sie keine SSL haben, möchten Sie Daten besser auf der Client -Seite manuell verschlüsseln, wenn ja, dies und auch dies.
Immer wenn der Benutzer registriert, wird eine E -Mail mit einer mit verschlüsselten Benutzer -ID verketteten Token gesendet. Dieses Token wird nach 24 Stunden abgelaufen. Es ist viel besser, diese Token abzulaufen und die registrierte E-Mail wiederzuverwenden, wenn sie abgelaufen sind.
Passwörter werden mit den neuesten Algorithmen in PHP v5.5 gehasht
$ hashedPassword = password_hash ( $ password , PASSWORD_DEFAULT , array ( ' cost ' => Config:: get ( ' HASH_COST_FACTOR ' )));Wenn der Benutzer sein Passwort vergessen hat, kann er es wiederherstellen. Die gleiche Idee von abgelaufenen Token geht hierher.
Zusätzlich blockieren Sie den Benutzer für eine bestimmte Dauer (> = 10 Minuten), wenn er die Anzahl der vergessenen Passwörter während einer bestimmten Dauer (> = 10 Minuten) überschritt.
Drossende Brute-Force-Angriffe sind, wenn ein Hacker alle möglichen Eingabekombinationen versucht, bis er das richtige Passwort findet.
Lösung:
Captchas verhindern automatisierte Anmeldungen besonders effektiv. Verwenden Sie Captcha, eine großartige PHP -Captcha -Bibliothek.
Das Blockieren von IP -Adressen ist die letzte Lösung, über die man nachdenken kann. Die IP -Adresse wird blockiert, wenn sich dieselbe IP nicht mehrmals mit verschiedenen Anmeldeinformationen anmelden konnte (> = 10).
PHP -Datenobjekte (PDO) werden zur Vorbereitung und Ausführung von Datenbankabfragen verwendet. In der Database gibt es verschiedene Methoden, die die Komplexität verborgen und das Datenbankobjekt instanziieren, vorbereiten, binden und in wenigen Zeilen ausführen.
SELECT, INSERT, UPDATE, DELETE sind für Benutzer ausreichendAdmin erwähnt.utf8mb4 auf Datenbankebene verwenden.utf8 Charset speichert nur UTF-8-codierte Symbole, die aus ein bis drei Bytes bestehen. Aber es kann nicht für Symbole mit vier Bytes.utf8 . Wenn Sie jedoch auf utf8mb4 upgraden möchten, folgen Sie folgenden Links:utf8mb4 zu ändern Encryption ist für die Verschlüsselung und Entschlüsselung von Daten verantwortlich. Die Verschlüsselung wird auf Dinge wie Cookies, Benutzer -ID, Post -ID, ..ETC angewendet. Verschlüsselte Saiten sind authentifiziert und sie sind jedes Mal unterschiedlich, wenn Sie verschlüsseln.
Die Validierung ist eine kleine Bibliothek zur Validierung von Benutzereingaben. Alle Validierungsregeln befinden sich innerhalb der 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 ist für den Umgang mit allen Ausnahmen und Fehlern verantwortlich. Es wird Logger verwendet, um Fehler zu protokollieren. Die Fehlerberichterstattung wird standardmäßig deaktiviert, da jeder Fehler in App/logs/log.txt protokolliert und gespeichert wird.
Wenn ein aufgetretener Fehler oder eine Ausnahme ausgelöst wurde, zeigt die Anwendung einen internen Fehler des Systems an (500).
Ein Ort, an dem Sie alles protokollieren und in App/log/log.txt speichern können. Sie können Fehler, Fehler, Ausnahmen oder andere böswillige Handlungen oder Angriffe schreiben.
Logger:: log ( " COOKIE " , self :: $ userId . " is trying to login using invalid cookie " , __FILE__ , __LINE__ ); E -Mails werden mit Phpmailer über SMTP gesendet, eine andere Bibliothek zum Senden von E -Mails. Sie sollten keine mail() -Funktion von PHP verwenden.
In App/Konfiguration gibt es zwei Dateien, eine namens config.php für Hauptanwendungskonfigurationen, und eine für JavaScript namens JavaScript.php . Die JavaScript -Konfigurationen werden dann einer JavaScript -Variablen in Ihrer Fußzeile zugeordnet.
Um Anfragen zu senden und eine Antwort zu erhalten, können Sie dazu auf AJAX -Anrufe angewiesen werden. Dieser Framework hängt stark von AJAX -Anfragen ab, um Aktionen auszuführen, aber Sie können immer noch dasselbe für normale Anfragen mit nur kleinen Verbesserungen tun.
Das Konfigurationsobjekt wird Schlüsselwertpaaren in Fußzeile zugewiesen.php. Diese Schlüsselwertpaare können mit Config::setJsConfig('key', "value"); , die dann dem Konfigurationsobjekt zugewiesen werden.
AJAX Ein Namespace mit zwei Hauptfunktionen zum Senden von AJAX -Anforderungen. Eine für normale Ajax -Anrufe und eine für das Hochladen von Dateien.
Helfer Ein Namespace mit einer Vielzahl von Funktionen zeigt Fehler an, serialisieren, leiten, codehtml usw.
App Ein Namespace, mit dem die gesamten JavaScript -Ereignisse für die aktuelle Seite gestört werden
Ereignisse Ein Namespace, mit dem alle Ereignisse deklariert werden können, die möglicherweise auftreten, z. B. wenn der Benutzer auf einen Link klickt, um zu erstellen, zu löschen oder zu aktualisieren.
Um anzuzeigen, wie das Framework in einer realen Situation verwendet wird, verfügt das Framework mit Implementierung für Funktionen wie Verwaltung des Benutzerprofils, Dashboard, News-Feed, Upload- und Download-Dateien, Beiträge und Kommentare, Pagination, Administrator, Systemsicherungen, Benachrichtigungen, Benachrichtigungen, Berichtsfehler usw.
Schritte:
Bearbeiten Sie die Konfigurationsdatei in App/config/config.php mit Ihren Anmeldeinformationen
Führen Sie SQL -Abfragen in _ Installationsverzeichnis aus
Login
E -Mail -Setup
Sie müssen Ihre SMTP -Kontodaten in App/config/config.php konfigurieren. Wenn Sie jedoch kein SMTP -Konto haben, speichern Sie E -Mails in App/logs/log.txt mit Logger.
Kommentieren Sie dazu in Core/E-Mail $mail->Send() & conpres Logger::log("EMAIL", $mail->Body);
Jeder Benutzer kann seinen Namen, seine E -Mail und sein Passwort ändern. Auch das Bild hochladen (dh ursprünglich zu Standards.png zugewiesen).
Immer wenn der Benutzer um seine E -Mail geändert wird, wird eine Benachrichtigung an die alte E -Mail des Benutzers gesendet.
Die an alte E -Mail gesendete Benachrichtigung gibt dem Benutzer die Möglichkeit, E -Mail -Änderungen zu widerrufen, während die an neue E -Mail gesendete Benachrichtigung um Bestätigung verlangt. Der Benutzer kann sich immer noch mit seiner alten E -Mail anmelden, bis er die Änderung bestätigt.
Dies geschieht in UserController in Methoden updateProfileInfo() , revokeEmail() & updateEmail() . In den meisten Situationen müssen Sie das Verhalten dieser Methoden nicht ändern.
Sie können Dateien hochladen und herunterladen.
file_uploads auf trueupload_max_filesize, max_file_uploads, post_max_size einrichtenStellen Sie sich Newsfeed als Tweets in Twitter vor und in Beiträgen wie beim Eröffnen eines Problems in GitHub.
Sie werden oben in diesem Rahmen implementiert.
Administratoren können Aktionen ausführen, bei denen normale Benutzer dies nicht können. Sie können löschen, bearbeiten, alle Newsfeeds, Posts oder Kommentare erstellen. Außerdem haben sie die Kontrolle über alle Benutzerprofile, erstellen und wiederherstellen Backups.
Nur Administratoren haben Zugriff auf alle registrierten Benutzer. Sie können löschen und ihre Informationen bearbeiten.
In den meisten Situationen müssen Sie Backups für das System erstellen und diese wiederherstellen, wann immer Sie möchten.
Dies geschieht durch die Verwendung von MySQldump, um Backups zu erstellen und wiederherzustellen. Alle Backups werden in App/Backups gespeichert.
Haben Sie die roten Benachrichtigungen auf Facebook oder die Blue auf Twitter gesehen? Die gleiche Idee ist hier. Es wird jedoch stattdessen mit Triggern implementiert. Auslöser sind in _ Installation/Triggers.sql definiert.
Wenn der Benutzer eine neue Newsfeed erstellt, eine Datei hochladen oder hochladen, erhöht dies die Anzahl für alle anderen Benutzer und zeigt eine rote Benachrichtigung in der Navigationsleiste an.
Benutzer können Fehler, Funktionen und Verbesserungen melden. Sobald sie das Formular übermittelt haben, wird eine E -Mail an ADMIN_EMAIL gesendet, die in App/config/config.php definiert sind
Angenommen, Sie möchten eine einfache Todo -Anwendung erstellen. Hier werde ich Schritt für Schritt gehen, um eine Todo -App mit dem Framework mit & ohne Ajax -Anrufen zu erstellen.
(1) Wenn Sie die obigen Installations -Setup -Schritte befolgt haben, sollten Sie kein Problem mit dem Erstellen von ersten Benutzerkonten haben.
(2) Erstellen Sie eine Tabelle mit ID als INT, Inhalts varchar, user_id als Fremdschlüssel für 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) Erstellen Sie Todocontroller
Erstellen Sie eine Datei namens TodoController.php in App/Controllern
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) Notenmodellklasse erstellen namens Todo.php in App/Models
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) Inside Views/
(a) Erstellen Sie header.php & footer.php in Ansichten/Layout/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) Inside Ansichten/ Erstellen Sie den Todo -Ordner mit index.php , der unsere TODO -Liste enthält.
<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 -Code zum Senden von Ajax -Anrufen und zur Bearbeitung von Antworten
// 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 ) ;
}
}
} ) ;
}
}
}Ich habe dieses Skript in meiner Freizeit während meines Studiums geschrieben. Dies ist kostenlos, unbezahlt. Ich sage das, weil ich gesehen habe, wie viele Entwickler gegenüber jeder Software sehr unhöflich handeln und ihr Verhalten wirklich frustrierend ist. Ich weiß nicht warum ?! Jeder neigt dazu, sich zu beschweren und harte Worte zu sagen. Ich akzeptiere das Feedback, aber auf gute und respektvolle Weise.
Es gibt viele andere Skripte online zum Kauf, die dasselbe tun (wenn nicht weniger), und ihre Autoren verdienen gutes Geld daraus, aber ich entscheide mich, es öffentlich zu halten, für alle verfügbar.
Wenn Sie etwas gelernt haben oder ich Ihre Zeit gespeichert habe, unterstützen Sie das Projekt bitte, indem Sie das Wort verbreiten.
Starten Sie durch Erstellen neuer Probleme, Senden von Pull -Anfragen auf Github oder Sie können eine E -Mail unter: [email protected] senden
Unter MIT -Lizenz gebaut.