Jump to content
Larry Ullman's Book Forums


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by Matt

  1. I think what he means, and I may be wrong, is he want's to store all the different print items in one table, the custom designs in another table, and then link them in an 'orders' table with foregin keys. Is this what you were saying Ben?
  2. Larry, I`ve implemented the changes and everything appears to work fine! What I've done is written the directory name to a variable in the index.php file, so that this can be used by the database query to grab all the data for that specific gallery. I also use it when an artist visits another gallery which isn't his/her own. In the sidebar menu, there is a conditional which compares this variable with the 'directory_name' pulled from the database when he/she logs in. If they are different, then the sidebar will only display a link to his/her gallery. If they are the same, then the menu will show links for updating their profile, uploading images, etc... What do you think of this? Here is an example index file written to a folder called "MattsGallery": <?php require ('../../includes/config.inc.php'); require (MYSQL); $dir = 'MattsGallery'; require ('../../includes/show_gallery.inc.php'); ?> Here is the show_gallery.php file: <?php if ($_SERVER['REQUEST_METHOD'] == 'POST') { include ('../../includes/gallery_login.inc.php'); } $q = "SELECT user_id, first_name, last_name, image, gallery_name, description FROM profiles WHERE directory_name='$dir'"; $r = mysqli_query ($dbc, $q); // Get the number of rows returned: $rows = mysqli_num_rows($r); if ($rows == 1) { $row = mysqli_fetch_array($r, MYSQLI_ASSOC); } // Include the header file: include ('../../includes/gallery_header.html'); echo '<div id="content">'; /* PAGE CONTENT STARTS HERE! */ include('../../includes/gallery_content.html'); echo '</div>'; include ('../../includes/gallery_footer.html'); // Omit the closing PHP tag to avoid 'headers already sent' errors! ?> What do you think Larry? Is this what you were recommending? Thanks, Matt
  3. Larry, Thank you so much for your good suggestions! When I fist saw this, I thought "Damnit! Larry's throwing a wrench into our great design!" (Larry, you know how I am). However, after rereading the post, I realized that Larry is 100% right! Why are we using a function to create the page at runtime, when an included script can do the same thing without all the database connection headaches! Then I talked to HartleySan and he brought up a good point! The index page that creates a gallery is very simple. It contains just an include for the gallery_functions.inc.php file and a call to the create_gallery() funtion, passing along the folder name (i.e. the gallery name) that the index file resides in as an argument. We don't want any content embedded within it. HartleySan thinks that calling a function which creates the galley content is better than including a file (which does the same) because if we ever decide to change the content later, then we only have to do it in one place (i.e. inside the function). The function is like a "black box" from the perspective of the index file calling it, and all the work is done there. I suppose that the same could be said of an included file, but he just felt that doing this in a function was better. What are your thoughts on this Larry? I'm not sure I fully understand what you mean by this Larry. Could you be a little more specific? Thanks again, Larry! Matt
  4. Thanks for the detailed explanation Larry! That was exactly what I wanted to hear. With all the talk of frameworks on this forum, and elsewhere, I just wanted to get a good idea of when it's appropriate to use them or not. I guess I'm bringing in a little backgroud from Flash into this. There are literally hundreds of Actionscript 3 APIs available on the web. I have often used them for one thing or another because I don't want to reinvent the proverbial wheel. However, I am very particular about things, and what I find myself doing 9 times out of 10 is customizing the API to suit my needs! With that in mind, I was looking at frameworks as the "easy way out", and that I would still have to do massive customization to get them to do exactly what I want! Anyway, now I have a better appreciation for using frameworks, so I will look into them more. Also, I apologize for the extreme tone in my posts! I guess it's my style when I don't understand why people are doing something a certain way. It's part serious and part show because I'm trying to elicit a good answer which supports the thing I'm arguing against (if you think that's bad, you should hear me talk about politics and U.S. foreign policy)! I just hope nobody took offence to it, and was perhaps entertained a little I will try and relax a bit before I post questions like this again.
  5. Great answers Antonio! Absolutely! I talked with HartleySan about this on the phone last night, and I kind of agreed with him that it was filtering data, but only to the extent that it was grabbing columns from the joined tables which matched the WHERE clause. You put it much better! Also, HartleySan was asking me questions about queries like "How do you choose which table to start with?" I told him that I look at the first table in the select statement as the root, or home, table. This table, in my view, becomes the "left" table, and all joins are carried out to the "right" of that table - this may seem like a load of nonsense, and have no bearing on the "LEFT" or "RIGHT" used in a JOIN clause, but that is how I picture it in my mind. For clarity, I always write joins in the order that the joined tables are connected to (and move away from) the "root" table, but I don't see why you couldn't put them in any order. In simple select queries with a join on a prominant table (i.e. `users` or `movies`) it is usually easy to determine which table is the "left" table. It is usually the "one" in a "one-to-many" relationship. Of course, the real answer of which table comes first depends on the question you are asking. If you want to find all the posts created by a user in a specific forum thread, then you would abviously start with the `users` table and join the `threads` and `posts` tables from there, with the WHERE clause being set to equal the "user_id". I'm sure I'm telling you and Jonathon stuff you already know, and I hope it doesn't sound like a bunch of hot air! It's just the way I look at it and it works for me! Matt
  6. Larry, Sorry to sound abrupt, but I really have to ask; Why in the hell would I want to use someone else's glorified api (which is all a framework is in my opinion) when I can do things myself using your books? I mean, what is the point of learning anything about php if I can just bloat my server disk space with someone else's code (half of which I`ll probably never need) and just call functions? Can you give any specific examples of when a framework might be better to use? Can they replace the brilliant code you have given us in the E-Commerce book? When I hear all this ranting and raving about how wonderful frameworks are, I really have to ask myself why I am working hard studying the more difficult aspects of php! Maybe I should just give up and install Yii!
  7. Apparently empty() does the same thing as the above! I found this code in the comments on php.net: <?php if (isset($var) && !empty($var)) { echo $var; } else { echo "missing variable '$var'"; } ?> The only problem is that it considers 0, and "0" to be empty values and returns TRUE!
  8. Jon, I agree. However, if you get anything out of Larry's books, then the thing that is glaringly obvious is that nothing can be overlooked when dealing with data! Always assume the worst and then work backwards! That's what separates half ass web programming from good! Thank you! I will test this.
  9. Ah, I see what you are saying! I thought you were insisting that I create a boolean field in the 'users' table to indicate whether a gallery had been created. My apologies for that! I will look into your suggestions!
  10. Thanks HartleySan, but that is completely an "apples" and "oranges" comparison! In the case of the user registration system, Larry is only doing a SELECT query on one table, and he is checking for the presence of a hashed value to see if someone had confirmed their registration through an email or not! What I'm doing is very different! I should have explained it clearer above (it is a little complicated), so I apologize for that. I am doing a LEFT OUTER JOIN on two tables. The query will always output one, and only one row (given that there are no errors in the data integrity) from the 'users' table. If the user has created a profile, and hence a gallery, then there will be a matching record in the 'profiles' table ON user_id, and thus the field in the result set for 'directory_name' will have a value. Storing a boolean, or other value, in the users table to check for the presence of a gallery breaks a cardinal rule of database design in that there is now data redundancy! The simple presence of a value in the 'directory_name' field in the 'profiles' table for a given user is the same as having a boolean value to indicate such in the 'users' table. Second, and more importantly, I need the 'directory_name' value so that I can create a link to it in the side menu. As a side note, running two queries is not an option! It is extremely bad programming practice to do so, especially in such a simple case as a user login! It would be akin to washing your car, going in and taking a shower, and then coming back out to wash the tires and polish the rims! I suppose I could do the test for NULL within the query itself as you mentioned, but I also need to check for an empty string as well (in the rare event that a record in the profile table has been created, but the 'directory_name' field is somehow empty. This is a pretty good idea! Thanks for that! Jonathon, congrats as well for the #200 post!
  11. I now have everything stored in session variables and they work fine! However, I have another question: How do you check to see if a field returned in a query is NULL or empty? I did a search on google and found some answers in other forums, but they were all over the place. People were arguing with each other over the best way to do this, and I thought that this should be pretty straight forward. The reason I ask is because I need to do the following check when a user logs in: In the login.inc.php script, I run a LEFT JOIN query on the `users` table and the `profiles` table in order to get the user_id, username, type, and directory_name (of their gallery). $query = "SELECT users.id, users.username, users.type, IF(users.date_expires >= NOW(), true, false), profiles.directory_name FROM users LEFT JOIN profiles ON users.id=profiles.user_id WHERE (users.email='$e' AND users.pass='" . get_password_hash($p) . "') LIMIT 0,1"; Besides redirecting the user at logout, the other reason I am checking the directory_name field in the `profiles` table is because I want to know if the user has created a gallery yet or not (they are not immediately required to). If they have, I want to store it in a session variable, so that I can create a link to their gallery in the side navigation menu. If they haven't, then I want to add a "Create Gallery" link to the side navigation menu. I already have the directory_name stored in a session variable and it works fine. However, I haven't added the check to see if the returned value is NULL/empty. If anyone knows how to do this, I would really appreciate it! Matt
  12. Larry, I would have to say yes! HartleySan and I can probably figure it out, but since a bad decision could jeopardize database security, I would like to hear what you think would be the best solution. Also, why is it that declaring the $dbc variable as global at the top of the mysqli_connect script leads to a security risk? First of all, nobody even knows the name of the variable. Second, how can they access this script if it is outside the web root? Thanks a lot! Matt
  13. MikeMikeMike, I can somewhat agree with you on that. I have also ran into situations where I felt the same way and it can be frustrating. However, given the nature of your questions, I feel like you are having trouble with some of the fundamental concepts of database design. I don't mean to steer you away from buying Larry's books (although you mentioned that you already had a few of them), but maybe you might consider supplementing them by enrolling in a web programming/database class at a local community college. The knowledge/experience you would gain would be invaluable!
  14. HartlySan, yes! The user will be directed back to their gallery index page. I almost forgot about that. With the code above, if they logout while visiting another gallery, they will be redirected to that other gallery's index page after logout. I'm starting to think I need to store each user's gallery url in a session variable. Making a call to the database during logout is simply not acceptable!
  15. Thanks for the reply Jonathon! That's what I'm starting to think would be the best way. I'm thinking I should have the logout link to another page. <a href="logout.php?returnpage=". $SERVER['PHP_SELF'].">logout</a> Then have the following in the logout.php script. <?php //Start session session_start(); $page = isset($_GET['returnpage']); // Destroy the session: $_SESSION = array(); // Destroy the variables. session_destroy(); // Destroy the session itself. setcookie (session_name(), '', time()-300); // Destroy the cookie. header("location: $page"); ?> The outline of this code came from a post I found in another forum while doing a google search on this topic. The errors were caused by a first attempt at doing this. There was a "can't find stream" error for an included file as well as a "headers already sent" error. I looked at the code after and realized that I had set it up wrong, so hopefully they were just caused by my initial carelessness.
  16. I am working on a site based on Example 1 from the book. As it is written, when a user logs into the site a "logout" link is displayed on the sidebar. When the link is clicked, it calls another page, logout.php, which logs the person out. What I want to do is keep everything modular and never have the user leave the index.php page. Instead, when a user logs out I would like them to be redirected back to the same index.php page and have the login form display again. I tried playing with this today, but ran into all sorts of errors! The way I think this should be handled is that clicking the "logout" link will call another included script in the background which does the actual logging out. After that the page will be reloaded. Figuring out where exactly to place the following code is the difficult part: // Destroy the session: $_SESSION = array(); // Destroy the variables. session_destroy(); // Destroy the session itself. setcookie (session_name(), '', time()-300); // Destroy the cookie. I'm just not sure if this is the best way to do this, or in fact, how I should do it. I would appreciate anyone's ideas/help with this! Thanks in advance, Matt
  17. Jon, Are you insane? Larry was about to answer!
  18. Larry, Thank you so much for your help! The answers you gave were just what I wanted to hear - well not really, but you know what I mean The problem is a bit out of the ordinary, so one of the solutions I posted (or a better one which I hadn' thought of) is absolutely necessary for the database connection to work right. I know you are busy, but you might want to look back in the thread a bit just to see what's going on here. Here`s a recap: The mysql_connect script is being used in 2 different scenarios: 1 - It is being included within a function - in the case of the individual galleries (as mentioned above) 2 - It is being included in the normal way (outside of a function) in the case of a user just going to the top level of the site and logging in through the main index.php page The problem is getting the script to handle both scenarios without the $dbc variable losing global scope/the functions internal to the mysqli_connect script losing access to the $dbc variable. HartleySan and I have both looked at this and are really at a loss as to the correct way to implement it. Although we have gotten the script to work using "B" above, we know it's not the best way to do this, as you said! This is a real conundrum Larry! What else can we do to allow global access to $dbc?
  19. MikeMikeMike, Sorry if my answer was not clear enough for you. I was just trying to help! As far as why you were only getting 10 results for the query which included the "ON" clause, I was 100% right! I originally said "The answer to this question is fairly easy! You are essentially selecting all records from the specific_coffees table WHERE the general_coffee_id = 3. If you look at the specific_coffees table, there are exactly 10 records, and all of them have a general_coffee_id of 3, so you should therefore have 10 records in your query result!" The key parts from the original query are: SELECT ... FROM specific_coffees and WHERE general_coffee_id =3 The "ON" clause merely limits the results so that only 1 record from the sizes table is matched with each specific_coffees record. As for the second question, yes I was a little off the mark! This was exactly the conclusion I came to when I first read your post. However, since you said you were getting 30 records in your result, I decided not to mention that and I got sidetracked and started looking at it another way. I completely overlooked the LIMIT clause, so my apologies for that. It was almost 3:00am in Japan when I wrote the last post, so I wasn't in the best condition to do any deep analysis of Larry's query. So, yes I was wrong as far as the second answer being exactly correct. Nevertheless, as I had said, a Cartesian Product was involved and I thought I explained that fairly well. And, as it turns out, the answer was far simpler than I had thought (i.e. the LIMIT clause restricting the result set to 30)! I only try to post answers in this forum to questions that relate to areas I am fairly confident in! That being said, I was an IT major and took several classes in database design and analysis over my university career. Although I may not be spot on in every answer, I still generally know what I'm talking about!
  20. Sorry MikeMikeMike! I didn't know how far along you were with using SQL. The answer to this question is fairly easy! You are essentially selecting all records from the specific_coffees table WHERE the general_coffee_id = 3. If you look at the specific_coffees table, there are exactly 10 records, and all of them have a general_coffee_id of 3, so you should therefore have 10 records in your query result! As for why there are 30 records when you take out the ON clause, I would need to look at the query more and think about it. Whatever the reason, there is some sort of a Cartesian Product going on there. It might have something to do with the specific_coffees table (which has 3 records) and the general_coffees table (which has 10 records). 3 x 10 = 30! Again, I would have to sit and look at the query a bit deeper to be certain, but it's getting late here. I hope that was a little better.
  21. Well now that I have that working, there are a few different ways to implement it. Since the mysqli_connect file is being used both within a function (in the case of the galleries) and outside (in the case of the top level index page), both situations need to be handled by the database connection script. I have found 3 possibilities that all seem to work, however, I wanted to know which is the best, most secure way to implement it! A - Declare the $dbc variable as global at the top of the mysqli_connect file: <?php // This file contains the database access information. // This file establishes a connection to MySQL and selects the database. // This file defines a function for making data safe to use in queries. // This file defines a function for hashing passwords. // Set the database access information as constants: DEFINE ('DB_USER', 'tueslcom_matt'); DEFINE ('DB_PASSWORD', 'Japan2004'); DEFINE ('DB_HOST', 'localhost'); DEFINE ('DB_NAME', 'tueslcom_gallery'); // Make the connection: global $dbc; $dbc = mysqli_connect (DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); ... B - Redefine the $dbc variable in the get_password_hash() function: function get_password_hash($password) { // Need the database connection: $dbc = mysqli_connect (DB_HOST, DB_USER, DB_PASSWORD, DB_NAME); // Return the escaped password: return mysqli_real_escape_string ($dbc, hash_hmac('sha256', $password, 'c#haRl891', true)); } C - Create a second mysqli_connect script for the galleries that has the $dbc variable declared as global at the top (as per the first example). This would limit any security risk only to situations where the gallery pages are accessing the database. This seems a bit redundant, however, since the one script should be able to be written to handle both access scenarios. A fourth option might even be to define the $dbc variable as is at the top of the script and then use a getDbc() function to pass the variable to whatever other function might need it: <?php function getDbc(){ global $dbc; return this->$dbc; } I'm not too sure how well that would work, but I was just running over several ideas and this one seemed like it might be possible to implement. I'm just hoping there is a more straightforward way to do this that's secure. Is it bad to define the $dbc variable as global at the top of the script? If so, why? Nobody can access the script from outside because it is above the web directory. I would think that example 'B' would be the best, but I'm not 100% confident. Larry, what do you think?
  22. To understand why this is happening, then we first have to understand what the "ON" clause is doing within an INNER JOIN. This is taken from the mysql website: The "ON" clause is used in an inner join query to select data from 2 tables where a match is made between data in one column from one table and one column in the other. In your example, "ON s.id = sc.size_id" is looking for matches between data in the "s.id" column and "sc.size.id". Wherever a match is made, then those records are being selected, if and only if, they match the data defined in the "WHERE" clause. I hope that makes some sense. Larry gives a nice crash course in "oins" in his "PHP 6 and MYSQL 5" book! What it sounds like you are getting is what's called (in systems analysis lingo) a "Cartesian Product". A cartesian product of multiple input sets is "a larger set containing every ordered combination of the input set elements." Translated into plain English, this means that each and every row in the first table is joined to each and every row in the second table (hence, the increase in the number of records output in your query). Failure to define a join conditional - such as an "ON" clause - when creating inner joins will result in Cartesian Products! Hope that helps!
  23. Noob, You mention Flash/Flex, but Actionscript (which is what I think you are referring to) is based on C syntax and certainly has a lot of the same "gotchas" found in those languages - you can read the wikipedia page link you posted to find some of them. However, Larry pretty much summed it up! What you need to do is study your ass off like I did and spend a lot of time developing with the Flex/Flash IDEs. I have been using Flash on and off for years and have read Actionscript 3.0 books to the point of nausea. I think I'm pretty knowledgeable with the technology, yet I still only consider myself an intermediate user! One mistake people make is in thinking they can just buy one of those "Learn Flash in 24 hours" books and be experts within a couple of weeks! I can very confidently say that this thinking is WRONG! Flash/Flex are very powerful technologies, and Actionscript 3.0 is a full fledged object oriented programming language. Once you start down the "rabbit hole", it can go very deep! If you want to learn the "gotchas" then you have to start spending time with the technology. Period!
  24. "Noob", I came from the exact background as you (learned AS 3 using Flash CS and then moved on to Flex), so I have asked the same questions before! I agree with Larry that using the "Cookbook" series is great! I also find these resources to be very helpful as well: Tour de Flex - This site, which is part of Adobe, is a must see resource for all Flex related topics! If you download the AIR app. there are literally hundreds of examples (with code) showing you how to do just about anything you can imagine! gotoandlearn - This is a great site by Adobe engineer Lee Brimlow, which features lots of how-to video tutorials about various Flash related topics. You have to search around a bit to find the Flex specific stuff, but there are some good tutorials here!
  25. I'll try to explain. Do you want the short version or the long version? I'll try the short version. What I'm doing is allowing a user who registers with my site to create his/her own art gallery. Once they register, they then fill out a form with various information ("gallery name", "directory name", "gallery description", etc...). As soon as this form is submitted, a folder is instantly created with the directory name they provided in the form. An index file is created on the fly and dropped into this folder as well. What is essentially happening is they are creating a site within my site! The index file is very simple. It first requires a file called gallery_functions.inc.php from the includes directory. Next, it grabs the directory name it resides in and then calls a function, create_gallery() in the gallery_functions.inc.php file and passes the directory name as an argument. Here is the create_gallery() function: function create_gallery_index ($directory) { // Require the configuration before any PHP code as the configuration controls error reporting: require('../../includes/config.inc.php'); // The config file also starts the session. // Require the database connection: require (BASE_URI . 'mysqli_ecommerce_connect.php'); if ($_SERVER['REQUEST_METHOD'] == 'POST') { include ('../../includes/gallery_login.inc.php'); } // Include the header file: include ('../../includes/gallery_header.html'); echo '<div id="content">'; /* PAGE CONTENT STARTS HERE! */ $q = "SELECT user_id, first_name, last_name, image, gallery_name, description FROM profiles WHERE directory_name='$directory'"; $r = mysqli_query ($dbc, $q); // Get the number of rows returned: $rows = mysqli_num_rows($r); if ($rows == 1) { $row = mysqli_fetch_array($r, MYSQLI_ASSOC); //echo '<img src="' . BASE_URL . 'includes/image_proxy.php?img=' . $row['image'] . '" alt=""/>'; echo "<p><h2>{$row['gallery_name']}</h2></p\n"; echo '<img src="../../includes/image_proxy.php?img=' . $row['image'] . '" height="200" width="200" alt=""/>'; echo "<p>{$row['first_name']}" . " {$row['last_name']}</p>\n"; echo "<p>{$row['description']}</p>\n"; } else { echo "<p>There was an error!</p>\n"; } echo "</div>"; echo ' <div class="sidebar">'; ....blah, blah, blah echo ' </div>'; echo '<div class="clear"></div>'; include ('../../includes/gallery_footer.html'); // Include the footer file to complete the template: //require ('../../includes/footer.html'); } I've removed some of the echo statements dealing with content, but you can get the basic idea. Since the mysqli_connect.php scrip It is being required within the create_gallery() function, the global definition of $dbc within the $get_password_hash() function inside the mysqli_connect file is being lost! Aside from that one problem, the set-up works quite nicely! Yes. This behavior is interesting, and quite unlike Java, VB, C based languages, etc...
  • Create New...