Jump to content


  • Content Count

  • Joined

  • Last visited

Community Reputation

0 Neutral

About hazel1919

  • Rank
  1. On further analysis it seems the only viable places to use dependency injection is in the Core\Controller (new View) and Core\Model (new Database) as the dependent classes are not related to the instantiated classes?
  2. Hi Jaques, I want to really thank you for taking out the time to look over the code... with regard to security concerns... I have a routing system that works using predefined regular expressions to match routes, it works... what I am concerned about here is the overall architecture of my framework so to make it as clear as possible I have stripped out all of the components that I know work, such as routing. I should have made that clearer from the beginning. Regarding your points. 1 - I have strip out everything except the minimal amount of code to display something, so controllers, methods, they are all hard coded for simplicity. 2 - I have actually implemented twig into the framework before, for now I am just learning the pure PHP method but it's definitely something I will do in the future, thanks! 3 - Good point, thanks. 4 - Great advice, will put into practice. 5 - I stripped out the error handling code for this example, but it basically writes errors to a log file and displays a generic 404 to the user. 6 - This is an interesting point... Re: point six... dependency injection: I am confused as to how I should go about this. The framework works as is, but I would like to expand upon it down the road and don't want my code quality to degrade with each new feature. Your comment prompted me to delve into dependency injection most of yesterday. Here Here is a flowchart of my simplified framework without dependency injection... As I understand it, the main dependencies are... Core\Router depends on Foo\Controller FooController depends on Core\Controller (via the parent::__construct method) Core\Controller depends on Core\View Foo_Model depends on Core\model which depends on Core\Database So I am a bit confused as to how I should use dependency injection here... is depending on parent::__construct like this making the framework too tightly coupled? Thanks for the time you have spent on helping me already.
  3. Hi all, I have just put together a tentative proof of concept MVC framework proposal. After many weeks of slogging through an array of PHP MVC tutorials and courses (some of which I paid for) I have decided to strip back all the frills, bells and whistles to try and put together a core proof of concept that uses best practices. In this simplified example I am trying to test the viability of the framework itself... so there is no routing code or query string management and the controller and action are hard coded. Here is the repository: https://github.com/JethroHazelhurst/psr-4-mvc I like this framework because it: Has clear seperation of concerns Is not cluttered with static functions Is clearly namespaced - thanks to the PSR-4 autoloading Has a clear way of passing data to and from the model - e.g. $this->_view->foo = $this->_model->getBar(); Below is the directory structure: and here is a print_r of my Object structure: Questions I am interested in hearing any feedback on the idea... I can't see any glaring issues at them moment. Some questions in the back of my mind are: Are there any dangers in heavily depending on the parent::__construct() function to call parent classes? In the controller, is passing data from Model to View using $this->_view->foo = $this->_model->getBar(); good practice? Are there any dangers in using Namespaces? I am also interested in reading up on MVC framework best practices so if anyone can recommend some resources I would be very grateful. It seems like there are a million ways to write an MVC framework, I am confused as to which way is best practice. EDIT: Hmm, can't seem to get a list to display here...
  4. Thanks for your kind replies... models needing to be used across the entire application is a good point. Perhaps an improvement to the folder structure is separating the models into one usable folder like this... I will build the framework out and see if it works, I will know if I am repeating any code that I need to make adjustments. This is for my education so it cant hurt! @gizmola, thanks for the link, that is some fantastic documentation and I have been going through the tutorial today... unfortunately there are just too many black boxes which I just don't understand (either why they exist or how to use them), otherwise I would love to jump straight into symfony or laravel and start taking advantage of the genius of the community. That is why I have to learn the basics of MVC/routing/design patterns first. I just cant learn the "how to" without the "why" in the first place. Best regards, Jaques.
  5. Hi everyone, I have been working through various tutorials over the past couple of months and am currently trying understand PHP frameworks. One of the ways I am doing this is by trying to design my own very simple MVC framework from scratch. I am trying to re-factor an application (which I have already built using spaghetti procedural PHP). This application has a front end for teachers and a back-end for the administrators. I would like to separate concerns and have URL's like this http://example.com/{module}/{controller}/{method}/{param-1}/{param-2} Now the MVC framework I have cobbled together up to this point does not handle routing for 'modules' (I apologise if this is not the correct terminology), only the controller/method/params. So I have separated the public_html from the app logic and inside of the /app/ folder I have specified two folders, my default "learn module" and the "admin module" so that the directory tree looks like this: Apparently this design pattern is a "H"MVC? My Solution I am basically making use if the is_dir(); function to check if there is a "module" directory (such as "admin") and then unsetting the first URL array element $url[0] and reindexing the array to 0... then I am changing the controller path according to the URL... the code should be clearer... <?php class App { protected $_module = 'learn'; // default module --> learn protected $_controller = 'home'; // default controller --> home protected $_method = 'index'; // default method --> index protected $_params = []; // default paramatars --> empty array public function __construct() { $url = $this->parseUrl(); // returns the url array // Checks if $url[0] is a module else it is a controller if (!empty($url) && is_dir('../app/' . $url[0])) { $this->_module = $url[0]; // if it is a model then assign it unset($url[0]); if (!empty($url[1]) && file_exists('../app/' . $this->_module . '/controllers/' . $url[1] . '.php')) { $this->_controller = $url[1]; // if $url[1] is also set, it must be a controller unset($url[1]); $url = array_values($url); // reset the array to zero, we are left with {method}{param}{etc..} } // if $url[0] is not a module then it might be a controller... } else if (!empty($url[0]) && file_exists('../app/' . $this->_module . '/controllers/' . $url[0] . '.php')) { $this->controller = $url[0]; // if it is a controller then assign it unset($url[0]); $url = array_values($url); // reset the array to zero } // else if url is empty default {module}{controller}{method} is loaded // default is ../app/learn/home/index.php require_once '../app/' . $this->_module . '/controllers/' . $this->_controller . '.php'; $this->_controller = new $this->_controller; // if there are methods left in the array if (isset($url[0])) { // and the methods are legit if (method_exists($this->_controller, $url[0])) { // sets the method that we will be using $this->_method = $url[0]; unset($url[0]); } // else nothing is set } // if there is anything else left in $url then it is a parameter $this->_params = $url ? array_values($url) : []; // calling everything call_user_func_array([$this->_controller, $this->_method], $this->_params); } public function parseUrl() { // checks if there is a url to work with if (isset($_GET['url'])) { // explodes the url by the '/' and returns an array of url 'elements' return $url = EXPLODE('/', filter_var(rtrim($_GET['url'], '/'), FILTER_SANITIZE_URL)); } } } this so far appears to be working for me, but..... Question I am not sure if this is the preferred solution to this issue. Is calling the is_dir() check for every page request going slow down my app? How would you engineer a solution or have I completely misunderstood the issue? Many thanks in advance for your time and consideration!! Hazel,
  6. Phew! I didn't realise going into this how addictive and fun coding could be... can't believe I have muddled along for so long just using HTML/CSS when there was the wider world of PHP to explore! Before continuing I want to make clear that I would never expect you or this community to do my dirty work, or what a paid developer would do and the help I have gotten thus far has has been more than I expected and very helpful. The key is in the classroom embed code here... // The object to load and instance name. To create a different "session", // just copy the html page and change the instance name. var object = 'new_conference:jethro'; So I need to change the 'var object' in the Javascript from 'jethro' (which is what I named the classroom) to a random string each time a teacher creates a classroom. That random string should be held in a PHP variable which I'll call '$instance'... I think that is what you mean by the following: So I have created an index.php login page with a temporary database. Here is the link on the live site: http://toucan-talk.com/classes The temporary database has the following credentials username: jethro password: password Here is the index.php code with comments by me... <?php session_start(); if ($_POST['username']) { // Temporary database $dbUsname = "jethro"; $dbPaswd = "password"; $uid = "1"; $usname = strip_tags($_POST['username']); $paswd = strip_tags($_POST['password']); if ($usname == $dbUsname && $paswd == $dbPaswd) { // Set session variables $_SESSION['username'] = $usname; $_SESSION['id'] = $uid; // To generate the random string from a word $str = "Hello"; // word to hash $instance = md5($str); // hash stored in variable header('Location: classroom.php?instance='.$instance);// Hash is concatenated onto the login redirect page } else { echo "<p>Oops! That username or password combination is incorrect. Please try again.</p>"; } } ?> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <link rel="stylesheet" type="text/css" href="style.css"> <title>Toucan-Talk Tutor Login</title> </head> <body> <div id="wrapper"> <center> <img style="width: 250px;" alt="" src="http://www.toucan-talk.com/images/logos/footer-logo.png"> </center> <h1>Enter Classroom</h1> <form id="form" action="index.php" method="post" enctype="multipart/form-data"> Username: <input type="text" name="username"/><br> Password: <input type="password" name="password" /><br> <br> <center> <input class="button" type="submit" value="Enter" name="Submit" /> </center> </form> </body> </html> So I have concatenated that md5 hash onto the header page redirect so that I now get a url that looks like this: http://toucan-talk.com/classes/classroom.php?instance=8b1a9953c4611296a827abf8c47804d7 I have made another file called classroom.php which the header redirects to. Inside there I have the classroom embed code. Here is just the PHP inside that file <?php session_start(); // Variable with the md5() hash code $instance = $_GET['instance']; if (isset($_SESSION['id'])) { $uid = $_SESSION['id']; $usname = "Test variables: <br> Username: ".$usname. "<br> Id: ".$uid; } else { echo 'Please login'; die(); } ?> As you can see I have defined the variable '$instance' again as $instance = $_GET['instance']; (I am not quite sure what this does still but it doesn't work without it!) So I know $_GET['instance'] = $instance = 8b1a9953c4611296a827abf8c47804d7 Now I simply replace the Javascript 'var object' with the variable $instance in PHP tags to generate the classroom on the fly on the Groupworlds servers! // The object to load and instance name. To create a different "session", // just copy the html page and change the instance name. var object = 'new_conference:<?php echo $instance ?>'; Now when I look at the classroom sourcecode the instance is the md5() hash! This seems to do the trick and a link generated by a teacher on my site, which looks like this... http://toucan-talk.com/classes/classroom.php?instance=8b1a9953c4611296a827abf8c47804d7 Is the same as that hash instance generated on the groupworld servers... https://www.groupworld.net/mp/parse.cgi?filename=ncjs&inst_id=1639&instance=8b1a9953c4611296a827abf8c47804d7&width=100%&height=100% And in fact both of those links lead to the SAME classroom. Does this seem like a reasonable way to solve this coding problem? I am excited to improve upon this to get something workable. Many thanks for you guys help this far! Jethro.
  7. Great! I wish I could fully express my gratitude Re: how helpful this is... I have drawn a simple pic of how I would like the user flow to work. I don't mind if the student shares his course link, the student agrees to the terms and conditions before receiving his classes so that would be considered a misconduct on the part of the student and would be dealt with... as for running scripts this should be a matter of making the md5 hash more secure? I would of course need to password protect the classroom creation page and also create a database of teachers who can create classes. That way when a teacher logs into the classroom with his credentials a unique URL and classroom instance is generated and the teacher is redirected to that unique URL and classroom instance. He can then share that unique link with his student via email and they can go ahead with the class. The problem I am having is that I need to generate the unique instance on my site using PHP... e.g. http://www.mysite.com/classes/room-1.php?instance=1i2un3lnj12xas But I also need to somehow tell the classroom providers (Groupworld) that I am instantiating a new instance of the classroom. The classroom providers (Groupworld) don't tell me much on their API page so I am a bit stuck: https://www.groupworld.net/api.shtml So how do I get my server talking to their server?
  8. Hi there mac_gyver, thanks for your considered reply... That means I would have to have a database of every student and also a way of managing/adding/removing them. This is too complex at this stage. I would rather have no student accounts, just a teacher account. I just want to create a random URL link when the teacher logs into the room so that only the teacher can share that link with the student... someone suggested using the md5(time()) function to generate a random URL instance so for example... site.com/classes/room_1?instance=wskcub6729sjcd9f0so3 Trouble is I don't know how to implement the function... Do I need to change my index.html to index.php and then add the php to the top?
  9. And just incase it might help.. this is the response I got from the people at groupworld when I asked them about this...
  10. Background I am relatively proficient in HTML/CSS and the Joomla! Content Management System. Until yesterday I am ashamed to say I had tried my best to avoid learning any PHP code. That being said, I am currently going through the introductory course on PHP with Codecademy in the hope that that will shed some light on my next step... What I am trying to do... Integrate an online classroom on our website for our teachers and students to use on a one to one basis (a single teacher to be paired up with a single student). I am using classroom software from a company called Groupworld (here is their API documentation: https://www.groupworld.net/api.shtml). Our Groupworld subscription allows for up to 10 simultaneous users, so for us that would be 5 teachers and 5 students at any one time. Their instructions are to configure the classroom as you want to display it and then go into the source code and simply copy the HTML onto your own hosting server. We have copied the classroom code to five different folders (one classroom per teacher) each under a master folder called classrooms. So the folder structure looks like this... classrooms ----room-1 --------index.html ----room-2 --------index.html ----room-3 --------index.html etc... Here is the classroom sourcecode for each of those pages... <!DOCTYPE html> <html> <head> <title>Groupworld HTML5 Conference Room</title> <link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/bkpfcahabbgcjikdomdcamdlcipolkcf"> <link rel="stylesheet" href="//www.groupworld.net/style.css" type="text/css"> <link rel="stylesheet" type="text/css" href="//www.groupworld.net/js/dialog.css"> <script type="text/javascript" src="//www.groupworld.net/js/aes-enc.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/aes-dec.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/aes-test.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/sha1.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/newbase64.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/dialog.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/tunnel.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/gsm610.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/groupworld.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/deskshare.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/polls.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/jscolor/jscolor.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/new_conference.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/new_whiteboard.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/new_videostrip.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/chat.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/jspdf.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/jspdf.plugin.addimage.min.js"></script> <script type="text/javascript" src="//www.groupworld.net/js/FileSaver.min.js"></script> <script type="text/javascript"> function getCookie(c_name) { var i,x,y,ARRcookies=document.cookie.split(';'); for (i=0;i<ARRcookies.length;i++) { x=ARRcookies[i].substr(0,ARRcookies[i].indexOf('=')); y=ARRcookies[i].substr(ARRcookies[i].indexOf('=')+1); x=x.replace(/^\s+|\\s+$/g,''); if (x==c_name) { return unescape(y); } } } function setCookie(c_name,value,exdays) { var exdate=new Date(); exdate.setDate(exdate.getDate() + exdays); var c_value=escape(value) + ((exdays==null) ? '' : '; expires='+exdate.toUTCString()); document.cookie=c_name + '=' + c_value + ';path=/'; } var agt=navigator.userAgent.toLowerCase(); var is_ipad = (agt.indexOf('ipad') != -1); var is_android = ((agt.indexOf('ventana') != -1) || (agt.indexOf('android') != -1)); var app_url = 'groupworld://www.groupworld.net?instance=room_1&object=new_conference&installation_id=1630'; if (is_ipad || is_android) { var appstore_url = 'http://itunes.apple.com/us/app/groupworld/id474262955?ls=1&mt=8'; if (is_android) { appstore_url = 'https://market.android.com/details?id=com.grouptechnologies.groupworld'; } var has_app = getCookie('has_groupworld_app'); var msg = 'In order to connect to Groupworld you must use'; if (is_android) { msg = 'For the best experience, we recommend that you use'; } if (has_app) { if (confirm(msg+' the Groupworld App. Launch the Groupworld App Now?')) { window.location = app_url; } } else { if (confirm(msg+' the Groupworld App. Install the Groupworld App Now?')) { setCookie('has_groupworld_app', 'true', 20000); window.location = appstore_url; } } } if ('1630' == '') { document.write("inst_id parameter missing. Please check the url."); } if ('1630' == '1049') { window.location = 'https://www.groupworld.net/mp/parse.cgi?filename=compmathtutor_js.html&instance=room_1&width=100%&height=100%&show_room_name=&show_timer=true&inst_id=1630&username=&password='; } function start() { // Optional username and password. If not specified here, a popup dialog // box will appear. var username = ''; var password = ''; // The Groupworld server to connect to. You can optionally specify the // port number (using the format "server:port"). var base = 'www.groupworld.net:9175:1630'; // The object to load and instance name. To create a different "session", // just copy the html page and change the instance name. var object = 'new_conference:room_1'; // Flags: not currently used. var flags = 0; groupworld.startup(username, password, base, object, flags); } </script> <style> /* Bug in Chrome: if you draw on the whiteboard and move off the top, Chrome will select a bunch of stuff which will then be dragged the next time you click on the whiteboard. To fix, we just turn off selection for all elements. */ * { -moz-user-select: none; -khtml-user-select: none; -webkit-user-select: none; -o-user-select: none; } /* Setting webkit-user-select to none screws up inputs on Safari. */ input { -webkit-user-select: auto; } /* For IE we need to disable touch behaviours (pan/zoom) on the canvas elements, so that the events are sent to the application instead. */ canvas { touch-action: none; } body { padding: 0; margin: 0; } p { padding-left: 8px; } </style> </head> <body onLoad="REDIPS.dialog.init(); start();"> <script src="//www.groupworld.net/js/strings.js"></script> <script type="text/javascript"> var start_time; function timer() { if (null == start_time) { return; } var cur_time = new Date(); var time_diff = (cur_time.getTime() - start_time.getTime())/1000; var hours = parseInt(time_diff/3600); var mins = parseInt((time_diff-hours*3600)/60); var secs = parseInt(time_diff - hours*3600 - mins*60); var t = document.getElementById("t"); t.innerHTML = hours+":"+mins+":"+secs; setTimeout("timer();", 1000); } </script> <h1>Time: <span id="t">0:0:0</span><script type="text/javascript">start_time = new Date(); setTimeout("timer();", 1000);</script></h1> <table border=0 cellspacing=0 width="100%" height="100%"> <tr><td> <script type="text/javascript"> // Generate the actual Groupworld object. Parameters: width and height of // object groupworld.htmlgen('100%','100%'); </script> </td></tr> </table> </body> </html> The problem...s As it stands ANYONE off the street can enter ANY of the rooms so long as they have the link to that room. Not good! So as an example... if a teacher is teaching a student in "room-1" and a previous student decides to log-in using the same "room-1" link then we have a problem. We need our classroom url to be uniquely generated each time a "teacher" logs in. Now the url for each classroom is generated as follows: https://www.groupworld.net/mp/parse.cgi?filename=ncjs&show_timer=true&hide_playback=true&hide_help=true&inst_id=1630&instance=room-1&width=100%&height=100% The interesting part is that the &instance=room_1 can be changed to any string and the Groupworld software will then create a new classroom on the fly! The problem now is that I do not want my teachers to have to manually change the &instance="xxxx" and then somehow copy the new url, this will not work. My closest guess as to how we can do this is as follows, apologies if this is as clear as mud, I simply do not know where to begin coding this! ---- When you enter the classroom called room-1... 1 - A popup appears that asks for a username (this is already coded into the system) 2 - If you enter the correct teacher name then... (this is already coded into the system) 2,a - another popup appears to name the class as $className 2,b - else you cant access the class (this is already coded into the system) 3 – In the class name you name the class e.g. "bobs-class" (no breaking spaces allowed) 4 – Now we want the string "bobs-class" to be added to the Instance ID so that the url instance is now 5 – &instance=room-1-bobs-class 6 – Once the class name is entered then another popup appears that says "share this link" from which the teacher can copy the private link to give to the student. ---- I can't think of another way to do this, I was assured by the people at Groupworld that this would be easily done and only require a few lines of code... however I am almost ready to have a nervouse breakdown! Thanks in advance for your kind help (or just reading thus far!), I'm heading back to learn more PHP... Jethro.
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.