
DeX
Members-
Posts
258 -
Joined
-
Last visited
Everything posted by DeX
-
Need a fast way to save a snapshot of MySQL table using PHP
DeX replied to DeX's topic in MySQL Help
Wow, that is genius! I actually laughed when I read it because of how smart that is. Because the system gets the overall price for the quote, it goes to the database 300 times to get the prices for all the different products with 300 individual database calls to the same table. I think it might only make the calls for products with a positive quantity though, now that I think about it. EDIT - These calls are only done when the quote is saved, not on edits. I'm not concerned right now about speed of saving quotes, currently I'm focused on edits. -
Need a fast way to save a snapshot of MySQL table using PHP
DeX replied to DeX's topic in MySQL Help
Yes, that's what I'm doing, it's just 4 columns: - id - quote_id - product_id - price Then I also have to save the sales person's commission rates: - operations commission - sales commission - sales management commission - 4 or 5 other commissions Then I save the rates: - winter build rate (used if building in winter) - remote labour rate (used if building far enough away from head office) And then I save minimums - minimum labour (used if labour is less than the minimum) - minimum materials (used if materials are less than the specified minimum) - minimum truss price (used if total truss price isn't at least the specified minimum) These are all things required for looking back at older quotes and they all come from separate tables and get stored into separate match tables. -
I know of all the ways to dump it to a text file but I want to save a database table into another match table. I have web software which allows users to enter some inputs and save a create a quote for their client. At the time of the quote, all of the building products in the database have an associated price and this pricing can change at any time. When they save the quote, I want to save all 300 products and prices into another table so I can go back later and see what the prices were when that quote was done. I don't want to load a quote from a month ago and have it price based on current pricing, I want it to price using the prices from a month ago. Right now I'm simply selecting all 300 rows and dumping them into a match table with the quote ID. That's causing it to take about 30-50 seconds to save the quote, along with a couple of other tables I'm saving as well. I'd like to make the quote saving much faster, is there a faster way to get this snapshot of the database table when the quote is saved?
-
I've been using Workbench in Ubuntu for years without any problems at all, it hasn't crashed once. Another alternative you can try is Squirrel SQL, I know that also works for Microsoft SQL databases as well. I used it on a previous Microsoft project and it worked great but I still prefer Workbench for non-Microsoft databases.
-
I don't know how to split your quote so I'll answer it in 2 parts here. As per your question in the first part, you're close but it doesn't quite work like that. I'm not updating quantities anywhere, I'm dynamically calculating the quantities each time they're requested. Let's use the following example: - quantityScrews = buildingWidth * 2; - quantity2x4 = quantityScrews / 3; - quantitySoffit = (quantityScrews > 100 ? quantity2x4 * 5 : quantityScrews + 4; So when a change is made in the program, I request the quantity of screws and it gets stored into the overallQuantities array for no other reason but to speed up the subsequent requests. That array isn't a master quantity array, it's just a quicker place to get the quantity instead of having to recalculate it again. So when I request the quantity of 2x4, it'll get quantityScrews from the overallQuantities array which (I assume) is faster than recalculating it again. I could be wrong but it sounds like you think I'm using that array as a quantity storage, then updating the quantities in there as needed, that's not the case. Should I be? The main calculation happening here is getFinalCost() which makes a request to get the total costs of all the individual products which makes a request to get all the quantities of each product. Those quantities are requested from the switch statement every time. On to the second part of your reply, the code you posted. I think you may really be on to something here but I don't quite understand it well enough to implement it. So let's say the sales guy changes the building to be 10 feet wider, the building width is used as a calculation in around 50% of the product quantity calculations so that's going to have a huge effect on the quantities of everything. More lumber, more posts, more metal, trims, insulation, everything. Also, you don't always have simple operators being applied, sometimes you have complicated IF statements like the quantitySoffit calculations above. Will that still work in your example? It looks like what you posted may work so I'd really like to understand it a bit better, please let me know if this is correct: - I would create a set of rules for all 300 products like you did for the 3 you posted above. - Then when the building length is changed, I would call the _calc method? Is that right? - What is the $rule variable I pass into _calc? I really like your top down idea but here are 2 more quantity calculations which I can't quite figure out how to convert to your example: This one is for interiorJTrim, it isn't too bad. There is an IF statement to see if the building is insulated because they're only used on insulated buildings. The $showInsulation variable is used to force an insulated price, I use that to get the price of the building if it were to be insulated, that allows the sales guys to print a cost on the quote for upgrading to an insulated building should the customer change their mind later. I can use that to query an insulated cost of their building by passing that value as true. You'll notice I changed all the product variables to constants but it didn't speed anything up. case (self::interiorJTrim) : $quantity = 0; if ($this->isInsulated() || $showInsulation) { $quantity += $this->getTotalQuantityManDoors($showInsulation, $showPerma) * 2.5 + $this->getTotalQuantityBuildingProduct(self::threeByThreeFixedWindow, $showInsulation, $showPerma) * 1.5 + $this->getTotalQuantityBuildingProduct(self::fourByThreeFixedWindow, $showInsulation, $showPerma) * 1.5 + $this->getTotalQuantityBuildingProduct(self::threeByThreeSlidingWindow, $showInsulation, $showPerma) * 2 + $this->getTotalQuantityBuildingProduct(self::fourByThreeSlidingWindow, $showInsulation, $showPerma) * 2 + $this->getQuantityCustomWindows() * 3 + $this->getTotalOverheadDoorQuantity() * 2 + $this->getTotalHeightBuildingProduct(self::biFoldDoor, $showInsulation, $showPerma) * 2 / 9 + $this->getTotalWidthBuildingProduct(self::biFoldDoor, $showInsulation, $showPerma) / 9 + $this->getTotalQuantityBuildingProduct(self::highLiftCharge, $showInsulation, $showPerma) * 1 + $this->getTotalQuantityBuildingProduct(self::atticHatch, $showInsulation, $showPerma) * 2; } $quantities[] = ceil($quantity); break; Now for the worst one, this is the quantity of wallMetal, it's probably the most complicated quantity calculation in the system: - First get a value based on all the overhead, sliding and bi-fold doors the sales guy added. - Then if it doesn't have exterior wall light, add more to the value. - Then generate a quantity of wall metal by REMOVING the value we just calculated because we need to remove any wall metal which will no longer be in the places of doors and wall light. Obviously those holes in the wall will now be filled with doors and wall light instead of wall metal. We don't want to charge the customer for that wall metal if we're not using it. - Then we calculate another quantity to add to the quantity array. The reason we're separating the quantities is because this quantity group of wall metal will have a different length. It's the same product in the system (wall metal) but when it gets printed out on the product list for the building construction, we need to know how many pieces of wall metal we have for each length. That length is calculated separately in the getLengthBuildingProduct method which is another switch statement. case (self::wallMetal) : $quantity = 0; $value = 0; for ($i = 0; $i < count(explode(",", $this->overheadQuantities, -1)); $i++) if (!$this->hasExteriorWallLight()) // does not have wall light $value += (floor($this->getOverheadDoorWidths($i) / 3) - 2) * $this->getOverheadDoorQuantities($i); for ($i = 0; $i < count(explode(",", $this->slidingQuantities, -1)); $i++) if (!$this->hasExteriorWallLight()) // does not have wall light $value += (floor($this->getSlidingDoorWidths($i) / 3) - 2) * $this->getSlidingDoorQuantities($i); for ($i = 0; $i < count(explode(",", $this->biFoldQuantities, -1)); $i++) if (!$this->hasExteriorWallLight()) // does not have wall light $value += (floor($this->getBiFoldDoorWidths($i) / 3) - 2) * $this->getBiFoldDoorQuantities($i); if (!$this->hasExteriorWallLight()) // if it doesn't have exterior wall light $value += $this->getTotalQuantityBuildingProduct(self::eveAccent, $showInsulation, $showPerma) + $this->getTotalQuantityBuildingProduct(self::gableAccent, $showInsulation, $showPerma); $quantities[] = (ceil($this->getBuildingWidth() / 3) + ceil($this->getBuildingLength() / 3)) * 2 + 1 - floor($this->getLengthExteriorWallLight() / 3) - $value; $quantity = 0; $value = 0; for ($i = 0; $i < count(explode(",", $this->overheadQuantities, -1)); $i++) if ($this->hasExteriorWallLight()) // has wall light $value += (floor($this->getOverheadDoorWidths($i) / 3) - 2) * $this->getOverheadDoorQuantities($i); for ($i = 0; $i < count(explode(",", $this->slidingQuantities, -1)); $i++) if ($this->hasExteriorWallLight()) // has wall light $value += (floor($this->getSlidingDoorWidths($i) / 3) - 2) * $this->getSlidingDoorQuantities($i); for ($i = 0; $i < count(explode(",", $this->biFoldQuantities, -1)); $i++) if ($this->hasExteriorWallLight()) // has wall light $value += (floor($this->getBiFoldDoorWidths($i) / 3) - 2) * $this->getBiFoldDoorQuantities($i); $quantity += $this->getQuantityExteriorWallLight() - $value; $quantityGableAccents = $this->getQuantityBuildingProduct(self::gableAccent, $showInsulation, $showPerma); if ($this->hasExteriorWallLight()) // if it has exterior wall light $quantity -= $this->getTotalQuantityBuildingProduct(self::eveAccent, $showInsulation, $showPerma) + $quantityGableAccents[0]; $quantities[] = $quantity; break;
-
As far as I can understand what you're saying, I may have explained it incorrectly. The quote page has about 60 different inputs for changing things like: - building width - building height - building length - building type (residential, commercial, barn, hayshed....) - insulated or not - how many windows? - how many doors? - what's the roof pitch? The sales guy will sit down with a customer and enter in all that information and right next to the input boxes there is a live quote which displays the actual live price for those options. That price is calculated by running through the quantities of every single available building product (300 of them), getting the unit price and finally getting a final cost for that job, down to the penny. It's so accurate that I know that building will require 14,394 screws to complete, not 1 more, not 1 fewer. So I don't think I can do it your way (please tell me if I'm wrong) because I don't have parent items and sub-items, I just have inputs. If the sales guy makes the building 10 feet longer, the program needs to recalculate every quantity because that might change the quantities, lengths, widths and heights of 20-30 different items (lumbers, metals, trims, posts, more labour.....). So they're not just choosing to add more corner mouldings, they're changing the building dimensions and that is getting a new quantity for corner mouldings on the back end.
-
Every time an input box is edited on the quote page, the pricing for the entire job is recalculated, that means recalculating every quantity of every product, building the HTML for the quote and displaying it on the page using AJAX. So if the customer wants 10 gable stops instead of 5, you make that change and the program recalculates every single quantity of every product, every length, height, width, recalculates the cost of that job and displays it. It's taking about 10 seconds where before it was almost instant with individual functions for each call. I'm actually getting complains from the sales guys that it's taking so long to update now after a change. So to answer your question, there is no time when I would only be calling corner moulding or ceiling-only labour, every single building product is recalculated and called on any edit. When the sales guys are sitting with a customer, the customer likes to change 10-20 different things to try and get the price within their range. They might add a window and that will change the quantities of 5 or 6 different lumber products used in framing the window, it'll remove quantities of exterior metal and add window labour costs so the entire building needs to be recalculated when this change is made. No, I was not using variable functions, that was the reason for the change. I had actual functions created and named for every single item quantity, width, length, height, unit-price and total price. It was a huge pain adding a new product and entering functions for every dimension calculation, then adding that to the total price of the building price calculation. That's a good idea to change all the items to constants though, I'll try doing that. Right now I have all the building products in the database with a row ID and then defined in the program like so: private $lumber2x8x12Treated = 14; private $lumber2x8x16Treated = 15; private $lumber2x6x12 = 16; private $lumber2x6x16 = 17; private $lumber2x8x12 = 18; private $lumber2x8x16 = 19; private $lumber2x4x12 = 20; private $lumber2x4x16 = 21; private $lumber2x10x16 = 23; private $lumber2x6x16TreatedFillerBoard = 24; private $lumber2x6x12TreatedFillerBoard = 25; private $lumber2x8x16TreatedFillerBoard = 26; private $lumber2x8x12TreatedFillerBoard = 27; private $lumber2x6x12Treated = 32; private $lumber2x6x16Treated = 33; private $wallMetal = 34; private $gableMetal = 42; private $roofMetal = 43; private $wallScrews = 44; private $trimScrews = 46; private $heelMetal = 47; private $biFoldDoorMetal = 48; private $slidingDoorMetal = 49; private $exteriorBaseTrim = 50; private $birdStop = 51; private $ridgeCap = 52; private $ridgeLight = 53; As for the post right above this one, I'll reply to that once I read it again and figure it out a bit better, I just ran through it quickly but I'm heading to bed here and need some more time to read through it a bit better. I will reply to it when I get a chance.
-
function getTotalQuantityBuildingProduct($productId, $showInsulation, $showPerma) { $quantity = 0; foreach ($this->getQuantityBuildingProduct($productId, $showInsulation, $showPerma) as $productQuantity) $quantity += $productQuantity; return $quantity; } The getQuantityBuildingProduct() is the method I already posted. Since a product can have multiple quantities (3 doors at one width and 5 doors at a different width), the getQuantityBuildingProduct is an array of the quantity groups. The getTotalQuantityBuildingProduct simply adds together all the quantities from the array and gets a total. That total is multiplied by the price for a total cost of that type of product.......for most products. Some products use the widths and lengths to calculate the final cost as well if it is dependent on price per square foot (tiles, poly or sheets of metal).
-
I'll lay out my whole issue here just in case I'm incorrect about where the problem is. I wrote some software in PHP to build a quote for a building company. I have a manual quantity calculation for every product they have in inventory and each time they modify the inputs, like the building dimensions, it recreates the quote and spits out a new price based on the quantity calculations for each individual product being used. There are a number of inputs on the page and I make an AJAX call to the server to recreate the quote, then display the new quote once the AJAX return is done. This includes running all the quantity calculations. When requesting the quantities, it goes into a switch statement consisting of 300 cases until it finds the matching ID of the product being requested. It then runs the quantity calculation I have coded in there which may or may not rely on quantities of other products in the system as well. I have statements at the top and bottom of the switch statement to check an overall array to see if that item ID is already in the overall array (if the quantity has been calculated already). If so, it returns that quantity instead of recalculating it. If not, at the bottom of the switch statement it adds that quantity to the overall array in case that product quantity is requested again. Here's how it looks: function getQuantityBuildingProduct($productId, $showInsulation, $showPerma) { $quantities = array(); if (isset($this->overallQuantities[$productId])) return $this->overallQuantities[$productId]; switch($productId) { case ($this->cornerMoulding) : $quantity = 0; if ($this->isInsulated() || $showInsulation) { $quantity += ceil( $this->getTotalQuantityBuildingProduct($this->threeByThreeFixedWindow, $showInsulation, $showPerma) * 1.5 + $this->getTotalQuantityBuildingProduct($this->fourByThreeFixedWindow, $showInsulation, $showPerma) * 1.5; ); $quantity += $this->getTotalQuantityBuildingProduct($this->threeFootStandardDoor, $showInsulation, $showPerma) * 2.5; } $quantities[] = ceil($quantity); break; case ($this->smokeDamper) : $quantities[] = ceil(($this->getTotalQuantityBuildingProduct($this->smokeStop, $showInsulation, $showPerma) + $this->getTotalQuantityBuildingProduct($this->fireStop, $showInsulation, $showPerma)) * 3); break; case ($this->tuckTape) : $quantities[] = ceil($this->getTotalQuantityBuildingProduct($this->poly, $showInsulation, $showPerma) / 2000); break; case ($this->ceilingOnlyLabour) : if ($this->isCeilingOnly()) $quantities[] = 1; break; default: break; } $this->overallQuantities[$productId] = $quantities; return $quantities; } It's taking about 10 seconds to get the entire quote back from the server since I implemented these switch statements. I have others to also get the widths, heights and lengths of the products just like I get these quantities. I used to have a separate function to get every single quantity, width, length and height but that was a lot of individual functions so I found this easier to add new functions to. Is this the cause my the slowdown? How can I make it faster? My dream goal is to somehow store all of the quantity calculations in the database but I have no idea how I can do that since they're all different and sometimes rely on quantities of other products. I think having them in the database may speed things up (or slow them down) but I'm just not sure how to accomplish that right now. For now I'd just like to speed up the current way.
-
No, they're using pagination to display 20 results at a time. You click the arrow and it displays the next 20 results. I want to somehow get all the results using a HTTP GET request on my own PHP page.
-
Yes, I'm trying to pull a list of stores from a mall directory but they have the listing split across 3 pages and you browse the pages using javascript links. I want to pull all the stores from the 3 pages. More specifically they have a Javascript link for returning all stores, I want that one. EDIT: This one - http://www.crossironmills.com/shopping/store-directory/alpha/
-
I'm writing a PHP script to pull information from another website which I don't own. That website uses javascript for pagination, splitting data across 3 pages. They also have a function to list all their data on one page but it requires clicking the link on the page which runs a javascript AJAX call. I want to pull all that data with PHP but how do I emulate the Javascript AJAX call in my code so I can get all that data instead of just the first page? Even if I could just call that function and then parse the information it returns to me. Thanks.
-
I built a Bootstrap site but when I view it on my phone (Samsung Galaxy S3), it doesn't collapse the navigation menu into the mobile button like I thought it would. I did some research and realized that my phone is actually the same resolution as my desktop (1920x1080) so it's giving me the desktop view. Bootstrap, to my surprise, only seems to be responsive to resolutions, not physical screen sizes. How do I overcome this? I want to build a site which is responsive to physical screen size, regardless of resolution.
-
Okay, I've had success with mod_rewrite and .htaccess, I can now redirect URL of http://www.example.com/users/bob to point to http://www.example.com/some-page.php?action=getUser&user=bob. So now that I've been successful with that I'm a little confused how I would use this. If I wanted to display a page all about Bob and his associated information in the database, what do I do with this? Am I right to assume I would just have a regular user.php page which I would rewrite to and that would load all the information using $_GET['user'] to figure out which user to display? If so then that's simple enough but what about the API I keep reading about? I keep reading that I should create a rest API file so what would this look like and what is it used for? As of now I have this, is this pointing in the right direction? <?php require_once('include/include.php'); ?> <?php $action = $_GET['action']; $userId = $_GET['user']; switch($action) { case("get"): $controller::getUserById($userId); break; case("delete"): $controller::deleteUser($userId); break; } ?> My include.php file has the following: <?php require_once('controller/mainController.php'); require_once('model/mainModel.php'); require_once('view/mainView.php'); require_once('controller/loginController.php'); // call on every page to start the session MainController::sec_session_start(); $model = new MainModel(); //It is important that the controller and the view share the model $controller = new MainController($model); $loginController = new LoginController($model); $view = new MainView($controller, $model); // if (isset($_GET['action'])) // $controller->{$_GET['action']}(); ?> This is the same model/view/controller setup I use for all my sites, I find it easy to separate the code this way. So I'm using this controller in my API to call methods. If the method requires database access I pass it to the model. I need direction on the API though, do I need one? If I use it to delete a user, how do I then display the resulting page after the user is deleted? Just do a PHP redirect?
-
Cool, I'm off to do some research on how to change the URL for those pages. Can you tell me what it's called or somehow point me in the right direction to find examples on that?
-
Very interesting, thank you. One last question, is it acceptable web programming for me to be using example.com/user.php?id=123 instead of example.com/users/123 I'd put a question mark at the end of that question but it looks confusing so I left it off. I'm hoping my site in question is going to blow up big, something like Kijiji and be used quite a lot on a daily basis. I want it to be as perfect as possible.
-
I'm quite good at PHP but I thought it was time to learn this ReST thing people are talking about. As of right now I've got a web application written entirely in PHP and has a MySQL database full of......let's say users. Anyone logged in can browse a list of the other users (users.php) and can then visit that user's profile (user.php). There are no security limitations for the sake of our example. Right now when the user clicks another user, it brings them to a URL (http://www.example.com/user.php?user=123) and the page (user.php) makes a call to the model which checks the database for a user with ID 123, then returns any information for that user. I'm wondering if it would be more professional to have the user go to a more friendly URL (http://www.example.com/users/bob) which would load user.php with all the information about Bob (only a single Bob in the database). Is it reasonable to switch from my way to this ReST way? Can someone point me (or provide) a tutorial for the simplest example you can imagine? I would just need it to get to the SQL call, I can do all the database authentication and calling myself, I just want to know how everything is set up and I can build on it from there. I can't find anything this simple online, they're all too complicated with extra features I don't want. Thanks.
-
How do I get database values for currently logged in users?
DeX replied to DeX's topic in PHP Coding Help
Session hijacking and poisoning? Is that something I should worry about? -
How do I get database values for currently logged in users?
DeX replied to DeX's topic in PHP Coding Help
How do I keep track of the currently logged in user if I don't store the ID in a session variable? If it's in a session variable then the user is free to change it as they wish. -
I'd like to display a user profile for the currently logged in user so they can edit their contact details. I already have a secure login scripted which works well and it stores the user_id, username and a login_string into session variables. The login_string is a long alphanumeric string of hashed values used when checking the logged in status of the user but it's not stored in the database. My concern is if I pass the user_id from the session variable to the model to get the user contact information, the user can easily change that variable in order to display someone else's information. So should I continuously hash the same variables to compare the login_function or should I just store it in the database once the user logs in so that's it's readily available to do a comparison on any time I need database information. Does that make sense?
-
Is sha512 an acceptable encryption algorithm for passwords?
DeX replied to DeX's topic in PHP Coding Help
So just a random string generator for every salt and store it in the user table? -
Is sha512 an acceptable encryption algorithm for passwords?
DeX replied to DeX's topic in PHP Coding Help
Great, thanks, so I'll incorporate SSL, send the unhashed password, then salt and hash it on the server side. Which things should I be salting with the password for best security? The IP? The browser session ID? Timestamp? And lastly, should I be storing the salt in the database or should I just use the same method each time (for example every second letter of their name or something)? -
I'm writing a huge PHP secure login script for a heavily used website so I need to do 2 things securely: a) transmit the password from the form to the webserver. b) store the password in the database. I'm using a JavaScript sha512 function I downloaded in order to encrypt the password prior to sending it to the webserver and I'm storing encrypted passwords in the database using hash("sha512", $password) as an encryption function. Is this good enough? Is there a different encryption algorithm I should be using? The process I'll be using is encrypting with javascript, sending to the webserver, adding a salt and encrypting again for storage.
-
I'm building a website with a layout I've never tried before but I've seen it work well on a lot of other websites. I'm wondering if someone here can help me accomplish doing this, I haven't been able to figure it out. This is the design I got from my designer which I need to code: I removed the middle white area so you wouldn't know my website idea. What I want is a 1200 pixel wide center area and I want the outside parts to fill the remaining portions of the page, regardless of the screen width. So (correct me if I'm wrong), I was thinking I need the left div, center div and right div. The center is fixed width and the left/right parts are variable but how do I accomplish this?
-
This is my very first MVC style PHP scripting so I'm wondering if I've done it the very best I can. I've done a lot of reading and this is what I just got working. First I'll explain how it works: - User goes to www.example.com/mvctest.php and gets a login prompt. - User tries to skip that and go directly to the home2.php page to try and view the site without logging in first. He gets automatically redirected back to mvctest.php for login. - User gives bad credentials, he gets routed back to mvctest.php for a bad login to try again - User gives proper credentials and gets logged in, gets redirected to home2.php on successful login. - User closes their browser window, then opens another and goes back to the homepage at mvctest.php. Instead of getting the login prompts again, he gets redirected straight to home2.php because he's already logged in (cookies remain until midnight). - User clicks logout button. Their cookie is set to a time in the past and they are redirected back to mvctest.php and prompted for login credentials. That's all the actions I could think of. Now on to the code. It all works except I commented out the disconnecting from the database because it was doing that prematurely and I wasn't able to log in using my mysql link because it had been closed before I got to use it. That's small stuff though, I'm wondering if people can comment on everything, I want this to be as good as it can be. Thanks. mvctest.php: <?php require_once('controller/login.php'); require_once('model/database.php'); require_once('view/login.php'); include('includes/include.php'); ?> <form action="?action=login" method="post"> Username: <input type="text" name="username"> Password: <input type="password" name="password"> <input type="submit"> </form> include.php: <?php $model = new DatabaseModel(); //It is important that the controller and the view share the model $controller = new LoginController($model); $view = new LoginView($controller, $model); if (isset($_GET['action'])) $controller->{$_GET['action']}(); ?> home2.php: <?php require_once('controller/login.php'); require_once('model/database.php'); require_once('view/login.php'); include('includes/include.php'); ?> <button type ="button" onclick ="window.location = '<?php echo $_SERVER['PHP_SELF'] ?>?action=logout'" >Log Out</button> controller/login.php: <?php class LoginController //extends Controller { public $view; public $databaseModel; public $loginModel; /** * Initializes the Vew and the Model. */ public function __construct($model) { require_once('model/login.php'); $this->connection = $model->connectToDatabase(); $this->loginModel = new LoginModel($model); $this->view = new LoginView($this, $model); if (!$this->loginModel->checkLogin() && !$this->isLoginPage()) { $this->view->showLoginPage(); $model->disconnectDatabase(); } else if ($this->loginModel->checkLogin() && $this->isLoginPage())// must wait for loginModel to return before disconnecting { $model->disconnectDatabase(); $this->view->loginSuccess(); // go somewhere else if already logged in } else $model->disconnectDatabase(); } /** * The "index" action. * Called by default if no action is defined. */ public function index() { $this->show(); } /** * The "show" action. * Simply instructs the View to display the form. */ public function show() { $this->view->showForm(); } public function isLoginPage() { $urlPath = explode("/", $_SERVER['PHP_SELF']); if ($urlPath[count($urlPath) - 1] == "mvctest.php") return true; else return false; } /** * The "process" action. * Processes the form data, either sending it to the model to be * saved into the database, or displays errors if the required * fields are not present. */ public function login() { $requiredFields = array('username', 'password'); $data = array(); $error = false; foreach($requiredFields as $_field) { if(!isset($_POST[$_field]) || empty($_POST[$_field])) { $error = true; $this->view->showLoginError("Field '{$_field}' needs to be filled."); } else { // Skipping any sort of validation, for the sake of // simplicity. $data[$_field] = trim($_POST[$_field]); } } if($error) { $this->view->showForm(); } else { if($this->loginModel->login()) { $this->view->loginSuccess(); } else { $this->view->showLoginError("Username or password is invalud. Please try again."); } } } public function logout() { if ($this->loginModel->logout()) $this->view->showLoginPage (); } } ?> model/database.php: <?php class DatabaseModel { public $connection; public function __construct() { } public function connectToDatabase() { require_once('includes/config/config.inc.php'); $connection = mysql_connect(HOSTNAME, USERNAME, PASSWORD); if (!$connection) die('Could not connect: ' . mysql_error()); $database = mysql_select_db(DATABASE, $connection); if (!$database) die('Could not select database: ' . mysql_error()); $this->connection = $connection; return $connection; } public function disconnectDatabase() { // mysql_close($this->connection); } public function getConnection() { return $this->connection; } } ?> model/login.php: <?php class LoginModel { public $connection; public function __construct($databaseModel) { $this->connection = $databaseModel->getConnection(); } public function checkLogin() { if (isset($_COOKIE['login'])) { if ($_COOKIE['login']) { return true; } else { return false; } } } /* public function inputs($fieldNames, $data) { foreach ($fieldNames as $field) { echo "data: " . $data[$field] . ", field: " . $field . "<br />"; } } */ public function login() { $sql = mysql_query("select salt, password from user where username = '" . $_POST['username'] . "'", $this->connection); if (mysql_num_rows($sql) > 0) { $sqlRow = mysql_fetch_assoc($sql); if (sha1($_POST['password'] . $sqlRow['salt']) == $sqlRow['password']) { setcookie("login", true, $this->getLoginCookieExpiry()); return true; } else return false; } else return false; } public function logout() { setcookie("login",false,time()-10); return true; } public function getLoginCookieExpiry() { return mktime(23, 59, 59, date("m"), date("d"), date("y")); } } ?> view/login.php: <?php class LoginView { protected $model; protected $controller; public function __construct(LoginController $controller, DatabaseModel $model) { $this->controller = $controller; $this->model = $model; } public function showLoginError($error) { return $error; } public function loginSuccess() { header("location: home2.php"); } public function showLoginPage() { header("location: mvctest.php"); } } ?>