Jump to content
Larry Ullman's Book Forums

Christopher

Members
  • Content Count

    52
  • Joined

  • Last visited

Everything posted by Christopher

  1. Larry, Antonio, thanks for the reply. I am learning and doing OO PHP now and probably will have more questions later
  2. Larry, I am reading CH4 the second time, and have a couple of questions: 1. I noticed that in Ch4 when introducing constructors, __autoload, and the like, you wrote 'note that functions in PHP beginning with two underscores are special ones'. Why not just use the term 'magic methods' for those special ones? 2. When introducing $this, it states 'you must use an alternative syntax to access the class’s attributes.' Will it be better to indicate that PHP requires an explicit $this to be used when we access class members in the class? Because many OO languages like C++, C# or Jave do not enforce $this(correct me if I am wrong)? Also, I think 'to access the class's members' would be better than "class's attributes". 3. In the last tip of Creating Constructor section it mentions the PHP 4 constructor naming scheme, why does PHP constructor have such change? My guess is, for PHP 4 style: class Human { public Human() { // PHP 4 constructor } } then when the class name is changed later somehow, we have to also update the constructor name; so to use __construct eliminates such issue. Is my guess right?
  3. Larry, thanks for the sharing! You mentioned when you was learning these technologies, you worked very hard, learned, practiced, and repeated until you got it right --- At that time how many hours on average did you spend on learning & practicing each day? I have a friend who is also a great programmer(Java), and he says when he was learning Java, he did coding 10-12 hours a day, non-stop except meal breaks. When I started to learn HTML and PHP, I could just focus on the topic for like 2 hours at most, then I took a break or changed a subject. After observing people who are really good at what they do(be it programming, engineering or other disciplines) in person or through reading, I found that they have one thing in common: they can focus on working for many hours a day. That's what makes them successful in their own fields. Through continuously trying, now I can keep learning and coding for a relative long time frame. I know almost all PHP frameworks use OOP, does the E-commerce book use procedural style or OOP style?
  4. Thanks Larry. Surprised to know that you have not been in the job market. If you don't mind, could you share how did you gain those project experience and great programming skills? By doing freelance projects? Currently I am reading your book to learn PHP and JS, and at the same time do my small projects so I can use what I have learned in your book. After months of trying and experiencing, I found that strategy suits me well, because it's a balance between reading books and doing projects. If I just do projects and not read books, then what I can do is quite limited; if I just read books and not do projects, then what I have read will quickly fade away from memory because only doing can make the knowledge part of me. How do you think of my learning-and-doing strategy? I just got your Advanced PHP book and started reading the OOP part like mad. After that, I should go with the Yii book or the E-commerce(2nd edition) book? I have the impluse to buy them at once and read them at the same time, but experience tells me it's not possible and not effective.
  5. Thanks, then I can save the exam fee which can buy several great books! Larry's books are on the top of my shopping list.
  6. Currently Zend updated its PHP certification to PHP 5.5, I am thinking whether it's worthy to prepare for the exam and take it. The exam is not cheap, and many people say all kinds of certifications by those companies are just their way to make money, well, in a sense, I agree. If I take the Zend exam: Pros??(I'm not sure...) I browsed the exam guide, seems a lot of stuff is covered. I plan to apply for some PHP developer jobs (in two months maybe) after I gain more experience (by doing some small web apps using what I have learned and plan to learn: procedural PHP --> OO PHP --> Frameworks). I guess in a job interview, I will be asked many questions on the knowledge of PHP, so maybe prepare for the Zend exam will also benefit my future job interview?? Cons: Time for preparing the exam is a major cost. Some people might believe I should spend the time used to prepare for the exam actually programming PHP apps. Any suggestions?
  7. I use NetBeans. Just found out Netbeans 8.0 beta has come out. It's very easy to debug PHP in Netbeans, while debugging in Eclipse is too slow(maybe the same in Zend Studio which is based on Eclipse). Another nice IDE is Visual Studio 2012, though I don't use it often at the moment. It has a PHP plugin but is not free to use.
  8. Larry, Thanks for the reply! I will address the two points one by one. Yes, I forgot to do it. Now in view_users.php, delete_users.php and edit.users.php, at the beginning of the script, I added in this code block: <?php # Script 10.5 - view_users.php, modified for Ch18 # Ch18 - PURSUE - Create view_users.php and edit_user.php scripts for site administration. Restrict access to these scripts to administrators (those users whose access level is 1). // This script retrieves all the records from the users table. // This new version allows the results to be sorted in different ways. // Include the configuration file: require ('includes/config.inc.php'); // Set the page title and include the HTML header: $page_title = 'View the Current Users'; include ('includes/header.php'); // Check for a valid admin ID (restrict access to this script to administrators(whose access level is 1)): if ( (isset($_SESSION['user_level']) && $_SESSION['user_level']) != 1 ) { // Not an admin, kill the script. echo '<p class="error">This page has been accessed in error.</p>'; include ('includes/footer.php'); exit(); } echo '<h1>Registered Users</h1>'; // I put the validation before generating any text on the content part of the page require (MYSQL); // Number of records to show per page: $display = 10; <?php # Script 10.3 - edit_user.php - PURSUE, modified for Ch18 // This page is for editing a user record. // This page is accessed through view_users.php. require ('includes/config.inc.php'); $page_title = 'Edit a User'; include ('includes/header.php'); // Check for a valid admin ID (restrict access to this script to administrators(whose access level is 1)): if ( (isset($_SESSION['user_level']) && $_SESSION['user_level']) != 1 ) { // Not an admin, kill the script. echo '<p class="error">This page has been accessed in error.</p>'; include ('includes/footer.php'); exit(); } echo '<h1>Edit a User</h1>'; // Check for a valid user ID, through GET or POST: if ( (isset($_GET['id'])) && (is_numeric($_GET['id'])) ) { // From view_users.php $id = $_GET['id']; } elseif ( (isset($_POST['id'])) && (is_numeric($_POST['id'])) ) { // Form submission. $id = $_POST['id']; } else { // No valid ID, kill the script. echo '<p class="error">This page has been accessed in error.</p>'; include ('includes/footer.php'); exit(); } require (MYSQL); <?php # Script 10.2 - delete_user.php, modified for Ch18 # 2014-1-26: modified for Ch18 // This page is for deleting a user record. // This page is accessed through view_users.php. require ('includes/config.inc.php'); $page_title = 'Delete a User'; include ('includes/header.php'); // Check for a valid admin ID (restrict access to this script to administrators(whose access level is 1)): if ( (isset($_SESSION['user_level']) && $_SESSION['user_level']) != 1 ) { // Not an admin, kill the script. echo '<p class="error">This page has been accessed in error.</p>'; include ('includes/footer.php'); exit(); } echo '<h1>Delete a User</h1>'; // Check for a valid user ID, through GET or POST: if ( (isset($_GET['id'])) && (is_numeric($_GET['id'])) ) { // From view_users.php $id = $_GET['id']; } elseif ( (isset($_POST['id'])) && (is_numeric($_POST['id'])) ) { // Form submission. $id = $_POST['id']; //when the confirmation form is submitted, user_id is transfered using from hidden field, in $_POST['id']! Smart! } else { // No valid ID, kill the script. echo '<p class="error">This page has been accessed in error.</p>'; include ('includes/footer.php'); exit(); } require (MYSQL); Just added in this access validation routine(using $_SESSION['user_level'] which was already set in login.php), anything else is the same. One question here is: I first just added this validation routine to view_users.php, because I thought only when a user gets there can he have access to delete and edit user scripts. But later I guess if these two scripts have no such access validation routine, then a malicious user could just guess the name of edit_users and delete_users, and type and try it in the browser, so I added them in. Is my understanding correct? If so, then I guess every page of a CMS should contain certain access validation at the beginning of the scripts, right?? For the second suggestion: I am still trying to figure it out, one query. Maybe any hint(just a key word)?
  9. lupiya, maybe you should debug the program, I am sure you will find the root cause.
  10. I am in the midst of replacing Ch18 scripts from using mysqli to PDO, but I got a problem here: login.php if ($e && $p) { // If email and password are validated. // Prepare the first query on users table: (using Prepared Statements) $q = "SELECT user_id, first_name, DATE_FORMAT(last_login_time, '%a, %b %e at %l:%i%p') as f_last_login_time, last_login_time FROM users WHERE (email=:e AND pass=SHA1(: p)) AND active IS NULL"; //$r = mysqli_query($dbc, $q) or trigger_error("Query: $q\n<br />MySQL Error: " . mysqli_error($dbc)); $stmt = $pdo->prepare($q); $stmt->execute(array(':e' => $e, ':p' => $p)); // Since $stmt->rowCount() is not suitable for counting number of rows in SELECT query... $rows = $stmt->fetchAll(); $num_rows = count($rows); if ($num_rows == 1) { // A match was made in the user table //if (@mysqli_num_rows($r) == 1) { // A match was made in the user table // Set the fetch mode: //$stmt->setFetchMode(PDO::FETCH_ASSOC); foreach( $rows as $row) { // Register the values: $_SESSION = $row; } The problem is for PDO, I have to use PDOStatement::fetchAll() to get all the rows in the result set and then use count() to get the number of the rows. But after that, when I need to fetch the matched 1 row to SESSION, $_SESSION = $row; is not correct! When $rows = $stmt->fetchAll(); is executed, the value of $rows is kinda strange(I debugged in Netbeans), so later in the foreach() loop, $row is also not the correct data. How to solve it? Or put it this way, what is the code pattern for: 1. use Prepared Statement --> 2. get the affected SELECT row number --> 3. fetch the result
  11. Larry and all, Please you take a look at my solutions and my questions. This is the last pursue question of Chapter 18 - 'administrator pages'. Other pursue questions were posted in my last post. This exercise is great - it put what is taught in Chapter 9 & 10 into Chapter 18 example(which is the best example in the book coz it is the closest to a real-world web app) Ch18 - PURSUE - Create view_users.php and edit_user.php scripts for site administration. Restrict access to these scripts to administrators (those users whose access level is 1). These 3 scripts here are modified based on the PURSUE version of Chapter 9 & 10, and I highlighted the changes in red. 1. view_users.php This one doesn't have much change, just to make it consistent with examples in Ch18. <?php # Script 10.5 - #5, modified for Ch18 # Ch18 - PURSUE - Create view_users.php and edit_user.php scripts for site administration. Restrict access to # these scripts to administrators (thoseusers whose access level is 1). // This script retrieves all the records from the users table. // This new version allows the results to be sorted in different ways. // Include the configuration file: require ('includes/config.inc.php'); // Set the page title and include the HTML header: $page_title = 'View the Current Users'; include ('includes/header.php'); echo '<h1>Registered Users</h1>'; require (MYSQL); // Number of records to show per page: $display = 10; // Determine how many pages there are... if (isset($_GET['p']) && is_numeric($_GET['p'])) { // Already been determined. $pages = $_GET['p']; } else { // Need to determine. // Count the number of records: $q = "SELECT COUNT(user_id) FROM users"; $r = @mysqli_query ($dbc, $q); $row = @mysqli_fetch_array ($r, MYSQLI_NUM); $records = $row[0]; // Calculate the number of pages... if ($records > $display) { // More than 1 page. $pages = ceil ($records/$display); } else { $pages = 1; } } // End of p IF. // Determine where in the database to start returning results... if (isset($_GET['s']) && is_numeric($_GET['s'])) { $start = $_GET['s']; } else { $start = 0; } // Determine the sort... // Default is by registration date. $sort = (isset($_GET['sort'])) ? $_GET['sort'] : 'rd'; // Determine the sorting order: switch ($sort) { case 'ln': $order_by = 'last_name ASC'; break; case 'fn': $order_by = 'first_name ASC'; break; case 'rd': $order_by = 'registration_date ASC'; break; default: $order_by = 'registration_date ASC'; $sort = 'rd'; break; } // Define the query: $q = "SELECT last_name, first_name, DATE_FORMAT(registration_date, '%M %d, %Y') AS dr, user_id FROM users ORDER BY $order_by LIMIT $start, $display"; $r = @mysqli_query ($dbc, $q); // Run the query. // Table header: echo '<table align="center" cellspacing="0" cellpadding="5" width="75%"> <tr> <td align="left"><b>Edit</b></td> <td align="left"><b>Delete</b></td> <td align="left"><b><a href="view_users.php?sort=ln">Last Name</a></b></td> <td align="left"><b><a href="view_users.php?sort=fn">First Name</a></b></td> <td align="left"><b><a href="view_users.php?sort=rd">Date Registered</a></b></td> </tr> '; // Fetch and print all the records.... $bg = '#eeeeee'; while ($row = mysqli_fetch_array($r, MYSQLI_ASSOC)) { $bg = ($bg=='#eeeeee' ? '#ffffff' : '#eeeeee'); echo '<tr bgcolor="' . $bg . '"> <td align="left"><a href="edit_user.php?id=' . $row['user_id'] . '&ln=' . $row['last_name'] . '&fn=' . $row['first_name'] . '">Edit</a></td> <td align="left"><a href="delete_user.php?id=' . $row['user_id'] . '&ln=' . $row['last_name'] . '&fn=' . $row['first_name'] . '">Delete</a></td> <td align="left">' . $row['last_name'] . '</td> <td align="left">' . $row['first_name'] . '</td> <td align="left">' . $row['dr'] . '</td> </tr> '; } // End of WHILE loop. echo '</table>'; //mysqli_free_result ($r); //mysqli_close($dbc); // Make the links to other pages, if necessary. if ($pages > 1) { echo '<br /><p>'; $current_page = ($start/$display) + 1; // If it's not the first page, make a Previous button: if ($current_page != 1) { echo '<a href="view_users.php?s=' . ($start - $display) . '&p=' . $pages . '&sort=' . $sort . '">Previous</a> '; } // Make all the numbered pages: for ($i = 1; $i <= $pages; $i++) { if ($i != $current_page) { echo '<a href="view_users.php?s=' . (($display * ($i - 1))) . '&p=' . $pages . '&sort=' . $sort . '">' . $i . '</a> '; } else { echo $i . ' '; } } // End of FOR loop. // If it's not the last page, make a Next button: if ($current_page != $pages) { echo '<a href="view_users.php?s=' . ($start + $display) . '&p=' . $pages . '&sort=' . $sort . '">Next</a>'; } echo '</p>'; // Close the paragraph. } // End of links section. include ('includes/footer.php'); ?> 2. edit_users.php Major change happens here. Add two radio buttons for account activating and administrator setting in the form on the page. Then the script itself will handle these two cases when the form is submitted, and according SQL queries are executed to UPDATE the users table for the specific record. <?php # Script 10.3 - edit_user.php - PURSUE, modified for Ch18 # 1. Change the delete_user.php and edit_user.php pages so that they both display the user being affected # in the browser window’s title bar. # 2. Modify edit_user.php so that you can also change a user’s password. # 3. If you’re up for a challenge, modify edit_user.php so that the form elements’ values come from # $_POST, if set, and the database if not. # # 2014-1-26: modified for Ch18 # Administrator could manually activate an account, declare that a user is an administrator, # or change a person's password. // This page is for editing a user record. // This page is accessed through view_users.php. require ('includes/config.inc.php'); $page_title = 'Edit a User'; include ('includes/header.php'); echo '<h1>Edit a User</h1>'; // Check for a valid user ID, through GET or POST: if ( (isset($_GET['id'])) && (is_numeric($_GET['id'])) ) { // From view_users.php $id = $_GET['id']; } elseif ( (isset($_POST['id'])) && (is_numeric($_POST['id'])) ) { // Form submission. $id = $_POST['id']; } else { // No valid ID, kill the script. echo '<p class="error">This page has been accessed in error.</p>'; include ('includes/footer.html'); exit(); } require (MYSQL); // Check if the form has been submitted: if ($_SERVER['REQUEST_METHOD'] == 'POST') { $errors = array(); // Check for a first name: if (empty($_POST['first_name'])) { $errors[] = 'You forgot to enter your first name.'; } else { $fn = mysqli_real_escape_string($dbc, trim($_POST['first_name'])); } // Check for a last name: if (empty($_POST['last_name'])) { $errors[] = 'You forgot to enter your last name.'; } else { $ln = mysqli_real_escape_string($dbc, trim($_POST['last_name'])); } // Check for an email address: if (empty($_POST['email'])) { $errors[] = 'You forgot to enter your email address.'; } else { $e = mysqli_real_escape_string($dbc, trim($_POST['email'])); } // PURSUE 2 - Check for a NEW password(updated) and match against the confirmed password: //If these values are submitted, update the password in the database as well. If these inputs are //left blank, do not update the password in the database(do not put an error message in $errors[] & use the original $q). if (!empty($_POST['pass1'])) { if ($_POST['pass1'] != $_POST['pass2']) { $errors[] = 'Your new password did not match the confirmed password.'; } else { $np = mysqli_real_escape_string($dbc, trim($_POST['pass1'])); } } // if pass1 is empty, then do nothing here, delete the original else statement. But nend to // add judge it again in the below query($q) if (empty($errors)) { // If everything's OK. // Test for unique email address: $q = "SELECT user_id FROM users WHERE email='$e' AND user_id != $id"; $r = @mysqli_query($dbc, $q); if (mysqli_num_rows($r) == 0) { // Not find it, so the email address is unique // Make the query to UPDATE the table: // PURSUE 2 - add pass=SHA1('$np') if (!empty($_POST['pass1'])) { $q = "UPDATE users SET first_name='$fn', last_name='$ln', email='$e', pass=SHA1('$np') WHERE user_id=$id LIMIT 1"; } else { // if no pass1 input, then do not update the password in the database; the original query $q = "UPDATE users SET first_name='$fn', last_name='$ln', email='$e' WHERE user_id=$id LIMIT 1"; } $r = @mysqli_query ($dbc, $q); if (mysqli_affected_rows($dbc) == 1) { // If it ran OK. // Print a message: echo '<p>The user has been edited.</p>'; //To handle the case when there's no update for name, email and password, I added this conditional. When an administrator is activating a user, seems he doesn't often need to change the user's name/email/password. } else if (mysqli_affected_rows($dbc) == 0) { // No actual update echo "</p>The user's name, email and/or password are not changed.</p>"; } else { // If it did not run OK. echo '<p class="error">The user could not be edited due to a system error. We apologize for any inconvenience.</p>'; // Public message. echo '<p>' . mysqli_error($dbc) . '<br />Query: ' . $q . '</p>'; // Debugging message. } } else { // Already registered. echo '<p class="error">The email address has already been registered.</p>'; } //Ch18 new added function - Active account if (isset($_POST['active']) && $_POST['active'] == "Yes") { //Query to active the user $q = "UPDATE users SET active=NULL WHERE (email='$e' AND user_id='$id') LIMIT 1"; $r = mysqli_query ($dbc, $q) or trigger_error("Query: $q\n<br />MySQL Error: " . mysqli_error($dbc)); // Print a customized message: if (mysqli_affected_rows($dbc) == 1) { echo "<h3>This user's account is now active.</h3>"; } else { echo '<p class="error">This account could not be activated. Please check.</p>'; } } //CH18 new added function - Set administrator if (isset($_POST['admin']) && $_POST['admin'] == "Yes") { //Query to set the user to an administrator $q = "UPDATE users SET user_level=1 WHERE (email='$e' AND user_id='$id') LIMIT 1"; $r = mysqli_query ($dbc, $q) or trigger_error("Query: $q\n<br />MySQL Error: " . mysqli_error($dbc)); // Print a customized message: if (mysqli_affected_rows($dbc) == 1) { echo "<h3>This user is site administrator now.</h3>"; } else { echo '<p class="error">This account could not be set to an administrator. Please check.</p>'; } } //One question here: is it better to use if (isset($_POST['admin']) && $_POST['admin'] == "Yes") or just use if ($_POST['admin'] == "Yes") (like in the delete_users.php) here? } else { // Report the errors. echo '<p class="error">The following error(s) occurred:<br />'; foreach ($errors as $msg) { // Print each error. echo " - $msg<br />\n"; } echo '</p><p>Please try again.</p>'; } // End of if (empty($errors)) IF. } // End of submit conditional. // Always show the form... // Retrieve the user's information: $q = "SELECT first_name, last_name, email FROM users WHERE user_id=$id"; $r = @mysqli_query ($dbc, $q); if (mysqli_num_rows($r) == 1) { // Valid user ID, show the form. // Get the user's information: $row = mysqli_fetch_array ($r, MYSQLI_NUM); // PURSUE 3 - form elements’ values come from $_POST, if set, and the database if not // Note: if UPDATE check is passed/UPDATE is succeful, then $row[] has the same value as $_POST[] $form_fn = isset($_POST['first_name']) ? $_POST['first_name'] : $row[0]; $form_ln = isset($_POST['last_name']) ? $_POST['last_name'] : $row[1]; $form_email = isset($_POST['email']) ? $_POST['email'] : $row[2]; // Create the form: // PURSUE 2 - also change a user’s password, adding the new password input and a confirmation // PURSUE 3 - substitute original $row[0], $row[1], $row[2] with $form_fn... echo '<form action="edit_user.php" method="post"> <p>First Name: <input type="text" name="first_name" size="15" maxlength="15" value="' . $form_fn . '" /></p> <p>Last Name: <input type="text" name="last_name" size="15" maxlength="30" value="' . $form_ln . '" /></p> <p>Email Address: <input type="text" name="email" size="20" maxlength="60" value="' . $form_email . '" /></p> <p>New Password: <input type="password" name="pass1" size="10" maxlength="20" value="" ></p> <p>Confirm Password: <input type="password" name="pass2" size="10" maxlength="20" value="" ></p> <p>Active the account: No<input type="radio" name="active" value="No" checked="checked"> Yes<input type="radio" name="active" value="Yes"></p> <p>Make the user an administrator: No<input type="radio" name="admin" value="No" checked="checked"> Yes<input type="radio" name="admin" value="Yes"></p> <p><input type="submit" name="submit" value="Submit" /></p> <input type="hidden" name="id" value="' . $id . '" /> </form>'; } else { // Not a valid user ID. If no record was returned from the database, because an invalid user ID was // submitted, this message is displayed: echo '<p class="error">This page has been accessed in error.</p>'; } mysqli_close($dbc); include ('includes/footer.php'); ?> 3. delete_users.php Just a little change here. <?php # Script 10.2 - delete_user.php, modified for Ch18 // This page is for deleting a user record. // This page is accessed through view_users.php. require ('includes/config.inc.php'); $page_title = 'Delete a User'; include ('includes/header.php'); echo '<h1>Delete a User</h1>'; // Check for a valid user ID, through GET or POST: if ( (isset($_GET['id'])) && (is_numeric($_GET['id'])) ) { // From view_users.php $id = $_GET['id']; } elseif ( (isset($_POST['id'])) && (is_numeric($_POST['id'])) ) { // Form submission. $id = $_POST['id']; //when the confirmation form is submitted, user_id is transfered using from hidden field, in $_POST['id']! Smart! } else { // No valid ID, kill the script. echo '<p class="error">This page has been accessed in error.</p>'; include ('includes/footer.html'); exit(); } require (MYSQL); // Check if the form has been submitted: if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($_POST['sure'] == 'Yes') { // Delete the record. // Make the query: $q = "DELETE FROM users WHERE user_id=$id LIMIT 1"; $r = @mysqli_query ($dbc, $q); if (mysqli_affected_rows($dbc)== 1) { // If it ran OK. // Print a message: echo '<p>The user has been deleted.</p>'; } else { // If the query did not run OK. echo '<p class="error">The user could not be deleted due to a system error.</p>'; // Public message. echo '<p>' . mysqli_error($dbc) . '<br />Query: ' . $q . '</p>'; // Debugging message. } } else { // No confirmation of deletion. echo '<p>The user has NOT been deleted.</p>'; } } else { // Show the form, to confirm that this user should be deleted. // Retrieve the user's information: $q = "SELECT CONCAT(last_name, ', ', first_name) FROM users WHERE user_id=$id"; $r = @mysqli_query ($dbc, $q); $test_rows = mysqli_num_rows($r); if (mysqli_num_rows($r) == 1) { // Valid user ID, show the form. (Just 1 result as user_id is PK) // Get the user's information: $row = mysqli_fetch_array ($r, MYSQLI_NUM); // Display the record being deleted: echo "<h3>Name: $row[0]</h3> Are you sure you want to delete this user?"; // Create the form: echo '<form action="delete_user.php" method="post"> <input type="radio" name="sure" value="Yes" /> Yes <input type="radio" name="sure" value="No" checked="checked" /> No <input type="submit" name="submit" value="Submit" /> <input type="hidden" name="id" value="' . $id . '" /> </form>'; } else { // Not a valid user ID. echo '<p class="error">This page has been accessed in error.</p>'; } } // End of the main submission conditional. mysqli_close($dbc); include ('includes/footer.php'); ?> The result page of editing a user: Edit a User First Name: Last Name: Email Address: New Password: Confirm Password: Active the account: No Yes Make the user an administrator: No Yes
  12. ionezation, Good luck. Live long and prosper.
  13. ionezation, I heard people say Javascript / Jquery the missing manual is mainly for designers. For web programmers, Larry's JS book is great, and you can also take a look at Professional JavaScript for Web Developers
  14. CSS could be painful(as least to me when I did it the first time), this is because there are many tricks and one design can be implemented in MANY MANY different ways. I guess CSS frameworks like Bootstrap will be the future trend, as well as LESS CSS.
  15. CSS book: CSS The Missing Manual. HTML book: First Head HTML5 Remember: buy a CSS book written by web developers, not by pure deb designers, if you want to become a developer.
  16. You guys make good points! Many many years ago I thought IT should be interesting, and I started to do IT, after several years my interest changed to something else, and after another several years I found my interest now is programming again!(especially web development & mobile development), and I started reading the books on these topics. Now I really want to be good at it.
  17. Larry and all, Please you take a look at my solutions and my questions. 1. Apply the same validation techniques to login.php as used in register.php. 2. Make the login form sticky. 3. Add a last_login DATETIME field to the users table and update its value when a user logs in. Use this information to indicate to the user how long it has been since the last time she or he accessed the site. The SQL to alter the table: ALTER TABLE users ADD COLUMN last_login DATETIME NOT NULL AFTER active ; 4. If you’ve added the last_login field, use it to print a message on the home page as to how many users have logged in in the past, say, hour or day. 5. Validate the submitted email address in forgot_password.php using the Filter extension or a regular expression. These are the pursue exercises in the book, expect the last one 'administrator pages', which I am still working on. Here are the three involved scripts - login.php, index.php and forgot_password.php (new code are in red): <?php # Script 18.8 - login.php # PURSUE 1 - Apply the same validation techniques to login.php as used in register.php. # PURSUE 2 - Make the login form sticky. # PURSUE 3 - Add a last_login DATETIME field to the users table and update its value when a user logs in. # PURSUE 4 - print a message on the home page as to how many users have logged in in the past, say, hour or day. // This is the login page for the site. require ('includes/config.inc.php'); $page_title = 'Login'; include ('includes/header.php'); if ($_SERVER['REQUEST_METHOD'] == 'POST') { require (MYSQL); // PUESUE 1 - Apply the same validation techniques to login.php as used in register.php // Trim all the incoming data: $trimmed = array_map('trim', $_POST); // Validate the email address: if (filter_var($trimmed['email'], FILTER_VALIDATE_EMAIL)) { $e = mysqli_real_escape_string ($dbc, $trimmed['email']); } else { $e = FALSE; echo '<p class="error">You forgot to enter your email address!</p>'; } // if (!empty($_POST['email'])) { // $e = mysqli_real_escape_string ($dbc, $_POST['email']); // } else { // $e = FALSE; // echo '<p class="error">You forgot to enter your email address!</p>'; // } // Validate the password: if (preg_match ('/^\w{4,20}$/', $trimmed['pass']) ) { //Here the password input name is pass in the form below!! $p = mysqli_real_escape_string ($dbc, $trimmed['pass']); } else { $p = FALSE; echo '<p class="error">You forgot to enter your password!</p>'; } // if (!empty($_POST['pass'])) { // $p = mysqli_real_escape_string ($dbc, $_POST['pass']); // } else { // $p = FALSE; // echo '<p class="error">You forgot to enter your password!</p>'; // } if ($e && $p) { // If everything's OK. // Query the database: // PURSUE 3 solution: select last_login value(both formatted and original) as part of the login query, and store the data in $_SESSION for data transfer between scripts. // Then fetch the data and do the calculation in index.php $q = "SELECT user_id, first_name, user_level, DATE_FORMAT(last_login, '%a, %b %e at %l:%i%p') as f_last_login, last_login FROM users WHERE (email='$e' AND pass=SHA1('$p')) AND active IS NULL"; $r = mysqli_query ($dbc, $q) or trigger_error("Query: $q\n<br />MySQL Error: " . mysqli_error($dbc)); if (@mysqli_num_rows($r) == 1) { // A match was made. // Register the values: $_SESSION = mysqli_fetch_array ($r, MYSQLI_ASSOC); // PURSUE 4 - print a message on the home page as to how many users have logged in in the past, say, hour or day. $q = "SELECT COUNT(user_id) FROM users WHERE last_login > DATE_SUB(NOW(), INTERVAL 60 MINUTE)"; $r = mysqli_query($dbc, $q) or trigger_error("Query: $q\n<br>MySQL Error: " . mysqli_error($dbc)); if (@mysqli_num_rows($r) == 1) { $row = mysqli_fetch_array($r, MYSQLI_NUM); $_SESSION['count_uid'] = $row[0]; } else { echo '<p class="error">There is some system error, please contact administrator!</p>'; } // PURSUE 3 - update last_login column when a user logs in // Update last_login to current time: (last login time was stored in session already) $q = "UPDATE users SET last_login=NOW()"; $r = mysqli_query($dbc, $q) or trigger_error("Query: $q\n<br>MySQL Error: " . mysqli_error($dbc)); if (@mysqli_num_rows($r) != 1) { echo '<p class="error">There is some system error, please contact administrator!</p>'; } mysqli_free_result($r); mysqli_close($dbc); // Redirect the user: $url = BASE_URL . 'index.php'; // Define the URL. ob_end_clean(); // Delete the buffer. header("Location: $url"); exit(); // Quit the script. } else { // No match was made. echo '<p class="error">Either the email address and password entered do not match those on file or you have not yet activated your account.</p>'; } } else { // If everything wasn't OK. echo '<p class="error">Please try again.</p>'; } mysqli_close($dbc); } // End of SUBMIT conditional. ?> <h1>Login</h1> <p>Your browser must allow cookies in order to log in.</p> <form action="login.php" method="post"> <fieldset> <!-- PURSUE 2 - Make the login form sticky. My Question: in register.php, trimmed $_POST values like $trimmed['first_name'] are used for form stickiness, is it also ok to just use $_POST value here? (I think that way we can exactly preserve what the user just input) --> <p><b>Email Address:</b> <input type="text" name="email" size="20" maxlength="60" value="<?php if (isset($_POST['email'])) echo $_POST['email']; ?>" /></p> <p><b>Password:</b> <input type="password" name="pass" size="20" maxlength="20" value="<?php if (isset($_POST['pass'])) echo $_POST['pass']; ?>" /></p> <div align="center"><input type="submit" name="submit" value="Login" /></div> </fieldset> </form> <?php include ('includes/footer.php'); ?> <?php # Script 18.5 - index.php // This is the main page for the site. // Include the configuration file: require ('includes/config.inc.php'); // Set the page title and include the HTML header: $page_title = 'Welcome to this Site!'; include ('includes/header.php'); // Welcome the user (by name if they are logged in): echo '<h1>Welcome'; if (isset($_SESSION['first_name'])) { echo ", {$_SESSION['first_name']}"; } echo '!</h1>'; // PURSUE 3 - indicate to the user how long it has been since the last time the user accessed the site if (isset($_SESSION['last_login'])) { //do calculation only the user logged in // Date difference calculation routine: $date1 = time(); $date2 = strtotime($_SESSION['last_login']); $dateDiff = $date1 - $date2; $fullDays = floor($dateDiff/(60*60*24)); $fullHours = floor(($dateDiff-($fullDays*60*60*24))/(60*60)); $fullMinutes = floor(($dateDiff-($fullDays*60*60*24)-($fullHours*60*60))/60); $sec_used = ($fullDays * 60 * 60 * 24) + ($fullHours * 60 * 60) + ($fullMinutes * 60); $sec_rem = $dateDiff - $sec_used; echo "<h4>The last time you logged in is: " . $_SESSION['f_last_login'] . "</h4>"; echo "<h4>There have been $fullDays days, $fullHours hours $fullMinutes minutes and $sec_rem seconds since you last logged in.</h4>"; // PURSUE 4 - print a message on the home page as to how many users have logged in in the past, say, hour or day. echo "<h5>There have been " . $_SESSION['count_uid'] . " users logged in in the last hour.</h5>"; } ?> <p>Spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam.</p> <p>Spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam.</p> <?php include ('includes/footer.php'); ?> The result of the index.php: User Registration Welcome, Mary! The last time you logged in is: Fri, Jan 17 at 3:05PM There have been -1 days, 15 hours 22 minutes and 19 seconds since you last logged in. There have been 0 users logged in in the last hour. Spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam. Spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam spam. My question: it seems the calculation of time difference has some issue here: $date1 = time(); $date2 = strtotime($_SESSION['last_login']); $dateDiff = $date1 - $date2; I debugged in Netbeans and found that $date1 is < $date2, so the $dateDiff is a negative number. Any hint for the root cause? Another issue is when I use Netbeans to debug, I have to comment out database closing statements such as //mysqli_free_result($r); // get around debug issue //mysqli_close($dbc); // get around debug issue otherwise there will be error during debugging. Also, I have to do some getaround in here: // Add the user to the database: $q = "INSERT INTO users (email, pass, first_name, last_name, active, registration_date) VALUES ('$e', SHA1('$p'), '$fn', '$ln', '$a', NOW() )"; $r = mysqli_query ($dbc, $q) or trigger_error("Query: $q\n<br />MySQL Error: " . mysqli_error($dbc)); $test_affected_rows = mysqli_affected_rows($dbc); // Get around debug issue if ($test_affected_rows == 1) { // If it ran OK. The reason is during debugging in Netbeans, affected_rows always return -1, so I have to use a temporary variable here and manually change -1 to 1 during debug. I researched a lot on the Internet, but haven't got the answer yet. <?php # Script 18.10 - forgot_password.php # PURSUE 5 - Validate the submitted email address in forgot_password.php using the Filter extension or a regular expression. // This page allows a user to reset their password, if forgotten. require ('includes/config.inc.php'); $page_title = 'Forgot Your Password'; include ('includes/header.php'); if ($_SERVER['REQUEST_METHOD'] == 'POST') { require (MYSQL); // Assume nothing: $uid = FALSE; // Validate the email address... // PURSUE 5 - Validate the submitted email address in forgot_password.php using the Filter extension // if (!empty($_POST['email'])) { if (filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) { ...(This one is easy so the rest of the code are ignored.)
  18. Currently all PHP books are using simple web apps examples. Is it doable to write a book using a small-to-middle size real-world website? By real-world I mean it's a 100% real website that can run without any modification and enhancement. This will not be a beginning PHP book so no syntax needs to be introduced, so the book won't be very thick. Just follow that one website development process, and develop every aspect of the system. I guess the market is crying out for such a book...
  19. Access the forums database using whatever client you prefer. the db name should be 'forum', not plural.
  20. Thanks for all the suggestions! I know the importance of algorithms and data structures, and currently I allocate some time to 'read-code-debug' a algorithms book. The book uses Java, but it doesn't bother at all - after reading and coding the java code in the book, I do it again in C#(almost no change as it is almost evidential to Java) or C or PHP. The mental training here is about 'thinking like a computer' or 'algorithmic thinking and problem solving', this is valuable no matter what programming one uses. I must master it now. For OOP, I read C# book first, then read some relative chapter in OO PHP and I feel comfortable when following this sequence.
  21. I tested in Firefox, it's working good. Guess you need to check whether your Firefox disabled js or not.
×
×
  • Create New...