Jump to content


  • Content count

  • Joined

  • Last visited

About MiCaDev

  • Rank
    Bronze Member
  • Birthday 12/28/1993
  1. [quote name='Game Master']Please - look into Ruby. I see you posting decent content, however this would be able to be performed in one language. Ruby is a very scalable and viable language to use. It's syntax is also nearly spoken, so I highly recommend you to look into it. It can build very modernized websites with quick functionality. Ruby, from up to version 1.8, had it's reputation slandered due to it's latency. However, Ruby 1.9 and up has had major improvements factored into it's speed. Making it a very reliable language able to be used globally.[/QUOTE] Thank you i will certainly look into it, didn't yet had the need of using a framework like that but if it can offer me some great advantages i might learn it. Until now i was able to do pretty much everything in a smart-coded way and I'm also a huge fan of jQuery for my client-side coding as i can do pretty much anything in an easier (and less code) way than javascript itself. (front-end)
  2. Hello Runelocus users, Bin working on a project and my custumor asked if there was a way to display the generated view in a js code string like smartgb.com offers with their free HTML Encrypter, and i said yes of course there is. Even though i told him that people who realy wanted to copycat the content could easily do it. Demo: view-source:[url]http://mafiasource.be/login[/url] make sure to view page source (and not the developer console) to see it's encrypted content | I have only enabled this function on that page for preview purposes. Uncrypted version: view-source:[url]http://mafiasource.be/register[/url] And for us web developers we do know once the page is fully loaded and the JS is executed we will have a readable HTML/CSS mockup in any developer console. Here's my function to encrypt your output HTML: [code] <?PHP function encryptHtml($content) //Post request naar smartgb.com met nodige velden { if(checkdnsrr('http://www.smartgb.com', 'ANY')) { $url = 'http://www.smartgb.com/free_encrypthtml.php?do=crypt'; $fields = array( 'h'=>$content, 's'=>"extended", 'Skicka'=>"Encrypt HTML" ); $postvars=''; $sep=''; foreach($fields as $key=>$value) { $postvars.= $sep.urlencode($key).'='.urlencode($value); $sep='&'; } $ch = curl_init(); curl_setopt($ch,CURLOPT_URL,$url); curl_setopt($ch,CURLOPT_POST,count($fields)); curl_setopt($ch,CURLOPT_POSTFIELDS,$postvars); curl_setopt($ch,CURLOPT_RETURNTRANSFER,true); $result = curl_exec($ch); curl_close($ch); error_reporting(0); $doc = new DOMDocument(); $doc->loadHTML($result); $els = $doc->getElementsByTagName('textarea'); for($i = $els->length; --$i >= 0; ) { $el = $els->item($i); if($el->getAttribute('name') == 'Textruta') { $encryption = $el->nodeValue; } } $doc->saveHTML(); if(isset($encryption)) { return $encryption; } else { return "Please check out the site smartgb, unable to retrieve the encryption. External page probably changed or moved content."; } } else { //Server offline return standard HTML return $content; } } [/code] The above code actualy sends a POST request to their site and retrieves the response, than it loops through the dom document to find the textarea with name: Textruta once found it saves the field value inside a variable that get's printed out at the end of the function. If you want this to work without overload you have to make sure all view content is in one variable (as you don't want to make multiple POST requests to their server). In my application for example i output all of my html with one var: [code] echo $twig->render('/src/Views/admin/cms.twig',$twigVars); [/code] Now when you have included the above function somewhere accessible by your whole app you can easily change the above echo line into: [code] echo encryptHtml($twig->render('/src/Views/admin/cms.twig',$twigVars)); [/code] When done corectly and you view your website's source you would see a html mockup and a large script tag with unreadable code. Perfect for people who want to stop a few copycat's just not all of them. Code not woking? Please check your server's PHP version and update to the most recent stable version. Still having problems? Please ask. Thanks for reading MiCa
  3. Hello Runelocus users, [B]Update: Code is updated, now the method (POST,GET,PUT,DELETE) gets retrieven from the form tag too, so you can now easily use this single code snippet for any form if you remove '#' from #form (it's a matter of picking the right selector) in the first line it will work on all of your forms on your website as long as you accuire all info needed in your form tag.[/B] Here's a simple snippet of how i process ajax forms with only a few lines of jQuery code. For this to work perfectly you will need jquery: - Include jquery in your mockup: [url]https://code.jquery.com/jquery-1.11.3.min.js[/url] A demo is live on [url]http://happyfoodstore.be[/url] (The contact form button footer) Send empty form if you'd like to test it, don't spam. (Just saw that captcha change was broken, i'm not responsible for the site anymore just once worked there.) jQuery has made Ajax a lot easier, instead of calling multiple functions depending on some states jQuery makes it possible to make an Ajax request with just the following code: [code] $("#form").submit(function(e) { var postData = $(this).serializeArray(); //The important part, no need to define any data key to an element, this way we can use our $_POST / $_GET tag the way we have set it up in our html by the input's name attribute. var formURL = $(this).attr("action"); var method = $(this).attr("method"); $.ajax( { url : formURL, //File to process the action type: method, //Post, get, put or delete ? ($_POST, $_GET, $_PUT, $_DELETE defined in the method attribute op the form tag) data : postData, //Will be accessible by it's name in the $_POST or $_GET arr. (Name of your inputs) success:function(data, textStatus, jqXHR) { $("[URL=http://www.runelocus.com/forums/usertag.php?do=list&action=hash&hash=form]#form[/URL] -response").html(data); //The div to place the response in. } }); e.preventDefault(); }); [/code] - This above jQuery code will make our form [URL=http://www.runelocus.com/forums/usertag.php?do=list&action=hash&hash=form]#form[/URL] submittable by Ajax - The action attribute in the form tag (HTML sided) wil determine where the ajax request is sent to (What URI?) - POST Data get's serialized automaticly, and you can use them in your action script like you have always used them before in PHP on a regular form submit ($_POST['key']) - Make sure div [URL=http://www.runelocus.com/forums/usertag.php?do=list&action=hash&hash=form]#form[/URL] -response is present in the HTML mockup (Most likely on top of the form) this will give us a response printed out from our action script. If we place the following code in our action script (The one the form action attribute points to): [code] <?PHP var_dump($_POST); [/code] Than we will have an array with all POST data to be shown to the users upon form submit. Our <div id="form-response"></div> (present in the HTML mockup) wil make sure the users get's to see the "action" response. In our case a whole Array of POST data values will be shown. Up to you to code your own form validation with error messages and on success a success message, those messages will be the printed data in your action script. And ofc, if you have multiple forms on your site you can code it in a way you only need to write it once. Ajax is a great way to handle all of your forms! It's up to you if you wanne use this great code or not. Don't reload your pages upon an action, instead use ajax to reduce server load and improve your UX. This method can be used by all kinds of actions, not only form sided, however this code was an example of how you should handle your forms with ajax. If you read the code than you should know how to use it on a simple button perhaps to load more products for example. NOTE: This wil not work on any browser that doesn't support javascript. (But to make u feel better: [url]http://www.w3counter.com/globalstats.php[/url] nearly no users use the real old browser software anymore which will make coding javascript only more and more convenient.) And ofcource a failsafe for this is you can code your action script for both the ajax response or a whole page reload response. If you realy don't get this, please let me know and i'l make time for you to explain it live. Regards, MiCa
  4. Hello Runelocus users, I have created a little jQuery code yesterday for an expandable menu. A demo is live on: [url]http://optiek.mafiasource.be/[/url] (The categories on the left side with the plus icon MORE EXPANDABLES ARE POSSIBLE) Thought for sharing this as some people may find it interesting the basic HTML mockup wil look something like this: [code] <ul class="menu-expandable"> <li><a href="#">Non-expandable</a></li> <li class="expandable"> <a href="javascript: void(0)" class="cross-small"></a> <a href="#url">Expandable</a> <ul class="list"> <li><a href="#url">Menu-item</a></li> </ul> </li> </ul> [/code] Mockup looks like a normal list element with children, The cross-small class bind to an <a> element is the class we are going to use in our jQuery code to expand the expandable ul element. (Clicking the cross or minus icon) And pretty O-T my actual expandable-menu mockup: (In all of my applications i love to use twig) [code] <ul class="menu-expandable"> {% for name,dropdownOrUrl in langs.MENU_HOMEPAGE %} {% if dropdownOrUrl is not iterable %} <li><a href="{{ dropdownOrUrl }}">{{ name }}</a></li> {% else %} <li class="expandable"> <a href="javascript: void(0)" class="cross-small"></a> <a href="{{ docRoot }}/{{ name|lower|replace({' ' : '-'}) }}">{{ name }}</a> <ul class="list"> {% for route,item in dropdownOrUrl %} <li><a href="{{ docRoot }}{{ route }}">{{ item }}</a></li> {% endfor %} </ul> </li> {% endif %} {% endfor %} </ul> [/code] The code above doesn't really matter but if you know twig, this is an great example to iterate and show your whole menu by using a few lines twig code. Than the jQuery (wich is also javascript, should be in <script></script> tags or included by (.JS) file in your mockup): [code] //Functions - place all yor functions at the top function expandableMenu(obj) { if(!$(obj).hasClass('open')){ $("a.cross-small.open").removeClass('open'); //Closeall REMOVE THIS LINE IF YOU DON'T WANT TO CLOSE ALL EXAPNDED ITEMS BY OPENING ANOTHER (Opened items will stay open) $("ul.expanded").slideUp(500).removeClass('expanded'); //Closeall REMOVE THIS LINE IF YOU DON'T WANT TO CLOSE ALL EXAPNDED ITEMS BY OPENING ANOTHER (Opened items will stay open) $(obj).addClass("open"); //Open this if($(obj).hasClass('open')){$(obj).next().next().slideDown(500).addClass('expanded');} //Open this } else { $(obj).removeClass('open'); //Close this $(obj).next().next().slideUp(500).removeClass('expanded'); //Close this } } //Document ready functions - All functions present after document is loaded and ready for use. $(document).ready(function(){ $("ul.menu-expandable > li.expandable > a.cross-small").click(function(e){ expandableMenu(this); e.preventDefault(): }); }); [/code] You have everything you need to create a expandable menu, now all left for you to do is style your menu (i would love it if you did it yourself). If you somehow forgotten to include jquery before your own scripts this wil not work, so don't forget it. This is my CSS i use for this expandable menu (for people who can't do it theirselves): [code] ul.menu-expandable {display: block; width: 100%; max-width: 100%; padding:0; margin: 0;list-style:none;} ul.menu-expandable > li {display: block; width: 100%; max-width: 100%;margin-left:24px;} ul.menu-expandable > li > a{color:#ADADAD;} ul.menu-expandable > li > a:hover{color:#08C6AF} ul.menu-expandable > li > ul {display: none; width: 100%; max-width: 100%; padding:0; margin: 0;list-style:none;} ul.menu-expandable > li > ul > li {display: block; width: 100%; max-width: 100%;margin-left:16px;} ul.menu-expandable > li > ul > li > a{font-size:14px;color:#ADADAD;} ul.menu-expandable > li > ul > li > a:hover{color:#08C6AF} ul.menu-expandable > li > ul.expanded {display:block;} .cross-small{background-image:url('../images/cross-small.png');display:block;width:18px;height:18px;position:absolute;margin-left: -1.5em;margin-top: 0.05em;transition: all .1s ease-in;-webkit-transition: all .1s ease-in;-moz-transition: all .1s ease-in;-o-transition: all .1s ease-in;} .cross-small.open{background-position: 0 -18px;} [/code] Important is that you should always change the background position of the cross (closed-open), also ul > li > ul should always be hidden unless it's expanded. (When you forget these 2 simple CSS tasks your menu won't work) Forgot to mention my cross-small image is a sprite with a cross and a minus icon, depending on if the class is open or not i change the background-position to show the other icon. Thanks for reading this small tutorial Regards, MiCa
  5. [quote name='Ziek`'][IMG]http://i.imgur.com/Dc7nJiD.png[/IMG][/QUOTE] I see thank you I'll delete the client. Edit: fixed, file is safe now <3
  6. Hello Runelocus users, I was a private web developer for revox they decided to quit and i'm still looking for another great server to play. Thought this whole package of what the site is right now (Not fully functional as you can see, didn't had the time to finish before they quited) would be a good web base for some rsps websites. It is aprox. 80% done in functionality, only things left to code are: - Compare users (highscores) - View based on skill (highscores) - Donation system Make sure you are running a PHP version of 5.5 or higher before using this, if you have errors after uploading (No database errors) it will most likely be your PHP version that is out-dated. If you have an error like sayin 'Could not connect to the database' than you have to edit root/[b]src/Data/config/DBConfig.php[/b] with your database information. (Also make sure to import the database provided in the download) The community board is not included in this download link. The security for the website is also up-to-date when you keep respecting the workflow of the application regarding queries and form submits. You can download the whole package here including the database: [url]http://mafiasource.be/web/public/Revox.zip[/url] And don't hack my database ffs, to lazy to change it anyway. A demo is live on [url]http://revoxrsps.eu/[/url] <-- The package is how the website is. Not fully functional for the case you didn't get it yet. By using this you can keep all current functionality (PHP code) i do however ask to change your cleint side code (HTML / CSS) I ask to change the layout to something unique because it could be that Revox returns and when we do we will keep our current layout. Got a ittle stuck in it's code ? Follow my tutorial: [URL="http://www.runelocus.com/forums/showthread.php?106486-Advanced-web-development-Introduction-to-MVC-the-Model-View-Controller-pattern"]Advanced-web-development-Introduction-to-MVC-the-Model-View-Controller-pattern[/URL] Client removed and re-scanned the zip file (Clean now): [IMG]http://i.imgur.com/oHPX3kZ.png[/IMG] Regards, Michael
  7. [quote name='Arix']Nice tutorial! Hadn't seen MVC in PHP before.[/QUOTE] Well yes it's realy great to use MVC in PHP, it was about time that PHP made OOP possible and with OOP being possible we have the ability to choose to build MVC structures too, For us developers this is a great deal to keep reliable, easily editable and dynamic code inside a smart-coded structure :D
  8. Hello Runelocus users, [B]Edit: Project cancelled by the owner of Amphion, i can still use this layout for another RSPS project, please PM me.[/B] Wanted to show of this new Photoshop layout of a project i'll soon be slicing and basing to an interactive website. I would love some feedback and thought on this design, please think mobile first and comment away! [IMG]http://mafiasource.be/web/public/images/totnu3.png[/IMG] Tip: open Image in new tab to view the large version. Home = active tab || Community = hover over tab There are some quality issues on the text but those will be fixed once this get's converted to valid HTML / CSS. Please let me know what you think and how you would do it better to improve UX. Thanks.
  9. Hello Runelocus users. I once wrote this tutorial which is based on my application itself. You should not proceed if you do not have a basic knowledge of PHP and an expert knowledge of HTML, this tutorial wil learn some advanced stuff that is simply not meant for starters. In this tutorial i will asume you know HTML and CSS perfectly, also PHP should not be new for you, if so this tutorial will fit you perfectly! This tutorial will be much copy paste work, by the end you should have a working structure though i do recommend reading every single word in this tutorial to understand what is going on exactly. As you will see by the end of this tutorial your structure will have many files in opposition of plain PHP writing, but it has a nice structure and a smart application system to process any kind of action. After that it's all about creating the pages by implementing a controller and a view where our controller would interact with the modal(s). This work method will reduce allot of work time spent in the future, because in opposition of working with plain PHP files mixed with html and stuff you will be able to seperate those layers which results in clearer code simply put you will know what to edit and where to edit it. Annother great advantage is that you can re-use any previous written code from your modal or view layers. For example a single login system (PHP sided) on multiple pages, or even a single login form (HTML/CSS) on multiple pages. As you will advance your skills working with this method you will also start to notice allot of other great advantages in many other open-source vendors you can use, even your client sided code will be completly programmable. I now introduce you to this great tutorial which will be editted upon time when some code is out-of-date or anywhat. Enjoy and read much to understand little! [b]What is MVC ?[/b] In terms it speaks of a Modal (class where we handle all of the logic related to a page) a View (template ex:HTML/CSS and some resources) and a Controller (PHP file where we process all of the page's actions and let the modal take care of it.) I'm also going to introduce people to using a one index controller for their web application, and using a templating engine like twig for faster and understandable twig code template rendering. Some would recommend using a class for your controllers (which you can perfectly do by the end of this tutorial 'trust me') but i see the benefit of just including the controller (Plain PHP file no class) inside the front controller and depending on what controller is accesed you can simply write what the controller has to do and let the modal take care of it. Which the modal than may or may not interact with our database classes or even entity classes if we'd like to store data inside an object. Using a class for your controllers is perfectly fine but quite unnecessary because the controller just needs to do one thing. (Interact with it's modal and generate the right view) [size=6][b]The setup:[/b][/size] Before we begin we will need all of the following resources: - An editor for both PHP / HTML and CSS code is recommended (May show you errors before you even debug) i use PHPDesigner which u can find here: [url=http://www.mpsoftware.dk/phpdesigner.php]phpDesigner 8 - PHP Editor & PHP IDE with built-in HTML5, JavaScript, CSS3 editor! | MPSOFTWARE[/url] - Twig library to implent in our source later: [URL]https://github.com/twigphp/Twig/tags[/URL] download the latest version and extract[b] /Twig(version)/lib/Twig[/b] somewhere save for later use. - Autoloading class which is included in doctrine common files: [URL]https://github.com/doctrine/common[/URL] download and extract[b] /common_master/lib/Doctrine[/b] somewhere save. - Last but not least a session manager to stop session hijackers: [url=http://mafiasource.be/downloads/sessionManager.txt]http://mafiasource.be/sessionManager.txt[/url] The one i use feel free to add your own proxies and stuff. [size=6][b]Starting off:[/b][/size] in public_html we will now create our application tree for example: [code]/app - Here we keep our application cache, configurations and standard base templates. /src - Here we can find our source code where our Models, Views and Controllers will be present maybe even Language packets. /vendor - An easy way to keep all of our 3rd library files for example doctrine and facebook api (We will not place Twig in there) /web - The directory where our front-controller is present (index.php) and we have 2 sub directories: one for web/lib and one for web/public. /web/lib - Here we wil upload our extracted Twig map. /web/public - Where every resource that has to be accessible from the web application is present. (ex: ajax, images, css, bootstrap, js) .htaccess robots.txt sitemap.xml[/code] [size=6][b]Step 1:[/b][/size] Creating the .htacces file to link all browser users to the same page on every request. (our front controller in /web/index.php ) This step is very important, we don't want our users the browse every single page itself why don't we create one single page to proccess all of our actions? So mmediatly in public_html you create a new file (if not already exsist) and name it .htaccess write following code: [code] DirectoryIndex /web/index.php Options -Indexes <IfModule mod_rewrite.c> RewriteEngine On #RewriteCond %{REQUEST_URI} /sitemap.xml #These are lines that have to be manualy accessible for SEO optimalisation / Remove comment if not working local #RewriteRule .* - [S=99999999999999] #These are lines that have to be manualy accessible for SEO optimalisation / Remove comment if not working local #RewriteCond %{REQUEST_URI} /robots.txt #These are lines that have to be manualy accessible for SEO optimalisation / Remove comment if not working local #RewriteRule .* - [S=99999999999999] #These are lines that have to be manualy accessible for SEO optimalisation / Remove comment if not working local RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ RewriteRule ^(.*) - [E=BASE:%1] RewriteCond %{ENV:REDIRECT_STATUS} ^$ RewriteRule ^web\index\.php(/(.*)|$) %{ENV:BASE}/$2 [R=301,L] RewriteRule .? %{ENV:BASE}/web/index.php [L] </IfModule> <IfModule !mod_rewrite.c> <IfModule mod_alias.c> RedirectMatch 302 ^/$ /web/index.php/ </IfModule> </IfModule>[/code] This code literaly says when the reqquest uri is /sitemap.xml ignore next 99999999999999 lines of code than it checks if the request uri is /robots.txt, and yes you already guessed it. If none of these matches so any other possible URI, it will direct the user to /web/index.php. [size=6][b]Step 2:[/b][/size] Creating the front controller /web/index.php. In our front-controller we will setup: - strict error reporting for debuging. - We will make classes that can be autoloaded in our whole application source using the autoloading vendors. - Setup the session manager - Setup a routing system for router -> controller. Before we can start writing the index controller we need to make sure we can use the session manager, the autoloading class and the twig engine, to do so please upload the previously saved Doctrine map to [b]/public_html/vendor[/b] you now have: public_html/vendor/Doctrine. Now for the session Manager you can upload it directly to [b]/public_html/vendor[/b] make sure to save it as a PHP extension and not a TXT (like i uploaded). At last upload the previously saved Twig map to [b]/public_html/web/lib[/b] Index.php front controller: [code]<?PHP /** * Front controller - all requests GET / POST are processed here * @author Michael Carrein **/ //Error reporting ini_set('display_errors',1); ini_set('display_startup_errors',1); error_reporting(-1); //Use statements use Doctrine\Common\ClassLoader; use app\config\Routing; /** Session manager **/ require_once __DIR__.'/../vendor/sessionManager.php'; SessionManager::sessionStart('Website name', 0, '/', $_SERVER['HTTP_HOST'], false); // Does the same as session_start(); but in a more secure way. **/ /** Routing & controllers **/ require_once __DIR__.'/../app/config/routing.php'; $route = new Routing(); if($route->getController() != FALSE) //If we get a valid controller it will execute following code { define("DOC_ROOT", $_SERVER['DOCUMENT_ROOT']); /** Autoloading with doctrine so we never have to include or require again (Just use statements)**/ require_once DOC_ROOT . '/vendor/Doctrine/Common/ClassLoader.php'; $classLoader = new ClassLoader('src' , DOC_ROOT); $classLoader->register(); /** Twig engine **/ require_once __DIR__.'/lib/Twig/Autoloader.php'; Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem(DOC_ROOT); //Load Twig templates from root $twig = new Twig_Environment($loader, array( 'cache' => FALSE //DOC_ROOT . '/app/cache/TwigCompilation/', //Cache or no cache ? )); $_SESSION['DOC_ROOT'] = DOC_ROOT; /** Get requested controller **/ if(file_exists(__DIR__.'/../src/Controllers/'.$route->getController())) { if($route->getController() != "notfound.php" && $route->getController() != "languageSelect.php") // Pages where we don't save the previous route for redirects (ex. notfound with button -> go back, or language select where we handle the reqest and redirect the user to the same page he was on. If you have allot of these pages, pleasy simplyfy this process) { $route->setPrevRoute(); //Save previous route } include __DIR__.'/../src/Controllers/'.$route->getController(); } }[/code] And again, the user will always be browsing on this page no mather what. This index file is the only file we will be using require or include functions (PHP) because this is our front-controller and our autoloading class will only be triggered once there's an exsisting route. In the rest of the application we can use the use statements to autoload a class instead of require / include every time. (Because when a user reaches another part of the application (Ex. a controller) he requested an exsisting route) Autoloading has less impact on server load especialy on large web application with lots of logic because any PHP file just use's what it needs while it doesn't have to include or require anything or everything physicaly, classes are "autoloaded" this allows us to dynamicaly obtain what we need in parts of our application and nothing more nothing less. Remember: you can only autoload classes and no plain PHP files. Important to notice is that every class that needs to be able to be autoloaded is going to get a namespace. This namespace is the directory the class is in. and don't mis it's \ instead of / for both namespace and use statements to jump directories. And this is however a bunch to remember for autoloading, but after all it's pretty easy to setup while you don't need to mind what it is realy doing for you. If you have read the code you saw some incompleted code which is routing and controllers. (we'll handle that later on this tutorial) Now for this setup to work we need to add one more .htaccess file in our web directory. So this goes in [b]/public_html/web[/b] as .htaccess [code]Options +FollowSymLinks Options -Indexes IndexIgnore */* # Turn on the RewriteEngine RewriteEngine On # Rules RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . index.php [/code] Explenation: We have pointed our public_html .htaccess file to always go to web/index.php but now in our web directory we need to confirm that whatever we do server sided we browse on index.php We have a server side and a client side to our web application, client side is everything that the eye sees, simply the website itself. Server side on the other hand are logic and inputing and retrieving data. [size=6][b]Step 3:[/b][/size] Creating the routing class and seting up the routes and controllers. You might ask yourself what the * are routes? As we don't direct our user to every single page anymore we need some kind of routing system te determine wheter a users is loggin in or reading the news or registering ... Routes are the URI's requested in our browser as we can create every route ourselfs we can create beautifull SEO applications too. Example of a route (bold): [URL]http://v3.mafiasource.be[/URL][b]/game/summary/info[/b] Now before we can setup the routes and controllers we need a routing class i have written quite a good routing class for you already: [code]<?PHP namespace app\config; use src\Data\seoDAO; /** * Routing class **/ class Routing { private $route; private $routeName; private $controller; public $routeMap = array(); public $prevRoute; public function __construct() //If class is requested this function is called immediatly { include __DIR__.'/routes/routes.php'; //Where we define our routes see Step 4 of this tutorial. And yes we use include because an array is not a class and can not be autoloaed. $this->routeMap = $applicationRoutes; //Put our defined routes in the routeMap /** * At the for loop you define from which directory the routes start. * Caution: as we root our web app in public_html/web/ we use $i = 1; **/ $requestURI = explode('/', $_SERVER['REQUEST_URI']); $routes = array(); for($i = 1; $i < count($requestURI); $i++) { $val = $requestURI[$i]; array_push($routes,$val); } $endRoute = ""; foreach($routes AS $value) { $endRoute .= '/'.$value; } $controller = false; //Now check wheter a user requested a route defined in routes.php (Step 4) foreach($this->routeMap AS $key => $value) { if(preg_match('{^'.$value['route'].'$}', $endRoute)) { $controller = $value['controller']; $routeName = $key; } } //Now check if the route exsist depending on what controller you retrieve. if($controller != false) { //Setup page parameters $this->route = $endRoute; $this->controller = $controller; $this->routeName = $routeName; } else { //Generate not found page $this->route = '/notfound'; $this->controller = 'notfound.php'; } } //Get previous route for redirects $route->getPrevRoute(); public function getPrevRoute() { if(isset($_SESSION['PREV_ROUTE'])) { return $_SESSION['PREV_ROUTE']; } else { return $_SESSION['PREV_ROUTE'] = $_SERVER['REQUEST_URI']; } } //Set prev route happens on every request already public function setPrevRoute() { $_SESSION['PREV_ROUTE'] = $_SERVER['REQUEST_URI']; } public function headTo($routeName) { /** * Replaces the header('Location: '); function now you can use $route->headTo("ROUTENAME (see Step 4)"); * **/ foreach($this->routeMap AS $key => $value) { if($key == $routeName) { header("Location: " . $value['route']); exit(0); } } } public function getRouteByRouteName($routeName) { foreach($this->routeMap AS $key => $value) { if($key == $routeName) { return $value['route']; } } } public function getRoute() { return $this->route; } public function getRouteName() { return $this->routeName; } public function getController() { return $this->controller; } } [/code] And as you can see in index.php (front controller) you see this belongs in [b]/public_html/app/config[/b] as: routing.php Now we need to keep in mind that we have aleady setup a routing and if the route doesn't exsist we throw a not found page, so in step 4 we will create the routes and in step 5 we will create our not found page. [size=6][b]Step 4:[/b][/size] Defining the routes in a PHP array file. For SEO optimalisation many search engines state that you have "beautiful" urls, those urls don't contain any special characters like &,? which is common used in form submit. With our own routing we can setup the routes the way we want it i will give some great examples allong the way. This array goes into [b]/public_html/app/config/routes[/b] as routes.php: [code]<?PHP /** * Define all possible routes * * [MENTION=33150]rou[/MENTION]teName = The name you want to give the route for ex. $route->headTo( [MENTION=33150]rou[/MENTION]teName"); * [MENTION=33150]rou[/MENTION]tePath = The requested URI * [MENTION=87372]Controller[/MENTION] = The controller to execute when Route matches. (remember in our index.php front controller we have defined the controller map to be at /public_html/src/Controllers there is where we handle our controllers.) * * A little example with / (root) * Routes with random PHP vals can be found by preg_match(); which routing already does, here we just need to use the regex. (check example 1 and 2 below) **/ $applicationRoutes = array( /** * [MENTION=33150]rou[/MENTION]teName **/ 'home' => array( /** * [MENTION=33150]rou[/MENTION]tePath **/ 'route' => '/', /** * [MENTION=87372]Controller[/MENTION] **/ 'controller' => 'index.php' ), 'index' => array( 'route' => '/index', 'controller' => 'index.php' ), 'not_found' => array( 'route' => '/notfound', 'controller' => 'notfound.php' )//, //Example 1: Working with page numbers //'news_page' //=> //array( // 'route' => '/news/page/[1-9][0-9]*', // 'controller' => 'news.php' //), //Example 2: working with news titels //'news_article' //=> //array( // 'route' => '/news/article/[A-Za-z0-9-]{3,200}', // 'controller' => 'news_article.php' //) ); [/code] Now it's up to you to define all routes needed for your web application and link them with the correct controllers. [size=6][b]Step 5:[/b][/size] Creating the not found page with 2 sub steps. (Now it's actualy all about creating the pages) Gratz you have succesfully finished your setup to start working realy fast and realy productive in the future! [size=5]Sub step 1:[/size] Creating the controller Now once we create the controller we can handle every possible action for that page. Depending on what action you do you might get another page.. This is where the view comes in handy. Our not_found controller which should be in [b]/public_html/src/Controllers[/b] as notfound.php (Like defined in the routes) [code]<?PHP /* * This code are examples of how logic should be processed in the controller using layers which get autoloader by our Doctrine autoloading class using the use statements. use src\Business\UserService; $user = new UserService(); $userProfile = $user->getUserProfile(); $loggedIn = false; if($userProfile) $loggedIn = true; */ //We don't want to render our PHP variables inside the template so we simply convert them to Twig variables (which is actualy a simple array with data) with folowing line of code: $twigVars = array('docRoot' => "http://".$_SERVER['HTTP_HOST']."",'routing' => $route); //Render notfound template and include all variables needed to render the template so for us the $twigVars echo $twig->render('/src/Views/notfound.twig',$twigVars); [/code] Yes, our controller can be as simple as that because we just need to render a template which says that the page was not found. [size=5]Sub step 2:[/size] Creating the not_found view. (The html page the user sees) Now in our view we will be learning nothing more than HTML and a little bit of Twig (for advanced twig options please refer to their website) Simply create [b]notfound.twig[/b] in [b]/public_html/src/Views[/b] with following code: [code]{% extends "/app/Resources/Views/base.twig" %} {% block content %} {# Example of how if else block works in twig {% if loggedIn == true %} {% include "/app/Resources/Views/base_ingame_static_nav.twig" %} {% else %} {% include "/app/Resources/Views/base_outgame_static_nav.twig" %} {% endif %} #} <section id="top" class="notFound"> <div class="not-found-page"> <div class="container"> <div class="row not-found-kol"> <div class="col-md-4"> <img class="img-rounded img-responsive" alt="Company Logo" src="/web/public/images/logo.png"/> </div> <div class="col-md-8"> <!-- <div class="not-found"> <div class='alert alert-warning'> <h4><span class="glyphicon glyphicon-ban-circle"></span>Page doens't exsist!</h4> </div> </div> --> <iframe src="http://notfound-static.fwebservices.be/404/index.html?&key=c3246892335c83e0a507e07c4f824a45" width="100%" height="650" frameborder="0"></iframe> </div> </div> </div> </div> </section> {% endblock content %} {% block footer %}{% endblock footer %} [/code] Note: as you can see my HTML mockup is already styled and has used some bootstrap classes. It's totaly up to you to code your HTML the way you want it. Now the realy IMPORTANT part here is notice the first line of code ? The not found template actualy extends another template, so in simple terms my not_found content actualy gets included in my base HTML mockup. [size=6][b]Step 6:[/b][/size] Creating the base template as required by step 5.2. Now head over to the [b]/public_html/app/Resources/Views[/b] directory (Create if needed DUH!) and create the file: [b]base.twig[/b] Note: The code bellow is code of my web application as i said before HTML and CSS is all up to you. [code]{% spaceless %} <!DOCTYPE html> <html lang="en"> <!-- SEO WORD ENKEL TOEGEPAST OP DE OUTGAME PAGINA'S! --> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" /> <base href="{{ docRoot }}"/> <title>{{ PAGE_TITLE }}</title> <meta property="og:title" content="{{ PAGE_TITLE }}" /> <!-- FB --> <meta property="og:type" content="game" /> <!-- FB --> <meta property="og:image" content="{{ docRoot }}{{ PAGE_IMAGE }}" /> <!-- FB --> <meta property="og:url" content="{{ PAGE_URL }}" /> <!-- FB --> <meta property="og:description" content="{{ PAGE_DESCRIPTION }}" /> <meta property="og:site_name" content="Mafiasource" /> <meta property="DC.title" content="{{ PAGE_TITLE }}" /> <meta property="DC.subject" content="{{ PAGE_SUBJECT }}" /> <meta property="DC.description" content="{{ PAGE_DESCRIPTION }}" /> <meta property="DC.format" content="text/html" /> <meta property="DC.publisher" content="{{ AUTHOR }}" /> <meta property="DC.language" content="nl-BE" /> <meta name="description" content="{{ PAGE_DESCRIPTION }}" /> <meta name="keywords" content="{{ PAGE_KEYWORDS }}" /> <meta name="google-site-verification" content="1pdpzSKdcZBpNYkkzZ0z3Sqxb9FXcZz4eJmolTUHFU8" /> <meta name="geo.region" content="nl-BE" /> <meta name="geo.placename" content="Deerlijk,Belgium" /> <meta name="geo.position" content="50.8683762,3.2712771" /> <meta name="ICBM" content="50.8683762,3.2712771" /> <link rel="publisher" href="https://plus.google.com/u/0/117401061808919535014"/> <link rel="icon" href="{{ docRoot }}/web/public/images/favicon.ico" type="image/x-icon" /> <link rel="shortcut icon" href="{{ docRoot }}/web/public/images/favicon.ico" type="image/x-icon" /> <link rel="apple-touch-icon" href="{{ docRoot }}/web/public/images/favicon.ico" /> <link href="{{ docRoot }}/web/public/bootstrap/css/bootstrap.min.css" rel="stylesheet" /> <link href="{{ docRoot }}/web/public/css/homepage.css" rel="stylesheet" /> <link href='http://fonts.googleapis.com/css?family=Pathway+Gothic+One' rel='stylesheet' type='text/css' /> <!-- Twig stylesheets --> {% block stylesheets %} {% endblock stylesheets %} </head> <body> <!-- Header --> {% block header %} <header id="top" class="header"> <div class="container"> {% block message %}{% endblock message %} </div> </header> {% endblock header %} <!-- /Header --> <!-- Navigation --> {% block navigation %} <aside id="nav"> <nav class="navbar navbar-new" role="navigation"> <div class="container"> </div> </nav> </aside> {% endblock navigation %} <!-- /Navigation --> {% block content %} {% endblock content %} {% block footer %} <!-- Footer --> <footer> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3 text-center"> <em>Copyright © 2014 Mafiasource.be</em> </div> </div> </div> </footer> <!-- /Footer --> {% endblock footer %} <!-- Bootstrap core JavaScript --> <script src="{{ docRoot }}/web/public/js/default/bootstrap.jquery.min.js"></script> <!-- Google Analytics --> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-49957889-1', 'mafiasource.be'); ga('send', 'pageview'); </script> <!-- End Google Analytics --> <!-- Twig javascripts --> {% block javascripts %} {% endblock %} </body> </html> {% endspaceless %} [/code] Now important to know is that in our not found view we extended this above view. But in our base view we will see something like: block content notice that we also used block content in our not_found view but there we inserted the content we needed. not_found view inherits from base view while not_found view inserts content in the base view. Also you see that in our not_found view we used the block footer too, but it's empty. This means the footer will not be visible on the page not_found. However if you do add content in the footer block in your not_found view it wil simply replace the base footer. And this is a great way of templating your HTML / CSS with twig cause you can actualy build HTML programaticly. [code]{% %} Are logic statements ex: if else construction, a loop but can also form a block as explained above. {{ }} Are variables to be printed out (Variables you have defined in the controller with $twigVars(). {# #} Makes comments possible Also make sure to check out Twigs documentation, you wil get a much better understanding of it all. [/code] In the above base.twig code you see i require some twig varables (ex: {{ PAGE_TITLE }} ) to be printed, if you have followed this tutorial from the beginning you would know how to fix it. Note that Twig has everything needed to replace PHP for templating! If you realy get stuck with outputing data you are doing it wrong. Also important is that when you have created the base template it should never be changed again unless you want to change your whole layout. You can simply build your blocks with standard content like a header and a navigation and a footer but all you ever have to change is the content of the page and the SEO tags of the page. That's why i work with the {{ }} print out's in my header tag. Depending on what page i might get another title, description, keywords, image, og,dc tags ... [size=6][b]Final step:[/b][/size] How to handle logic and seting up a database connection, a great view of what you can do. Remember this ? [code]/* use src\Business\UserService; $user = new UserService(); $userProfile = $user->getUserProfile(); $loggedIn = false; if($userProfile) $loggedIn = true; */ [/code] That was an example of a controller interacting with it's modal. Just create the Modal in it's right directory: [b]/public_html/src/Business[/b] as UserService.php Now our controller "Uses" this class. In this class we can handle all our users logic wheter someone is logging in or out, or writing a post or even changing their password. Note: we have not yet written any HTML form to interact with users so don't start dreaming. Now Me Myself and I like to get my business and data seperate. For that i create another folder in src/ named Data. Every business class wil have it's own Data class if the class need's to interact with a database. En example of UserService.php could be: [code]<?PHP namespace src\Business; use src\Data\UserDAO; class UserService { private $data; public function __construct() { $this->data = new UserDAO(); //Get class where data is handled opens connection. } public function __destruct() { $this->data = null; //Close connection on destruct. } public static function errorMessage($msg) { $message = "<div id='alert' class='alert fade in alert-danger'><button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×</button><span class='glyphicon glyphicon-exclamation-sign'></span> ".$msg."</div>"; return $message; } public static function successMessage($msg) { $message = "<div id='alert' class='alert fade in alert-success'><button type='button' class='close' data-dismiss='alert' aria-hidden='true'>×</button><span class='glyphicon glyphicon-ok-circle'></span> ".$msg."</div>"; return $message; } } [/code] As you can see our Business layer for UserService also uses the UserDAO data class. In that class there will be all functions to edit, insert, select,... anything related to our database. Also i have made 2 functions in the UserService already which is showing a error message or success message to the user. For simplicity reasons i have included HTML inside the functions, but note: HTML should never be written except in the view layer. Now for the data class in [b]/public_html/src/Data[/b] as UserDAO.php for example: [code]<?PHP namespace src\Data; use src\Data\config\DBConfig; //User Data class class UserDAO extends DBConfig { private $dbh = ''; public function __construct() { parent::__construct(); $connection = new DBConfig(); $this->dbh = $connection->con; } public function __destruct() { $this->dbh = null; } } [/code] You might think everything is done now but we still have one more class to make which is connecting to our database. After that we can start creating functions in the DAO class with PDO in mind (Better way to handle MySQL) You can look it all up on google. So our DBConfig.php file goes into [b]/public_html/src/Data/config[/b] with following code: [code]<?PHP namespace src\Data\config; use PDO; class DBConfig { protected $dbConstring = "mysql:host=DatabaseHost;dbname=DatabaseName"; protected $dbUser = "DatabaseUser"; protected $dbPass = "DatabasePass"; public $con = null; public $error; public function __construct() { $this->connect(); } public function __destruct() { $this->disConnect(); } public function connect() { //Only connect when connection is null to prevent multiple connections and lag. if($this->con == null) { try { $this->con = new PDO($this->dbConstring,$this->dbUser,$this->dbPass); $this->con->setAttribute(PDO::ERRMODE_SILENT,PDO::ERRMODE_EXCEPTION); } catch(\PDOException $e) { $this->error = $e->getMessage(); die('An error occured while connecting to the database. Please try again later.'); } } } public function disConnect() { $this->con = null; } } [/code] Congratulations you have have a working MVC pattern. I have still not explained how to query though so here's the thing i'm going to check if a username exsist in my database. The following code goes in the UserService class as a function: [code] public function checkUsernameExsists($username) { return $this->data->checkUsernameExsists($username); } [/code] As you can see it returns a function from the data class which does not exsist yet. Up to us to create the function and the query. The next code goes into UserDAO class as a function,[b] It is very important to query anything through this method by using PDO and prepared statements to avoid any sql injection![/b] (Always bind ALL USER INPUT)): [code] public function checkUsernameExsists($username) { $statement = $this->dbh->prepare("SELECT `id` FROM `users` WHERE `username` = :username "); $statement->execute(array(':username' => $username)); //Remember to handle all user input this way to prevent SQL injection! if($statement->fetchColumn() > 0) { return TRUE; } else { return FALSE; } } [/code] And this is how we query in our application. So te get back to our not_found controller we can actualy interact with our modal layer, where our modal layer can interact with the database itself with a seperate class. If we now edit our not_found controller like so: [code]<?PHP use src\Business\UserService; $user = new UserService(); $username = "MiCa"; $bool = $user->checkUsernameExsists($username); //We can't use any PHP variables inside our (Twig) view, so all variabes needed to print data will be included inside a single array: $twigVars = array('docRoot' => "http://".$_SERVER['HTTP_HOST']."",'routing' => $route, 'usernameExsists' => $bool); //Render notfound template and include all variables needed to render the template so for us the $twigVars echo $twig->render('/src/Views/notfound.twig',$twigVars); [/code] The only variables we can now use in our Twig rendered page are: 'docRoot' => "http://".$_SERVER['HTTP_HOST']."",'routing' => $route,'usernmeExsists' => $bool (as listed above) If we echo them in our notfound.twig page like so: [code]{% extends "/app/Resources/Views/base.twig" %} {% block content %} <section id="top" class="notFound"> <div class="not-found-page"> <div class="container"> {{ docRoot }}<br /> {{ routing.getRoute }}<br /> {% if UsernameExsists %} True {% else %} False {% endif %} </div> </div> </section> {% endblock content %} {% block footer %}{% endblock footer %} [/code] Now if we browse to our websiteurl.ex/notfound We will get the right results first line echoes the website url, the second echoes the current route and the last line echoes true or false. However if you output {{ routing }} it would give you an twig error as you cannot convert a class into a string. Also good to know is that {{ var|raw }} can output HTML data too. So for example our success or error message to the user if we print it we use |raw next to our variable. However if we now just browse to websiteurl.ex or websiteurl.ex/index we will get a PHP error including index.php from Controllers as it does not exsist yet. But we did setup a route for it already, that's why it give's us the error. You could now try browse any other possible url you didn't setup yet, it would direct you to not found page. Up to you to code the controller and style the view template (Step 5.1 & Step 5.2). Goodluck! [b]Update 1: Looping with Twig instead of PHP[/b] Another great code for twig is: [code]{% for charType in charTypes %} {% if registerForm.charType == charType.getId %} <option value="{{ charType.getId }}" title="{{ charType.getDescription }}" selected="selected">{{ charType.getName }}</option> {% else %} <option value="{{ charType.getId }}" title="{{ charType.getDescription }}">{{ charType.getName }}</option> {% endif %} {% endfor %} [/code] This is an example of printing an array of data, for example in PHP we would use the for loop and the echo / print function. And yes, this is how we loop in twig so in twig vars: [code]$twigVars['charTypes'] = array(); // And fill it with all data nedded to print on your view side. [/code] As simple as that, i think i have included the most important twig statements now. [b]Update 1.1: Binding any function to a twig filter to use in our view.[/b] Here's a great way of binding any PHP or own made function into a twig filter, the possibilities are endless as long as you always return any value in the function. First of all create a new file in [b]app/config/[/b] with name[b] twig.filters.php[/b] and paste the following code: [code]<?PHP /** Nodige functies toevoegen **/ function isstr($str) { if(!is_numeric($str)) { return TRUE; } else { return FALSE; } } /** Filters initialiseren **/ $twig->addFilter('var_dump', new Twig_Filter_Function('var_dump')); $twig->addFilter('isstr', new Twig_Filter_Function('isstr')); $twig->addFilter('ucfirst', new Twig_Filter_Function('ucfirst')); [/code] Now we have our file that binds our filters but we still have to require the file in our front controller (Initialize twig first, than bind filters.), it should look something like this: [code]... /** Load Twig **/ require_once __DIR__.'/lib/Twig/Autoloader.php'; Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem(DOC_ROOT); //Twig templates kunnen laden vanaf de root applicatie (PHP) $twig = new Twig_Environment($loader, array( 'cache' => FALSE, 'debug' => true, 'autoescape' => false //DOC_ROOT . '/app/cache/TwigCompilation/', //Cache uit tijen DEVELOPMENT MODE )); require_once __DIR__.'/../app/config/twig.filters.php'; ... [/code] These are a small example of how to bind your functions into twig filters, in our view side we can use them like so: [code]{# inside a statement: #} {% if key|isstr %} {# Do something #} {% endif %} {# Or a simple print/echo: #} {{ key|isstr }} [/code] Another great way to expand your view functions and filters, before adding a function please make sure it doesn't already exsist therefore you can visit Twig's official website for any info and documentation: [URL]http://twig.sensiolabs.org/[/URL] [b]Update 2: Starting to work very safe, not just database sided where we made sure any ser input is binded in prepared statements.[/b] Now we also have to make sure we protect ourselves from several other kinds of attacks where mostly the client side is used as a hacking method either by hijacking sessions or manipulating our view contents. Our sessions are already protected from hijacking inside the session manager (again feel free to change any settings inside the session manager) but still our view content needs protection too especialy when working with forms to submit any user input. Also if we would store any user input for exmple to our database we will have to xss escape the user's value first, this way we can prevent View printing manipulation where the attacker can execute anything to his own liking. First of all add this line on top of the front-controller script as a use satetement: [code]use app\config\Security;[/code] And these 2 lines of code just under the session initialisation of your front-conroller: [code]require_once __DIR__.'/../app/config/security.php'; $security = new Security();[/code] And yes, add these 2 functions in the routing class for action messages: [code] public function createActionMessage($msg) { $_SESSION['message'] = $msg; } public function setActionMessage() { $message = ""; if(isset($_SESSION['message'])) $message = $_SESSION['message']; unset($_SESSION['message']); return $message; } [/code] A Security class to initialize in your front-controller and use anywhere in your application. With this class you can prevent CSRF and XSS examples will follow bellow, create it in it's rightfull directory as shown above. [code]<?PHP /** Security class om XSS en CSRF tegen te gaan **/ namespace app\config; class Security { /** * CSRF * */ protected $token; public function __construct() { if(!isset($_SESSION['security_token'])) { $_SESSION['security_token'] = self::createToken(); } $this->token = $_SESSION['security_token']; } private function createToken() { $string = md5(uniqid(rand(), true)); $hash = hash('sha256', $string); return $hash; } public function getToken() { return $this->token; } public function generateNewToken() { $_SESSION['security_token'] = self::createToken(); $this->token = $_SESSION['security_token']; } /* * Use this function on any form submit to check the inputed hidden token (on any form submit) with the user's session token * */ public function checkToken($input) { $validToken = $_SESSION['security_token']; if($validToken === $input) { return TRUE; } else { return FALSE; } } /** * XSS * */ public function xssEscape($input) { $output = htmlspecialchars(strip_tags($input)); return $output; } /** * Captcha use to increment the captcha count on any action. * */ public function setCaptcha($count = false) { if(!isset($_SESSION['captcha_security'])) $_SESSION['captcha_security'] = 0;//Initialiseren if($count) $_SESSION['captcha_security'] += $count; $_SESSION['captcha_security'] += 1; } public function resetCaptcha() { $_SESSION['captcha_security'] = 0; } /* * Checks if the user has to validate a captcha or not * */ public function checkCaptcha() { if(isset($_SESSION['captcha_security']) && $_SESSION['captcha_security'] > 4) //Change the number if the captcha has to be shown after more actions. { return TRUE; } else { return FALSE; } } } [/code] So how do we use this ? In realy any form on your website you would need to protect yourself from these other kind of attacks. So basicaly our view content starting from the form should look something like this: [code]{# ... Any other mockup and maybe ofcource the extending #} <form action="{{ routing.getRouteByRouteName('maffia_home') }}" method="post" id="some-form" class="form-horizontal"> <fieldset> <div class="form-group"> <label class="col-sm-4 control-label" for="name">{{ langs.HOME_USER_INPUT }}</label> <div class="col-sm-8"> <input type="text" placeholder="{{ langs.HOME_USER_INPUT_PLACEHOLDER }}" class="form-control" name="user_input" id="user_input" /> </div> </div> {% if captcha_security == true %} <div class="form-group"> <label class="col-sm-4 control-label" for="captcha">{{ langs.CAPTCHA_CODE_LABEL }}</label> <div class="col-sm-8"> {{ langs.CAPTCHA_CODE|raw }} <br /><br /> <input type="text" placeholder="{{ langs.CAPTCHA_CODE_PLACEHOLDER }}" class="form-control" name="captcha" id="captcha" /> </div> </div> {% endif %} <div class="col-sm-offset-4 col-sm-8"> <input type="hidden" name="security_token" value="{{ security_token }}" /> <button type="submit" name="submit" id="submit" class="btn btn-success">{{ langs.HOME_SUBMIT }}</button> </div> </fieldset> </form> [/code] - As you can see this is a simple example of a form that we have inserted in our view. - Our action tag is our homepage note how simple it is with the routing class to obtain our path for that route and include it in our action tag. So in simple terms, need to change a route ? No problem, change it once in routes.php array an programm your structure smart-coded and not hard-coded so you don't have to change a bunch of files for one simple route. As you need to notice you can really apply a lot of these techniques to make your web application more reliable for future use. - Than we have a user input field that we handle in our controller below. - Also our hidden security token to prevent CSRF attacks, and last our button to submit the action. Now for example in our controller we would have something like this: [code]use src\Business\UserService; $user = new UserService(); $langs = new Lang(); //You would need to create that yourself. & $route also included in twig tags is already initialized in our front-controller remember? no need to re-add it. if(isset($_POST['submit'])) { $userInput = $security->xssEscape($_POST['user_input']); //Make sure the users input is safe, if not make it safe.(If we would store it for our view) if($security->checkToken($_POST['security_token'])) { //No CSRF Attack process inputs and who knows what else, make sure to handle as much logic you can inside your modal layer and maybe eventualy redirect the user to another or the same page. if($user->submitUserAction($userInput)) //You would also need to create that yourself. { $route->createActionMessage($user::succesMessage("No errors, our form is submitted")); //And a action message to be displayed after the user gets headed. $route->headTo("mafia_home"); //As i wil mention below this is important the heading part. (the session PREV_ROUTE wil not be saved on any form submit for security reasons too. There's no way to go to a previous route that submits a form) exit(0)://After heading always exit, exit does not execute any other code in the script: ex twig rendering. (which can slow down the heading process) } else { $route->createActionMessage($user::errorMessage("Oops, form was not submitted due to errors")); //And a action message to be displayed after the user gets headed. $route->headTo("mafia_home"); //As i wil mention below this is important the heading part. (the session PREV_ROUTE wil not be saved on any form submit for security reasons too. There's no way to go to a previous route that submits a form) exit(0)://After heading always exit, exit does not execute any other code in the script: ex twig rendering. (which can slow down the heading process) } } } /** Just always do that when you have a form on that controller, it generates a action message to be shown to the user and gets deactivated automaticly when seen. **/ $message = $route->setActionMessage(); $twigVars = array('langs' => $langs, 'security_token' => $security->getToken(), 'message' => $message, 'routing' => $route); echo $twig->render('/src/Views/index.twig',$twigVars); [/code] And this is our controller, it has some incompleted code view sided to be initialised in the controller as you've guesed the langs variable. Also everything should work fine except for the submitUserAction function that doesn't exsist yet. It is important to head the user to the same or another url after any action either valid or invalid, this is to avoid spam submitting forms. And with the exit tag we make sure the script stops immediatly after heading the user, this to avoid saving the previous route also for security reasons. And of course you can find yourself a way to simplify this process, like handling the action messages and heading also in the modal however you like. NOTE!: guys, this is realy important you should start to notice allot by now, working with this stucture gives you great benefits and less vulnerabilities. If you however forget to apply these security measures your application can be vulnerable for today's web hacking technologies. [size=6][b]Download:[/b][/size] No time but advanced enough ? Download the whole package here: Here is a complete package in zip format starting from the start-off to step 6. (Username search and other final step's and updates not included) I have made this in about 15 minutes following this tutorial till it was a working pattern both localy and online, you can [url=http://mafiasource.be/downloads/Package.zip]download it here[/url]. If the structure is not working on your server you most likely have an out-dated PHP version. Update your PHP version to the most recent and stable version. Thank you for reading this tutorial! Remember that you now have to power to contain your whole code: - If you know whats wrong you now know how to fix it and where to fix it. - No more messy one script editting since it can bug up the rest of your application. - Logic handling with classes and objects. (Java alike) - You can now use the same functions code everywhere you want instead of copy pasting / where eventualy you get bugs too because of editting one and forgetting the other... (Class functions ex: UserService.php) Is there something wrong with this tutorial or do you need help? Please message me. My next tutorial will be using objects instead of plain variables, it will teach you to insert data in an object and retrieve it as an object. It will be based on this tutorial and we wil be making a working user login / register / logout. Regards, MiCa Excuse me for any misspelling.
  10. Looks good, looking forward to see more of your work.
  11. Looks pretty plain, spice it up a bit give it some modern feel.
  12. If you're still looking for a web dev please PM me ;)
  13. You can try to use Google's public DNS, i use it all the time anywhere if i wanne browse freely. I've only had to set this up once on my Laptop and now i can browse every possible blocked URL in my network and even those URLs blocked by my government. (piratebay,kat,...) Source: [url]https://developers.google.com/speed/public-dns/[/url] By using google's DNS your not browsing on your own (auto generated) DNS anymore this is why you can access anything anywhere from now on, it's an easy setup and you only have to change it once for every PC unless all the settings endure a reset every period of time. If you can't change any settings to that machine you're browsing on than i'm afraid this won't help you either.