Categories
Programming

Apache Trick – Rewrite to 404 Not Found

This may be a well known trick, but I couldn’t find it anywhere. If you’re needing to hide certain files using .htaccess, the only way to do so according to the documentation is by using [G] for “410 Gone” or [F] for “403 Forbidden”. In my case, I didn’t want the user to know the file existed at all, so here’s the trick:


RewriteRule ^hidden - [R=404]

“^hidden” tells the server to look for any path on the server that starts with hidden. The “-” tells the server not to rewrite the URL, and the [R=404] tells the server to do a external redirect (making your browser go to the new location) to nowhere, and gives a 404 Not Found status.

Update: Apache 2.0 seems to only accept R=3xx, not R=404, so I think this must only work in 2.2 and up.

Categories
Programming

MySQL Searching

I’ve found that MySQL’s searching implementations don’t quite work for a smaller database. When I try to use fulltext searching on waggonersboots.com, it removes “Wolverine” because 55 of the 85 products in our database are Wolverine. So I think I’m going to have to come up with a custom search.

I’ve searched and searched, and when on a shared server (I don’t think sphinx will do it) there’s really not a lot that I found that’s very helpful. I’m probably going to have to use indexing, instead of trying to use fancy SQL queries. It’s probably going to take around three days of coding, scrapping, and more coding, until I come up with something that is both fast and effective. It probably would have helped had I stuck with a computer science major.

I think I can finish the majority of my tasks on the site within a couple of days, or at least the ones I intend to do before it goes live. If I ever get done, I’m not going to know what to do with myself. Staying busy has the upside of cutting boredom, but it also has a way of getting in the way of homework (not that I do it anyways). I may be spending a lot of time on my Wii.

Categories
Programming

The End is in Sight

I’ve been coding lots and lots for many hours, but I can finally see the end for Waggonersboots.com version 2.0. I may have to come up with a new front-end to signify a change, but right now, it’s pretty similar in style. The backend is WAY more extensible though. With logging for errors and data changes, and a pretty good seperation of logic and presentation, I think it’s going to be a lot better. I hope to get some page editing in place for the admin, and better integration with Paypal and Google Checkout.

I can’t quite what I should do with data consistency. If we want to remove a product from the website, I would normally just delete it out of the database, but that creates some inconsistency, such as, if we wanted to look at selling history. I’ll probably continue to delete them, to remove the extra load on the database for indexing, etc, but I’m not sure what the rules are.

At my current job, I do a lot of reading. It’s hard to get used to, because the only jobs I’ve had before, I was expected to be, or at least look, busy. In some ways it’s nice, but it gets to be a little dull. I’ve been reading over MySQL, and even though I haven’t done much with it at work yet, I’ve implemented a lot of it into the WB‘s code. Here’s one that I came up with today:

SELECT name, COUNT(DISTINCT value) FROM variation
GROUP BY name ORDER BY 2

It’s pretty simple to most with SQL experience, but came as a revelation when trying to do different hacks in PHP. This query gets the types of variations (e.g. Size, Color) in order by the fewest distinctions. It’s useful for making a list such as (Colors are always top-level in this case):

  • Brown
    • 32
    • 34
    • 36
  • Black
    • 34
    • 38
    • 40

I then take a PHP function and sort it like this, for use in usort():

public function item_cmp(&$a, &$b) {
  $astr = $bstr = '';
  $vartns = Variation::get_variations();
  foreach($vartns as $v) {
    if(isset($a->variations[$v])) { // zero-pad with zeros to three digits
      $astr .= sprintf('%03s',$a->variations[$v]->weight);
    } else $astr .= '999'; // Make null values float to bottom
      if(isset($b->variations[$v])) {
        $bstr .= sprintf('%03s',$b->variations[$v]->weight);
      } else
        $bstr .= '999';
      }
  }
  return strcmp($astr, $bstr); // Compare the two as strings
  // (digits would probably work too, but strcmp was easiest)
}

Rather than hardcoding it, I thought it best to make it smart. I’ve implemented the site in PHP5, and I’m crossing my fingers that the shift from MySQL 5 to MySQL 4.1 won’t cause too many problems.

Categories
Programming

All About Waggonersboots.com

The last month of my life has been coding a whole new site for waggonersboots.com. I’ve moved everything over to PHP5, using PHP Classes, MySQLi, normalized tables, and a rough version of the Model-View-Controller system.

When dealing with footwear, you have to have shoe sizes, and other products have colors. I could have codeed different variations for products to have sizes, and others to have colors, and any other variations that would have come along, but to avoid the extra coding, I implemented them as one idea:

  • The product table contains generic information about a product, such as a brand, stock number, title, prices, category, and so forth.
  • The item table contains one instance of a product. The item is what actually gets sold and is tied to the shopping cart. Items have unique variations, which allows for a product to have multiple items.
  • The variations table has variations with a name and value. To keep the tables normalized, there is a item_variations table which join the two together, allowing an item to have multiple variations, and an item to have multiple variations (forcing a unique variation name, such as “Size” on an item).

The products have a product type, and I’ve been toying with the idea of letting variations be type specific, so that products that are footwear, can have the Size 8.5 D, 9 D, 10 D, and products that are apparel can have the size 32×32, 32×34, Medium, Large; this is kind of contaminated too, as Jeans, Shirts, and Hats have their own systems of sizing.

This method causes a few problems when trying to turn the results from the database into a web interface, but I got it to work. I may post some code later.

Categories
Programming

jQuery: Characters Remaining

I needed a counter on my input texts to say how many characters are left, so I came up with this. It creates a yellow box to the right of the input area, which is updated when the field is edited.

Counter Function

jQuery.fn.counter = function() {
  $(this).each(function() {
    var max = $(this).attr('maxlength');
    var val = $(this).attr('value');
    var cur = 0;
    if(val) // value="", or no value at all will cause an error
      cur = val.length;
    var left = max-cur;
    $(this).after("<div class='counter'>"
      + left.toString()+"</div>");
    // You can use something like this to align the
    // counter to the right of the input field.
    var c = $(this).next(".counter");
    c.width(40);
    c.css("position","relative");
    c.css("top",-$(this).height()-8);
    c.css("left",$(this).width()+8);
    c.css("background","yellow");

    $(this).keyup(function(i) {
      var max = $(this).attr('maxlength');
      var val = $(this).attr('value');
      var cur = 0;
      if(val)
        cur = val.length;
      var left = max-cur;
      $(this).next(".counter").text(left.toString());
      return this;
    });
  });
  return this;
}

Usage Examples

You’d use it like the following. In the example, #main is the main body area, and all fields will have a class of maxlength which need the counter.

$(document).ready(function() {
  $("#main form input.maxlength").counter();
});

Or you could search for any fields with a maxlength attribute:

$(document).ready(function() {
  $("form input[@maxlength]").counter();
});