Jump to content
Larry Ullman's Book Forums

oderza

Members
  • Posts

    13
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by oderza

  1. In Chapter 9 (CMS with OOP), the user class is defined with six protected attributes, including email and pass. A few pages later in the login script, a user object is created and then stored in a session:

     

    'SELECT id, userType, username, email FROM users WHERE email=:email AND pass=SHA1(:pass)';

    // The results are fetched into $user using PDO:FETCH_CLASS

     

    Then $user is stored in a Session:

    if($user) { $_SESSION['user'] = $user; // followed by a redirect and exit

    }

     

    I realize that the way it is written, only id, userType, username, and email are retrieved from the database and are the ONLY results passed to the $user object. I'm wondering, however, why you would include a $pass attribute in the $user class if you plan on storing that object in a session. Is this safe? What if somewhere along the line, the $pass attribute is used and set in the object?

     

    I'm guessing that ALL of the attributes of the class are stored in $_SESSION['user'] as serialized data, and even though they are 'protected' in the class, the password would be stored in the session with whatever value it is set to in the $pass attribute. If I were to keep the $pass attribute in the class, I would make sure that $this->pass is run through whatever security hash I have in place for my application.

     

    So the question is: If I am going to be storing user objects in a session, do I get rid of the protected $pass attribute from the user class completely? Or is it safe to keep it there as long as it gets hashed (or maybe even reset to NULL after login)?

     

    Thanks again!

  2. I just read that if you're only going to run a statement once, it probably isn't very efficient to use prepared statements. So for the scenario above I changed my code to this:

     

    $q = sprintf('SELECT id, title, content FROM pages WHERE id=%d', (int)$_GET['id']);

    $r = $dbc->query($q);

    if ($r->num_rows ==1){

    $page = $r->fetch_object('Page');

    }

     

    This works fine and creates a Page object. However, I will come across instances where I do want to use mysqli prepared statements. The only work around that I could think of is to bind_result like mentioned in my previous post and then create a new object doing this:

     

    $stmt->bind_result($id, $title, $content);

    while($stmt->fetch()){

    $page = new Page($id, $title, $content); // I would change the Page class to include a __construct function.

    }

  3. I have been trying to research how to have a prepared mysqli statement give you a result set that you can fetch into an object (class). I know PDO can do this effortlessly, but it's hard to believe you can't do it with mysqli. Maybe someone can point me in the right direction.

     

    Some example code that I have been trying:

     

    class Page {

    protected $id = null;

    protected $title = null;

    protected $content = null;

    }

     

    $dbc = new mysqli('host', 'user', 'password', 'db');

     

    $q = 'SELECT id, title, content FROM pages WHERE id=?';

    $stmt = $dbc->prepare($q);

    $pid = (int) $_GET['p']; // I validate this extensively above... no worries.

    $stmt->bind_param('i', $pid);

    $stmt->execute();

    $stmt->store_result();

    if ($stmt->num_rows ==1) {

    echo "<h1>Success!</h1>"; //This works, but the following line doesn't. $page is never created.

    $page = $stmt->fetch_object('Page');

    }

     

     

    If I decide not to use:

    stmt->store_result and $stmt->fetch object

     

    and instead just use:

    stmt->bind_result($id, $title, $content) and stmt->fetch

    I can successfully retrieve the columns ($id, $title, $content) individually, but I would rather put them into an object.

     

     

    What I also found interesting is that if I don't use a prepared statement, then fetching into an object isn't a big deal either. This works just fine:

     

     

    $q = 'SELECT id, title, content FROM pages LIMIT 10';

    $r = $dbc->query($q);

    while($page = $r->fetch_object('Page')){

    // This works

    }

     

    Thanks

  4. It is really awesome to finally be able to calculate distance, thanks Larry!

     

    I had a question about ways of expanding on this new knowledge. The query presented in the book takes information from the stores table and does a left join with the zip_codes table. The query looks like this:

     

    "SELECT name, address, city, state, stores.zip_code, phone, ROUND(return_distance($lat, $long, latitude, longitude)) AS distance FROM stores LEFT JOIN zip_codes USING (zip_code) ORDER BY distance ASC LIMIT 3"

     

    I want to confirm the order of things that are happening. Is the following correct?:

    1) First, ALL of the stores are returned from the stores table

    2) Next, the remaining information needed (city, state, lat, long) are joined to those results

    3) Next, the return_distance formula calculates the distance between the origin location and the location of every store

    4) Finally those results are ordered to show the 3 closest results

     

    If this is how that query gets processed, then I'm wondering how efficient it will be if my table had 500,000 stores? Obviously a table with 500,000 stores will take up a lot more resources calculating the distance between an origin and all 500,000 stores, than it would if I only had 500 stores.

     

    If that is in fact how that query with the left join works AND my stores table has a ton of stores, what I'm thinking about doing to improve efficiency is:

     

    First do a query that locates every zip code within a certain distance of the origin, lets say 100 miles. That way I'm not running the distance formula 500,000 times, but rather 45,000 times (number of zip codes). Next I would run the query just like it was presented in the book, but include a 'WHERE zip_code=(the values returned by the previous query).

     

    Again, this would only improve efficiency if I did in fact have many times more stores in my table than there are zip codes. Does this strategy make sense?

  5. I appreciate this book, and as usual, it is very easy to understand and great way to learn these topics.

     

    My question concerns step 8 on page 94 of the book. The </body> and </html> tags are closed within the php tags, although the opening <body> and <html> were not. Is there any reason for this?

     

    The next step mentions that session_write_close can be written anywhere in the script as long as the modifications to session data is over, so I'm assuming there isn't any reason to close the body and hmtl tags prior to this.

     

    Hopefully I'm not over thinking this!

  6. I've decided to take this route and stick with it, that way I can leave the setThemeCookie function alone:

     

    In the onload function I'm using:

     

     

    if(theme) {

    setTheme(theme);

    var expire = new Date();

    expire.setDate(expire.getDate() + 7);

    COOKIE.setCookie('theme', theme, expire);

    };

     

    I'm pretty sure I've completely exhausted this topic. Thanks again for all of your help Larry! I start the final chapter today :D

  7. Speculating on the splice is a waste of time, so I agree that split is a much better option. You could also check the index of a space, or other marker, and then splice at that point.

     

    With all that said, however, I would be careful for people that have a space IN their first or last name:

     

    Examples:

    Anne Marie

    Billy Ray

    Anna Beth

    Xui Li

    Juan Pedro

    etc...

     

    This could be a full name:

    Juan Pedro Gómez Martínez

     

    If you insist on only providing one input for a full name, then I would guide your user to separate their first, last and middle names with a comma and then use a split on the comma.

     

    Once you get further into the book you'll see ways on how you can show tips to your users on how they should format their input. You can also validate their input to make sure they are following your required format before the submit is processed.

  8. Yes, this did help. Replacing setThemeCookie with setTheme did solve the problem of loading the theme upon reopening the page.

     

    However, like you said above, I still need to pass something along to the setThemeCookie to restart the cookie. I wasn't sure how proper my fix was when I changed setThemeCookie. As far as passing an object to setThemeCookie (leaving setThemeCookie the way it is), I'm not really sure what I could pass to it (besides the onclick from the link).

     

    Thanks

  9. I'm using the code from theme.html, theme.js and cookies.js. When you select a theme and then close the browser, you are expecting that the 'theme' will be stored and then loaded from a Cookie. Upon reopening the page, the cookie is retrieved in the onload function of the theme.js file.

     

     

    window.onload = function() {

    'use strict';

     

    // Add click event handlers to each theme link:

    document.getElementById('aTheme').onclick = setThemeCookie;

    document.getElementById('bTheme').onclick = setThemeCookie;

    // Get the cookie's value:

    var theme = COOKIE.getCookie('theme');

     

    The final line in the getCookie code provided in cookies.js is:

    return cookies.split('=')[1];

    This sends back a string. In this case either aTheme or bTheme.

     

    The next lines in theme.js are:

     

    // If there was a value, set the theme:

    if (theme) {

    setThemeCookie(theme);

    }

    }; // End of onload anonymous function.

     

    I think this is happening: Theme is selected -> a cookie is stored -> the page is closed -> the page is opened again -> a cookie is retrieved (as a string). This string (bTheme or aTheme) is passed to setThemeCookie. The value passed to setThemeCookie(e) is checked by:

     

    if (typeof e == 'undefined') e = window.event;

     

    But because e is being passed along as a string, it is not undefined. Then you try to use e.target || e.srcElement on a string, which is where I thought maybe this is failing and why the background (theme) is not loading when I reopen the page.

     

    That is why I modified the setThemeCookie to check for a string first (aTheme or bTheme), else use an event object, which would be every other time (when you are clicking on the links to change the theme).

     

    If I DON'T modify the setThemeCookie function, like I show in my original post, then the background color is white upon reopening the page. I wanted to make sure that setCookie and getCookie were working properly, so I inserted a document.getElementById('whatever').innerHTML = theme to show me the theme variable prior to sending it through setThemeCookie. It does indeed show me either aTheme or bTheme as the value when I open the page, so I know that both setCookie and getCookie are working properly.

     

    I hope that I'm not missing something super obvious here and that I'm understanding everything correctly. Thank you greatly for your help and your patience.

  10. I had some trouble with the steps on pages 366-367 when setting cookies. What was happening ( I think ) is that the following code (step 7 & 8) was looking for the id of the target:

     

    var target = e.target || e.srcElement;

     

    //The timer code here didn't effect my results, but was sitting between the problematic code

    var expire = new Date();

    expire.setDate(expire.getDate() + 7);

     

    COOKIE.setCookie('theme', target.id, expire);

    setTheme(target.id);

     

    However if a cookie was already set, and you use getCookie('theme') to retrieve it, your value is a string. So the fix I came up with was to use and IF and ELSE:

     

    var expire = new Date();

     

    expire.setDate(expire.getDate() + 7);

     

    if (typeof e == ‘string’) {

    COOKIE.setCookie(‘theme’, e, expire);

    setTheme(e);

    } else {

    var target = e.target || e.srcElement;

    COOKIE.setCookie(‘theme’, target.id, expire);

    setTheme(target.id);

    }

     

    This got my page to work, meaning that I could switch between the Themes, close my browser, and then see the last Theme used. Otherwise, you could still alternate between the two Themes when the the window was open, but it would not be retrieved properly.

     

    I wanted to know if there was a better way to work around this? Using (typeof e == 'string') worked out in this scenario, but as a rookie I'm not 100% confident in this fix.

     

    Also, since nobody else has brought this up, I wanted to make sure I didn't miss or screw up somewhere along the way. Sometimes obvious mistakes are preventing my code from working in the first place.

     

    Thanks!

×
×
  • Create New...